diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml new file mode 100644 index 0000000..e737698 --- /dev/null +++ b/.github/workflows/e2e.yml @@ -0,0 +1,40 @@ +name: E2E + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: e2e-${{ github.event_name == 'pull_request' && github.event.pull_request.number || github.sha }} + cancel-in-progress: true + +jobs: + e2e: + runs-on: ubuntu-latest + timeout-minutes: 60 + env: + E2E_SUITES: go-core + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Provision cluster + uses: agynio/bootstrap/.github/actions/provision@main + + - name: Setup DevSpace + uses: agynio/e2e/.github/actions/setup-devspace@main + + - name: Deploy users from source + run: devspace dev + + - name: Run E2E tests + uses: agynio/e2e/.github/actions/run-tests@main + with: + service: users + tag: svc_gateway + include_smoke: false diff --git a/README.md b/README.md index 41e7db5..4e88243 100644 --- a/README.md +++ b/README.md @@ -29,10 +29,12 @@ devspace dev devspace dev -w ``` -### Run tests +### Run E2E tests ```bash -devspace run test:e2e +git clone https://github.com/agynio/e2e.git +cd e2e +devspace run test-e2e --tag svc_users ``` See [E2E Testing](https://github.com/agynio/architecture/blob/main/architecture/operations/e2e-testing.md). diff --git a/devspace.yaml b/devspace.yaml index 187ed6e..7acf81f 100644 --- a/devspace.yaml +++ b/devspace.yaml @@ -2,7 +2,6 @@ version: v2beta1 vars: USERS_NAMESPACE: platform - E2E_IMAGE: ghcr.io/agynio/devcontainer-go:1 functions: disable_argocd_sync: |- @@ -27,7 +26,7 @@ functions: fi patch_deployment: |- echo "Patching users deployment for DevSpace..." - kubectl patch deployment users-users -n ${USERS_NAMESPACE} --type strategic --patch "$(cat <<'EOF' + kubectl patch deployment users -n ${USERS_NAMESPACE} --type strategic --patch "$(cat <<'EOF' spec: template: spec: @@ -40,7 +39,7 @@ functions: emptyDir: {} containers: - name: users - image: ghcr.io/agynio/devcontainer-go:1 # keep in sync with E2E_IMAGE + image: ghcr.io/agynio/devcontainer-go:1 # dev container for source deploy workingDir: /opt/app/data command: - sh @@ -57,6 +56,9 @@ functions: volumeMounts: - name: data mountPath: /opt/app/data + livenessProbe: null + readinessProbe: null + startupProbe: null resources: requests: cpu: 500m @@ -77,26 +79,6 @@ functions: EOF )" -deployments: - e2e-runner: - namespace: ${USERS_NAMESPACE} - helm: - chart: - name: component-chart - repo: https://charts.devspace.sh - values: - containers: - - image: ${E2E_IMAGE} - env: - - name: USERS_ADDR - value: "users:50051" - labels: - app.kubernetes.io/name: users-e2e - -commands: - test:e2e: |- - devspace run-pipeline test:e2e $@ - pipelines: dev: flags: @@ -109,38 +91,26 @@ pipelines: if [ "$(get_flag "watch")" == "true" ]; then start_dev --disable-pod-replace users else - start_dev --disable-pod-replace users + kubectl rollout status deployment/users -n ${USERS_NAMESPACE} --timeout=180s + start_dev --disable-pod-replace users & echo "Waiting for users to be healthy on :50051..." healthy=false - for i in $(seq 1 60); do - if exec_container --label-selector=app.kubernetes.io/name=users -n ${USERS_NAMESPACE} -- bash -c 'nc -z localhost 50051 >/dev/null 2>&1 || (echo > /dev/tcp/localhost/50051) >/dev/null 2>&1'; then + for i in $(seq 1 120); do + if kubectl exec deploy/users -n ${USERS_NAMESPACE} -c users -- bash -c 'nc -z localhost 50051 >/dev/null 2>&1 || (echo > /dev/tcp/localhost/50051) >/dev/null 2>&1'; then healthy=true break fi sleep 2 done if [ "$healthy" != "true" ]; then - echo "ERROR: Users did not become healthy within 120s" >&2 + stop_dev users || true + echo "ERROR: Users did not become healthy within 240s" >&2 exit 1 fi echo "Dev environment ready. Stopping dev session." stop_dev users fi - test:e2e: - run: |- - create_deployments e2e-runner - start_dev e2e-runner & - sleep 5 - exec_container \ - --label-selector "app.kubernetes.io/name=users-e2e" \ - -n ${USERS_NAMESPACE} \ - -- bash -c 'cd /opt/app/data && buf generate buf.build/agynio/api --path agynio/api/users/v1 --path agynio/api/authorization/v1 --path agynio/api/identity/v1 --path agynio/api/ziti_management/v1 && go test -v -count=1 -tags e2e ./test/e2e/' - EXIT_CODE=$? - stop_dev e2e-runner - purge_deployments e2e-runner - exit $EXIT_CODE - hooks: - name: restore-argocd-auto-sync events: @@ -165,33 +135,25 @@ dev: - .git/ - .devspace/ - /.gen/ + - /bootstrap/ + - /e2e/ - /tmp/ uploadExcludePaths: - .git/ - .devspace/ - /.gen/ + - /bootstrap/ + - /e2e/ - /tmp/ downloadExcludePaths: - .git/ - .devspace/ - /.gen/ + - /bootstrap/ + - /e2e/ - /tmp/ logs: enabled: true lastLines: 200 ports: - port: "50051" - - e2e-runner: - namespace: ${USERS_NAMESPACE} - labelSelector: - app.kubernetes.io/name: users-e2e - command: ["sleep", "infinity"] - workingDir: /opt/app/data - sync: - - path: ./:/opt/app/data - excludePaths: - - .git/ - - .devspace/ - - /.gen/ - - /tmp/ diff --git a/test/e2e/api_tokens_e2e_test.go b/test/e2e/api_tokens_e2e_test.go deleted file mode 100644 index 2b51c53..0000000 --- a/test/e2e/api_tokens_e2e_test.go +++ /dev/null @@ -1,195 +0,0 @@ -//go:build e2e -// +build e2e - -package e2e - -import ( - "context" - "regexp" - "testing" - "time" - - usersv1 "github.com/agynio/users/.gen/go/agynio/api/users/v1" - "github.com/agynio/users/internal/apitoken" - "github.com/google/uuid" - "github.com/stretchr/testify/require" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/metadata" - "google.golang.org/protobuf/types/known/timestamppb" -) - -func TestAPITokensE2E(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - conn, err := grpc.DialContext(ctx, usersAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()) - require.NoError(t, err) - t.Cleanup(func() { - _ = conn.Close() - }) - - client := usersv1.NewUsersServiceClient(conn) - plainTextFormat := regexp.MustCompile(`^agyn_[0-9A-Za-z]{44}$`) - - t.Run("CreateAPIToken", func(t *testing.T) { - identityID, authedCtx := createUserContext(t, ctx, client) - resp, err := client.CreateAPIToken(authedCtx, &usersv1.CreateAPITokenRequest{Name: "CLI"}) - require.NoError(t, err) - require.NotNil(t, resp.Token) - require.True(t, plainTextFormat.MatchString(resp.GetPlaintextToken())) - require.Equal(t, resp.GetPlaintextToken()[:8], resp.Token.TokenPrefix) - require.Equal(t, identityID, resp.Token.IdentityId) - require.Equal(t, "CLI", resp.Token.Name) - require.NotNil(t, resp.Token.CreatedAt) - }) - - t.Run("CreateAPITokenWithExpiration", func(t *testing.T) { - identityID, authedCtx := createUserContext(t, ctx, client) - expiresAt := time.Now().Add(2 * time.Hour).UTC() - resp, err := client.CreateAPIToken(authedCtx, &usersv1.CreateAPITokenRequest{ - Name: "expires", - ExpiresAt: timestamppb.New(expiresAt), - }) - require.NoError(t, err) - require.Equal(t, identityID, resp.Token.IdentityId) - require.WithinDuration(t, expiresAt, resp.Token.ExpiresAt.AsTime(), time.Second) - }) - - t.Run("CreateAPITokenValidation", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - _, err := client.CreateAPIToken(authedCtx, &usersv1.CreateAPITokenRequest{}) - requireStatusCode(t, err, codes.InvalidArgument) - }) - - t.Run("CreateAPITokenPastExpiration", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - past := time.Now().Add(-1 * time.Hour) - _, err := client.CreateAPIToken(authedCtx, &usersv1.CreateAPITokenRequest{ - Name: "expired", - ExpiresAt: timestamppb.New(past), - }) - requireStatusCode(t, err, codes.InvalidArgument) - }) - - t.Run("ListAPITokens", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - firstResp := createAPIToken(t, authedCtx, client, "first", nil) - time.Sleep(10 * time.Millisecond) - secondResp := createAPIToken(t, authedCtx, client, "second", nil) - - listResp, err := client.ListAPITokens(authedCtx, &usersv1.ListAPITokensRequest{}) - require.NoError(t, err) - require.Len(t, listResp.Tokens, 2) - require.Equal(t, secondResp.Token.Id, listResp.Tokens[0].Id) - require.Equal(t, firstResp.Token.Id, listResp.Tokens[1].Id) - }) - - t.Run("ListAPITokensEmpty", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - listResp, err := client.ListAPITokens(authedCtx, &usersv1.ListAPITokensRequest{}) - require.NoError(t, err) - require.Empty(t, listResp.Tokens) - }) - - t.Run("RevokeAPIToken", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - createResp := createAPIToken(t, authedCtx, client, "revoke", nil) - - _, err := client.RevokeAPIToken(authedCtx, &usersv1.RevokeAPITokenRequest{TokenId: createResp.Token.Id}) - require.NoError(t, err) - - listResp, err := client.ListAPITokens(authedCtx, &usersv1.ListAPITokensRequest{}) - require.NoError(t, err) - require.Empty(t, listResp.Tokens) - }) - - t.Run("RevokeAPITokenNotFound", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - _, err := client.RevokeAPIToken(authedCtx, &usersv1.RevokeAPITokenRequest{TokenId: uuid.NewString()}) - requireStatusCode(t, err, codes.NotFound) - }) - - t.Run("RevokeAPITokenCrossUser", func(t *testing.T) { - _, firstCtx := createUserContext(t, ctx, client) - createResp := createAPIToken(t, firstCtx, client, "owner", nil) - _, secondCtx := createUserContext(t, ctx, client) - - _, err := client.RevokeAPIToken(secondCtx, &usersv1.RevokeAPITokenRequest{TokenId: createResp.Token.Id}) - requireStatusCode(t, err, codes.NotFound) - }) - - t.Run("ResolveAPIToken", func(t *testing.T) { - identityID, authedCtx := createUserContext(t, ctx, client) - createResp := createAPIToken(t, authedCtx, client, "resolve", nil) - resolveResp, err := client.ResolveAPIToken(ctx, &usersv1.ResolveAPITokenRequest{TokenHash: apitoken.Hash(createResp.PlaintextToken)}) - require.NoError(t, err) - require.Equal(t, identityID, resolveResp.IdentityId) - require.NotNil(t, resolveResp.Token) - require.NotNil(t, resolveResp.Token.LastUsedAt) - }) - - t.Run("ResolveAPITokenNotFound", func(t *testing.T) { - _, err := client.ResolveAPIToken(ctx, &usersv1.ResolveAPITokenRequest{TokenHash: apitoken.Hash("agyn_" + uuid.NewString())}) - requireStatusCode(t, err, codes.NotFound) - }) - - t.Run("ResolveAPITokenExpired", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - expiresAt := time.Now().Add(300 * time.Millisecond) - createResp := createAPIToken(t, authedCtx, client, "soon", &expiresAt) - if wait := time.Until(expiresAt.Add(50 * time.Millisecond)); wait > 0 { - time.Sleep(wait) - } - _, err := client.ResolveAPIToken(ctx, &usersv1.ResolveAPITokenRequest{TokenHash: apitoken.Hash(createResp.PlaintextToken)}) - requireStatusCode(t, err, codes.Unauthenticated) - }) - - t.Run("ResolveAPITokenLastUsedAtUpdates", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - createResp := createAPIToken(t, authedCtx, client, "repeat", nil) - tokenHash := apitoken.Hash(createResp.PlaintextToken) - - firstResp, err := client.ResolveAPIToken(ctx, &usersv1.ResolveAPITokenRequest{TokenHash: tokenHash}) - require.NoError(t, err) - firstUsed := firstResp.Token.LastUsedAt.AsTime() - - time.Sleep(10 * time.Millisecond) - secondResp, err := client.ResolveAPIToken(ctx, &usersv1.ResolveAPITokenRequest{TokenHash: tokenHash}) - require.NoError(t, err) - secondUsed := secondResp.Token.LastUsedAt.AsTime() - require.True(t, secondUsed.After(firstUsed)) - }) -} - -func createUserContext(t *testing.T, ctx context.Context, client usersv1.UsersServiceClient) (string, context.Context) { - t.Helper() - subject := "oidc-" + uuid.NewString() - resp, err := client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{ - OidcSubject: subject, - Name: "Token User", - Email: "token-user", - PhotoUrl: "https://example.com/token-user.png", - }) - require.NoError(t, err) - identityID := resp.User.Meta.Id - return identityID, metadata.AppendToOutgoingContext(ctx, "x-identity-id", identityID) -} - -func createAPIToken( - t *testing.T, - ctx context.Context, - client usersv1.UsersServiceClient, - name string, - expiresAt *time.Time, -) *usersv1.CreateAPITokenResponse { - t.Helper() - request := &usersv1.CreateAPITokenRequest{Name: name} - if expiresAt != nil { - request.ExpiresAt = timestamppb.New(*expiresAt) - } - resp, err := client.CreateAPIToken(ctx, request) - require.NoError(t, err) - return resp -} diff --git a/test/e2e/devices_e2e_test.go b/test/e2e/devices_e2e_test.go deleted file mode 100644 index 2e0b240..0000000 --- a/test/e2e/devices_e2e_test.go +++ /dev/null @@ -1,120 +0,0 @@ -//go:build e2e -// +build e2e - -package e2e - -import ( - "context" - "testing" - "time" - - usersv1 "github.com/agynio/users/.gen/go/agynio/api/users/v1" - "github.com/google/uuid" - "github.com/stretchr/testify/require" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials/insecure" -) - -func TestDevicesE2E(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - conn, err := grpc.DialContext(ctx, usersAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()) - require.NoError(t, err) - t.Cleanup(func() { - _ = conn.Close() - }) - - client := usersv1.NewUsersServiceClient(conn) - - t.Run("CreateDevice", func(t *testing.T) { - identityID, authedCtx := createUserContext(t, ctx, client) - resp, err := client.CreateDevice(authedCtx, &usersv1.CreateDeviceRequest{Name: "laptop"}) - require.NoError(t, err) - require.NotNil(t, resp.Device) - require.NotNil(t, resp.Device.Meta) - require.NotEmpty(t, resp.Device.Meta.Id) - require.NotNil(t, resp.Device.Meta.CreatedAt) - require.Equal(t, identityID, resp.Device.UserIdentityId) - require.Equal(t, "laptop", resp.Device.Name) - require.NotEmpty(t, resp.Device.OpenzitiIdentityId) - require.Equal(t, usersv1.DeviceStatus_DEVICE_STATUS_PENDING, resp.Device.Status) - require.NotEmpty(t, resp.EnrollmentJwt) - }) - - t.Run("CreateDeviceValidation", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - _, err := client.CreateDevice(authedCtx, &usersv1.CreateDeviceRequest{}) - requireStatusCode(t, err, codes.InvalidArgument) - }) - - t.Run("ListDevices", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - firstResp := createDevice(t, authedCtx, client, "device-"+uuid.NewString()) - secondResp := createDevice(t, authedCtx, client, "device-"+uuid.NewString()) - - listResp, err := client.ListDevices(authedCtx, &usersv1.ListDevicesRequest{}) - require.NoError(t, err) - require.Len(t, listResp.Devices, 2) - require.True(t, hasDeviceID(listResp.Devices, firstResp.Device.Meta.Id)) - require.True(t, hasDeviceID(listResp.Devices, secondResp.Device.Meta.Id)) - require.Empty(t, listResp.NextPageToken) - }) - - t.Run("ListDevicesEmpty", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - listResp, err := client.ListDevices(authedCtx, &usersv1.ListDevicesRequest{}) - require.NoError(t, err) - require.Empty(t, listResp.Devices) - require.Empty(t, listResp.NextPageToken) - }) - - t.Run("DeleteDevice", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - createResp := createDevice(t, authedCtx, client, "remove") - - _, err := client.DeleteDevice(authedCtx, &usersv1.DeleteDeviceRequest{Id: createResp.Device.Meta.Id}) - require.NoError(t, err) - - listResp, err := client.ListDevices(authedCtx, &usersv1.ListDevicesRequest{}) - require.NoError(t, err) - require.Empty(t, listResp.Devices) - }) - - t.Run("DeleteDeviceNotFound", func(t *testing.T) { - _, authedCtx := createUserContext(t, ctx, client) - _, err := client.DeleteDevice(authedCtx, &usersv1.DeleteDeviceRequest{Id: uuid.NewString()}) - requireStatusCode(t, err, codes.NotFound) - }) - - t.Run("DeleteDeviceCrossUser", func(t *testing.T) { - _, firstCtx := createUserContext(t, ctx, client) - createResp := createDevice(t, firstCtx, client, "owner") - _, secondCtx := createUserContext(t, ctx, client) - - _, err := client.DeleteDevice(secondCtx, &usersv1.DeleteDeviceRequest{Id: createResp.Device.Meta.Id}) - requireStatusCode(t, err, codes.NotFound) - }) -} - -func createDevice( - t *testing.T, - ctx context.Context, - client usersv1.UsersServiceClient, - name string, -) *usersv1.CreateDeviceResponse { - t.Helper() - resp, err := client.CreateDevice(ctx, &usersv1.CreateDeviceRequest{Name: name}) - require.NoError(t, err) - return resp -} - -func hasDeviceID(devices []*usersv1.Device, id string) bool { - for _, device := range devices { - if device.GetMeta().GetId() == id { - return true - } - } - return false -} diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go deleted file mode 100644 index e8a5532..0000000 --- a/test/e2e/e2e_test.go +++ /dev/null @@ -1,176 +0,0 @@ -//go:build e2e -// +build e2e - -package e2e - -import ( - "context" - "testing" - "time" - - usersv1 "github.com/agynio/users/.gen/go/agynio/api/users/v1" - "github.com/google/uuid" - "github.com/stretchr/testify/require" - "google.golang.org/grpc" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/credentials/insecure" - "google.golang.org/grpc/status" - "google.golang.org/protobuf/proto" -) - -func TestUsersServiceE2E(t *testing.T) { - ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute) - defer cancel() - - conn, err := grpc.DialContext(ctx, usersAddr, grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithBlock()) - require.NoError(t, err) - t.Cleanup(func() { - _ = conn.Close() - }) - - client := usersv1.NewUsersServiceClient(conn) - - t.Run("ResolveOrCreateUser", func(t *testing.T) { - subject := "oidc-" + uuid.NewString() - createResp, err := client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{ - OidcSubject: subject, - Name: "Alice", - Email: "alice@example.com", - PhotoUrl: "https://example.com/photo.png", - }) - require.NoError(t, err) - require.True(t, createResp.Created) - require.Equal(t, subject, createResp.User.OidcSubject) - - resolveResp, err := client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{ - OidcSubject: subject, - Name: "Alice Updated", - Email: "alice-updated@example.com", - PhotoUrl: "https://example.com/updated.png", - }) - require.NoError(t, err) - require.False(t, resolveResp.Created) - require.Equal(t, createResp.User.Meta.Id, resolveResp.User.Meta.Id) - }) - - t.Run("GetUser", func(t *testing.T) { - subject := "oidc-" + uuid.NewString() - createResp, err := client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{ - OidcSubject: subject, - Name: "Bob", - Email: "bob@example.com", - PhotoUrl: "https://example.com/bob.png", - }) - require.NoError(t, err) - - getResp, err := client.GetUser(ctx, &usersv1.GetUserRequest{IdentityId: createResp.User.Meta.Id}) - require.NoError(t, err) - require.Equal(t, subject, getResp.User.OidcSubject) - require.Equal(t, "Bob", getResp.User.Name) - }) - - t.Run("GetUserByOIDCSubject", func(t *testing.T) { - subject := "oidc-" + uuid.NewString() - createResp, err := client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{ - OidcSubject: subject, - Name: "Charlie", - Email: "charlie@example.com", - PhotoUrl: "https://example.com/charlie.png", - }) - require.NoError(t, err) - - getResp, err := client.GetUserByOIDCSubject(ctx, &usersv1.GetUserByOIDCSubjectRequest{OidcSubject: subject}) - require.NoError(t, err) - require.Equal(t, createResp.User.Meta.Id, getResp.User.Meta.Id) - }) - - t.Run("BatchGetUsers", func(t *testing.T) { - firstSubject := "oidc-" + uuid.NewString() - secondSubject := "oidc-" + uuid.NewString() - firstResp, err := client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{ - OidcSubject: firstSubject, - Name: "Dana", - Email: "dana@example.com", - PhotoUrl: "https://example.com/dana.png", - }) - require.NoError(t, err) - secondResp, err := client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{ - OidcSubject: secondSubject, - Name: "Elliot", - Email: "elliot@example.com", - PhotoUrl: "https://example.com/elliot.png", - }) - require.NoError(t, err) - - batchResp, err := client.BatchGetUsers(ctx, &usersv1.BatchGetUsersRequest{ - IdentityIds: []string{firstResp.User.Meta.Id, secondResp.User.Meta.Id, uuid.NewString()}, - }) - require.NoError(t, err) - require.Len(t, batchResp.Users, 2) - require.True(t, hasUserID(batchResp.Users, firstResp.User.Meta.Id)) - require.True(t, hasUserID(batchResp.Users, secondResp.User.Meta.Id)) - }) - - t.Run("UpdateUser", func(t *testing.T) { - subject := "oidc-" + uuid.NewString() - createResp, err := client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{ - OidcSubject: subject, - Name: "Frank", - Email: "frank@example.com", - PhotoUrl: "https://example.com/frank.png", - }) - require.NoError(t, err) - - updateResp, err := client.UpdateUser(ctx, &usersv1.UpdateUserRequest{ - IdentityId: createResp.User.Meta.Id, - Name: proto.String("Frank Updated"), - PhotoUrl: proto.String("https://example.com/frank-updated.png"), - }) - require.NoError(t, err) - require.Equal(t, "Frank Updated", updateResp.User.Name) - require.Equal(t, "https://example.com/frank-updated.png", updateResp.User.PhotoUrl) - }) - - t.Run("NegativePaths", func(t *testing.T) { - _, err := client.GetUser(ctx, &usersv1.GetUserRequest{IdentityId: uuid.NewString()}) - requireStatusCode(t, err, codes.NotFound) - - _, err = client.GetUser(ctx, &usersv1.GetUserRequest{IdentityId: "not-a-uuid"}) - requireStatusCode(t, err, codes.InvalidArgument) - - _, err = client.ResolveOrCreateUser(ctx, &usersv1.ResolveOrCreateUserRequest{}) - requireStatusCode(t, err, codes.InvalidArgument) - - _, err = client.GetUserByOIDCSubject(ctx, &usersv1.GetUserByOIDCSubjectRequest{OidcSubject: ""}) - requireStatusCode(t, err, codes.InvalidArgument) - - _, err = client.BatchGetUsers(ctx, &usersv1.BatchGetUsersRequest{IdentityIds: []string{"bad"}}) - requireStatusCode(t, err, codes.InvalidArgument) - - ids := make([]string, 101) - for i := range ids { - ids[i] = uuid.NewString() - } - _, err = client.BatchGetUsers(ctx, &usersv1.BatchGetUsersRequest{IdentityIds: ids}) - requireStatusCode(t, err, codes.InvalidArgument) - - _, err = client.UpdateUser(ctx, &usersv1.UpdateUserRequest{IdentityId: uuid.NewString()}) - requireStatusCode(t, err, codes.InvalidArgument) - }) -} - -func hasUserID(users []*usersv1.User, id string) bool { - for _, user := range users { - if user.GetMeta().GetId() == id { - return true - } - } - return false -} - -func requireStatusCode(t *testing.T, err error, code codes.Code) { - t.Helper() - statusErr, ok := status.FromError(err) - require.True(t, ok) - require.Equal(t, code, statusErr.Code()) -} diff --git a/test/e2e/main_test.go b/test/e2e/main_test.go deleted file mode 100644 index db8efc5..0000000 --- a/test/e2e/main_test.go +++ /dev/null @@ -1,15 +0,0 @@ -//go:build e2e -// +build e2e - -package e2e - -import "os" - -var usersAddr = envOrDefault("USERS_ADDR", "users:50051") - -func envOrDefault(key, fallback string) string { - if value := os.Getenv(key); value != "" { - return value - } - return fallback -}