package data import ( "context" "errors" "testing" "time" "neuralhunt/internal/auth" ) func TestPlaceWorkerProgressCreditsOwnerAndFundsPlacements(t *testing.T) { ctx := context.Background() db, err := OpenSQLite(ctx, t.TempDir()+"/place.db") if err != nil { t.Fatal(err) } defer db.Close() s := New(db) jwk := auth.PublicJWK{Kty: "EC", Crv: "P-256", X: "AQ", Y: "Ag"} if err := s.UpsertClient(ctx, "owner", jwk); err != nil { t.Fatal(err) } if err := s.UpsertClient(ctx, "worker", jwk); err != nil { t.Fatal(err) } if err := s.SetIdentityDelegation(ctx, "worker", "owner"); err != nil { t.Fatal(err) } if err := s.EnsureActiveTasks(ctx, 1, 28); err != nil { t.Fatal(err) } tasks, err := s.ActiveTasks(ctx) if err != nil || len(tasks) != 1 { t.Fatalf("tasks=%d err=%v", len(tasks), err) } tx, err := db.BeginTx(ctx, nil) if err != nil { t.Fatal(err) } owner, milli, err := s.placeRewardImprovementTx(ctx, tx, tasks[0].ID, "worker", 10, 12.5, 100, time.Now().UTC().UnixMilli()) if err != nil { t.Fatal(err) } if owner != "owner" || milli != 250000 { t.Fatalf("owner=%q milli=%d", owner, milli) } if err := tx.Commit(); err != nil { t.Fatal(err) } wallet, err := s.PlaceWallet(ctx, "owner", 100) if err != nil { t.Fatal(err) } if wallet.BalancePoints != 250 || wallet.AvailablePixels != 2 || len(wallet.LinkedWorkers) != 1 || wallet.LinkedWorkers[0] != "worker" { t.Fatalf("unexpected wallet: %+v", wallet) } first, wallet, err := s.PlacePixel(ctx, "owner", 7, 9, 3, 256, 256, 100, 32) if err != nil { t.Fatal(err) } if first.Revision != 1 || wallet.BalancePoints != 150 || wallet.Placements != 1 || wallet.OwnedPixels != 1 { t.Fatalf("first=%+v wallet=%+v", first, wallet) } second, wallet, err := s.PlacePixel(ctx, "owner", 7, 9, 8, 256, 256, 100, 32) if err != nil { t.Fatal(err) } if second.Revision != 2 || wallet.BalancePoints != 50 || wallet.Placements != 2 || wallet.OwnedPixels != 1 { t.Fatalf("second=%+v wallet=%+v", second, wallet) } if _, _, err := s.PlacePixel(ctx, "owner", 8, 9, 1, 256, 256, 100, 32); !errors.Is(err, ErrPlaceInsufficientPoints) { t.Fatalf("expected insufficient points, got %v", err) } pixels, stats, err := s.PlaceSnapshot(ctx) if err != nil { t.Fatal(err) } if len(pixels) != 1 || pixels[0].ColorIndex != 8 || stats.Revision != 2 || stats.TotalPlacements != 2 { t.Fatalf("pixels=%+v stats=%+v", pixels, stats) } changes, rev, err := s.PlaceChanges(ctx, 0, 100) if err != nil { t.Fatal(err) } if len(changes) != 1 || changes[0].Revision != 2 || changes[0].ColorIndex != 8 || rev != 2 { t.Fatalf("changes=%+v rev=%d", changes, rev) } recent, err := s.PlaceRecent(ctx, 2) if err != nil { t.Fatal(err) } if len(recent) != 2 || recent[0].Revision != 2 || recent[1].Revision != 1 { t.Fatalf("recent=%+v", recent) } outside, err := s.PlacePixelsOutside(ctx, 7, 256) if err != nil || outside != 1 { t.Fatalf("outside=%d err=%v", outside, err) } outside, err = s.PlacePixelsOutside(ctx, 8, 10) if err != nil || outside != 0 { t.Fatalf("inside bounds outside=%d err=%v", outside, err) } }