From 2f8274cbe7e2c59655192ba8dfd33f52abdefe7a Mon Sep 17 00:00:00 2001 From: Marco Ardizzone Date: Tue, 29 Apr 2025 12:59:46 +0200 Subject: [PATCH] feat: Integration tests for CreateInstance v2 endpoint (#9452) --- internal/api/grpc/instance/v2/converter.go | 2 +- .../v2/integration_test/instance_test.go | 103 ++++++++++++++++++ .../v2/integration_test/server_test.go | 26 +++++ 3 files changed, 130 insertions(+), 1 deletion(-) create mode 100644 internal/api/grpc/instance/v2/integration_test/instance_test.go create mode 100644 internal/api/grpc/instance/v2/integration_test/server_test.go diff --git a/internal/api/grpc/instance/v2/converter.go b/internal/api/grpc/instance/v2/converter.go index 515953ae43e..a49172160c7 100644 --- a/internal/api/grpc/instance/v2/converter.go +++ b/internal/api/grpc/instance/v2/converter.go @@ -159,7 +159,7 @@ func CreateInstancePbToSetupInstance(req *instance.CreateInstanceRequest, defaul func createInstancePbToAddHuman(req *instance.CreateInstanceRequest_Human, defaultHuman command.AddHuman, userLoginMustBeDomain bool, org, externalDomain string) *command.AddHuman { user := defaultHuman if req.Email != nil { - user.Email.Address = domain.EmailAddress(req.Email.Email) + user.Email.Address = domain.EmailAddress(strings.TrimSpace(req.Email.Email)) user.Email.Verified = req.Email.IsEmailVerified } if req.Profile != nil { diff --git a/internal/api/grpc/instance/v2/integration_test/instance_test.go b/internal/api/grpc/instance/v2/integration_test/instance_test.go new file mode 100644 index 00000000000..43abf6f9275 --- /dev/null +++ b/internal/api/grpc/instance/v2/integration_test/instance_test.go @@ -0,0 +1,103 @@ +//go:build integration + +package instance_test + +import ( + "context" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zitadel/zitadel/internal/integration" + instance "github.com/zitadel/zitadel/pkg/grpc/instance/v2beta" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" +) + +func TestCreateInstance(t *testing.T) { + tt := []struct { + testName string + inputRequest *instance.CreateInstanceRequest + inputContext context.Context + expectedErrorMsg string + expectedErrorCode codes.Code + }{ + { + testName: "when invalid context should return unauthN error", + inputRequest: &instance.CreateInstanceRequest{ + InstanceName: " ", + FirstOrgName: " ", + CustomDomain: " ", + Owner: &instance.CreateInstanceRequest_Machine_{ + Machine: &instance.CreateInstanceRequest_Machine{ + UserName: "owner", + Name: "owner", + PersonalAccessToken: &instance.CreateInstanceRequest_PersonalAccessToken{}, + }, + }, + DefaultLanguage: "", + }, + inputContext: context.Background(), + expectedErrorCode: codes.Unauthenticated, + expectedErrorMsg: "auth header missing", + }, + { + testName: "when invalid input should return no admin error", + inputRequest: &instance.CreateInstanceRequest{ + InstanceName: " ", + FirstOrgName: " ", + CustomDomain: " ", + DefaultLanguage: "", + Owner: &instance.CreateInstanceRequest_Human_{ + Human: &instance.CreateInstanceRequest_Human{ + Email: &instance.CreateInstanceRequest_Email{ + Email: " user@example.com ", + }, + }, + }, + }, + inputContext: CTXWithSysAuthZ, + expectedErrorCode: codes.InvalidArgument, + expectedErrorMsg: "Given name in profile is empty (USER-UCej2)", + }, + { + testName: "when input and context are valid should return expected response and no error", + inputRequest: &instance.CreateInstanceRequest{ + InstanceName: " ", + FirstOrgName: " ", + CustomDomain: " ", + Owner: &instance.CreateInstanceRequest_Machine_{ + Machine: &instance.CreateInstanceRequest_Machine{ + UserName: "owner", + Name: "owner", + PersonalAccessToken: &instance.CreateInstanceRequest_PersonalAccessToken{}, + }, + }, + DefaultLanguage: "", + }, + inputContext: CTXWithSysAuthZ, + }, + } + + for _, tc := range tt { + t.Run(tc.testName, func(t *testing.T) { + // Given + cli, err := integration.NewDefaultClient(CTXWithSysAuthZ) + require.Nil(t, err) + + // Test + res, err := cli.InstanceV2Beta.CreateInstance(tc.inputContext, tc.inputRequest) + + // Verify + assert.Equal(t, tc.expectedErrorCode, status.Code(err)) + assert.Equal(t, tc.expectedErrorMsg, status.Convert(err).Message()) + if tc.expectedErrorMsg == "" { + require.NotEmpty(t, res.GetInstanceId()) + assert.NotEmpty(t, res.GetPat()) + + require.NotNil(t, res.GetDetails()) + assert.NotEmpty(t, res.GetDetails().GetResourceOwner()) + } + }) + } +} diff --git a/internal/api/grpc/instance/v2/integration_test/server_test.go b/internal/api/grpc/instance/v2/integration_test/server_test.go new file mode 100644 index 00000000000..201a6f67f97 --- /dev/null +++ b/internal/api/grpc/instance/v2/integration_test/server_test.go @@ -0,0 +1,26 @@ +package instance_test + +import ( + "context" + "os" + "testing" + "time" + + "github.com/zitadel/zitadel/internal/integration" +) + +var ( + CTXWithSysAuthZ context.Context +) + +func TestMain(m *testing.M) { + os.Exit(func() int { + + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Minute) + defer cancel() + + CTXWithSysAuthZ = integration.WithSystemAuthorization(ctx) + + return m.Run() + }()) +}