From 6366cf985a2b2926f9c0f9086c65b4aa573d96af Mon Sep 17 00:00:00 2001 From: Kenneth Date: Thu, 1 Jan 2026 18:59:44 +0000 Subject: [PATCH] test(backend): account service tests --- .../account/service_integration_test.go | 121 ++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 apps/backend/internal/account/service_integration_test.go diff --git a/apps/backend/internal/account/service_integration_test.go b/apps/backend/internal/account/service_integration_test.go new file mode 100644 index 0000000..f220e3e --- /dev/null +++ b/apps/backend/internal/account/service_integration_test.go @@ -0,0 +1,121 @@ +//go:build integration + +package account + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/get-drexa/drexa/internal/database" + "github.com/get-drexa/drexa/internal/organization" + "github.com/get-drexa/drexa/internal/password" + "github.com/get-drexa/drexa/internal/user" + "github.com/testcontainers/testcontainers-go/modules/postgres" +) + +func TestService_AccountQueries(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) + defer cancel() + + pg, err := runPostgres(ctx) + if err != nil { + t.Skipf("postgres testcontainer unavailable (docker not running/configured?): %v", err) + } + t.Cleanup(func() { _ = pg.Terminate(ctx) }) + + postgresURL, err := pg.ConnectionString(ctx, "sslmode=disable") + if err != nil { + t.Fatalf("postgres connection string: %v", err) + } + + db := database.NewFromPostgres(postgresURL) + t.Cleanup(func() { _ = db.Close() }) + + if err := database.RunMigrations(ctx, db); err != nil { + t.Fatalf("RunMigrations: %v", err) + } + + hashed, err := password.HashString("account-pass") + if err != nil { + t.Fatalf("HashString: %v", err) + } + + userSvc := user.NewService() + orgSvc := organization.NewService() + accSvc := NewService() + + testUser, err := userSvc.RegisterUser(ctx, db, user.UserRegistrationOptions{ + Email: "account@example.com", + DisplayName: "Account User", + Password: hashed, + }) + if err != nil { + t.Fatalf("RegisterUser: %v", err) + } + + personalOrg, err := orgSvc.CreatePersonalOrganization(ctx, db, "Personal Org") + if err != nil { + t.Fatalf("CreatePersonalOrganization(personal): %v", err) + } + + accPersonal, err := accSvc.CreateAccount(ctx, db, personalOrg.ID, testUser.ID, RoleAdmin, StatusActive) + if err != nil { + t.Fatalf("CreateAccount(personal): %v", err) + } + + t.Run("list accounts", func(t *testing.T) { + accounts, err := accSvc.ListAccounts(ctx, db, testUser.ID) + if err != nil { + t.Fatalf("ListAccounts: %v", err) + } + if len(accounts) != 1 { + t.Fatalf("expected 1 account, got %d", len(accounts)) + } + if accounts[0].ID != accPersonal.ID { + t.Fatalf("unexpected account id: got %q want %q", accounts[0].ID, accPersonal.ID) + } + }) + + t.Run("account by id", func(t *testing.T) { + gotPersonal, err := accSvc.AccountByID(ctx, db, testUser.ID, accPersonal.ID) + if err != nil { + t.Fatalf("AccountByID(personal): %v", err) + } + if gotPersonal.OrgID != personalOrg.ID { + t.Fatalf("unexpected personal org id: got %q want %q", gotPersonal.OrgID, personalOrg.ID) + } + if gotPersonal.Role != RoleAdmin { + t.Fatalf("unexpected personal role: got %q want %q", gotPersonal.Role, RoleAdmin) + } + + }) + + t.Run("find user account in org", func(t *testing.T) { + gotPersonal, err := accSvc.FindUserAccountInOrg(ctx, db, personalOrg.ID, testUser.ID) + if err != nil { + t.Fatalf("FindUserAccountInOrg(personal): %v", err) + } + if gotPersonal.ID != accPersonal.ID { + t.Fatalf("unexpected personal account id: got %q want %q", gotPersonal.ID, accPersonal.ID) + } + }) +} + +func runPostgres(ctx context.Context) (_ *postgres.PostgresContainer, err error) { + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("testcontainers panic: %v", r) + } + }() + + return postgres.Run( + ctx, + "postgres:16-alpine", + postgres.WithDatabase("drexa"), + postgres.WithUsername("drexa"), + postgres.WithPassword("drexa"), + postgres.BasicWaitStrategies(), + ) +}