diff --git a/.github/workflows/integration.yml b/.github/workflows/integration.yml new file mode 100644 index 0000000000..6c80e53723 --- /dev/null +++ b/.github/workflows/integration.yml @@ -0,0 +1,35 @@ +on: + push: + +jobs: + integration-tests: + strategy: + matrix: + db: [cockroach, postgres] + runs-on: ubuntu-20.04 + env: + DOCKER_BUILDKIT: 1 + steps: + - name: Set up Go + uses: actions/setup-go@v3 + with: + go-version: 1.19 + - name: Source checkout + uses: actions/checkout@v3 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v2 + with: + driver: docker + install: true + - name: Generate gRPC definitions + run: docker build -f build/grpc/Dockerfile -t zitadel-base:local . + - name: Copy gRPC definitions + run: docker build -f build/zitadel/Dockerfile . -t zitadel-go-base --target go-copy -o . + - name: Download Go modules + run: go mod download + - name: Start ${{ matrix.db }} database + run: docker compose -f e2e/config/integration/docker-compose.yaml up --wait ${{ matrix.db }} + - name: Run integration test + env: + INTEGRATION_DB_FLAVOR: ${{ matrix.db }} + run: go test -tags=integration -v ./internal/integration ./internal/api/grpc/... diff --git a/e2e/config/integration/docker-compose.yaml b/e2e/config/integration/docker-compose.yaml new file mode 100644 index 0000000000..85d68e4a2a --- /dev/null +++ b/e2e/config/integration/docker-compose.yaml @@ -0,0 +1,24 @@ +version: '3.8' + +services: + cockroach: + extends: + file: '../localhost/docker-compose.yaml' + service: 'db' + + postgres: + restart: 'always' + image: 'postgres:15' + environment: + - POSTGRES_USER=zitadel + - PGUSER=zitadel + - POSTGRES_DB=zitadel + - POSTGRES_HOST_AUTH_METHOD=trust + healthcheck: + test: ["CMD-SHELL", "pg_isready"] + interval: '10s' + timeout: '30s' + retries: 5 + start_period: '20s' + ports: + - 5432:5432 diff --git a/internal/api/grpc/admin/failed_event_converter_test.go b/internal/api/grpc/admin/failed_event_converter_test.go index 6edc36c1e2..cb6c6bddab 100644 --- a/internal/api/grpc/admin/failed_event_converter_test.go +++ b/internal/api/grpc/admin/failed_event_converter_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package admin import ( diff --git a/internal/api/grpc/admin/iam_member_converter_test.go b/internal/api/grpc/admin/iam_member_converter_test.go index 74dd329ee1..f2b90031db 100644 --- a/internal/api/grpc/admin/iam_member_converter_test.go +++ b/internal/api/grpc/admin/iam_member_converter_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package admin import ( diff --git a/internal/api/grpc/admin/idp_converter_test.go b/internal/api/grpc/admin/idp_converter_test.go index 23d378b888..0eb04efcb1 100644 --- a/internal/api/grpc/admin/idp_converter_test.go +++ b/internal/api/grpc/admin/idp_converter_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package admin import ( diff --git a/internal/api/grpc/admin/admin_test.go b/internal/api/grpc/admin/information_integration_test.go similarity index 50% rename from internal/api/grpc/admin/admin_test.go rename to internal/api/grpc/admin/information_integration_test.go index 9ca65d819c..65f2dd93b7 100644 --- a/internal/api/grpc/admin/admin_test.go +++ b/internal/api/grpc/admin/information_integration_test.go @@ -1,16 +1,18 @@ +//go:build integration + package admin_test import ( "context" "os" - "strings" "testing" "time" - "github.com/zitadel/zitadel/internal/integration" -) + "github.com/stretchr/testify/require" -const commandLine = `start-from-init --masterkey MasterkeyNeedsToHave32Characters --tlsMode disabled --config ../../e2e/config/localhost/zitadel.yaml --steps ../../e2e/config/localhost/zitadel.yaml` + "github.com/zitadel/zitadel/internal/integration" + "github.com/zitadel/zitadel/pkg/grpc/admin" +) var ( Tester *integration.Tester @@ -21,9 +23,15 @@ func TestMain(m *testing.M) { ctx, cancel := context.WithTimeout(context.Background(), time.Minute) defer cancel() - Tester = integration.NewTester(ctx, strings.Split(commandLine, " ")) + Tester = integration.NewTester(ctx) defer Tester.Done() return m.Run() }()) } + +func TestServer_Healthz(t *testing.T) { + client := admin.NewAdminServiceClient(Tester.ClientConn) + _, err := client.Healthz(context.TODO(), &admin.HealthzRequest{}) + require.NoError(t, err) +} diff --git a/internal/api/grpc/admin/information_test.go b/internal/api/grpc/admin/information_test.go deleted file mode 100644 index e2867805be..0000000000 --- a/internal/api/grpc/admin/information_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package admin_test - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/zitadel/zitadel/pkg/grpc/admin" -) - -func TestServer_Healthz(t *testing.T) { - client := admin.NewAdminServiceClient(Tester.ClientConn) - _, err := client.Healthz(context.TODO(), &admin.HealthzRequest{}) - require.NoError(t, err) -} diff --git a/internal/api/grpc/errors/caos_errors_test.go b/internal/api/grpc/errors/caos_errors_test.go index 3a14f1bbfc..6efe37b588 100644 --- a/internal/api/grpc/errors/caos_errors_test.go +++ b/internal/api/grpc/errors/caos_errors_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package errors import ( diff --git a/internal/api/grpc/header_test.go b/internal/api/grpc/header_test.go index e304900073..085473328e 100644 --- a/internal/api/grpc/header_test.go +++ b/internal/api/grpc/header_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package grpc import ( diff --git a/internal/api/grpc/management/idp_converter_test.go b/internal/api/grpc/management/idp_converter_test.go index 999be2ea06..ae30b09c89 100644 --- a/internal/api/grpc/management/idp_converter_test.go +++ b/internal/api/grpc/management/idp_converter_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package management import ( diff --git a/internal/api/grpc/server/middleware/auth_interceptor_test.go b/internal/api/grpc/server/middleware/auth_interceptor_test.go index abe50606f9..d51de2ff7a 100644 --- a/internal/api/grpc/server/middleware/auth_interceptor_test.go +++ b/internal/api/grpc/server/middleware/auth_interceptor_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package middleware import ( diff --git a/internal/api/grpc/server/middleware/error_interceptor_test.go b/internal/api/grpc/server/middleware/error_interceptor_test.go index 82dc35f64a..3ce69e0d34 100644 --- a/internal/api/grpc/server/middleware/error_interceptor_test.go +++ b/internal/api/grpc/server/middleware/error_interceptor_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package middleware import ( diff --git a/internal/api/grpc/server/middleware/instance_interceptor_test.go b/internal/api/grpc/server/middleware/instance_interceptor_test.go index 513dfe96cc..194fafbdde 100644 --- a/internal/api/grpc/server/middleware/instance_interceptor_test.go +++ b/internal/api/grpc/server/middleware/instance_interceptor_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package middleware import ( diff --git a/internal/api/grpc/server/probes_test.go b/internal/api/grpc/server/probes_test.go index 15c889e24c..1d743178c8 100644 --- a/internal/api/grpc/server/probes_test.go +++ b/internal/api/grpc/server/probes_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package server import ( diff --git a/internal/api/grpc/system/failed_event_converter_test.go b/internal/api/grpc/system/failed_event_converter_test.go index f91c2d1b4f..27caeff918 100644 --- a/internal/api/grpc/system/failed_event_converter_test.go +++ b/internal/api/grpc/system/failed_event_converter_test.go @@ -1,3 +1,5 @@ +//go:build !integration + package system_test import ( diff --git a/internal/integration/config/cockroach.yaml b/internal/integration/config/cockroach.yaml new file mode 100644 index 0000000000..920e3cd6ec --- /dev/null +++ b/internal/integration/config/cockroach.yaml @@ -0,0 +1,10 @@ +Database: + cockroach: + Host: localhost + Port: 26257 + Database: zitadel + Options: "" + User: + Username: zitadel + Admin: + Username: root diff --git a/internal/integration/config/postgres.yaml b/internal/integration/config/postgres.yaml new file mode 100644 index 0000000000..0ef4739e25 --- /dev/null +++ b/internal/integration/config/postgres.yaml @@ -0,0 +1,15 @@ +Database: + postgres: + Host: localhost + Port: 5432 + Database: zitadel + MaxOpenConns: 20 + MaxIdleConns: 10 + User: + Username: zitadel + SSL: + Mode: disable + Admin: + Username: zitadel + SSL: + Mode: disable diff --git a/internal/integration/config/zitadel.yaml b/internal/integration/config/zitadel.yaml new file mode 100644 index 0000000000..de4eb8aa1d --- /dev/null +++ b/internal/integration/config/zitadel.yaml @@ -0,0 +1,38 @@ +Log: + Level: debug + +TLS: + Enabled: false + +FirstInstance: + Org: + Human: + PasswordChangeRequired: false + +LogStore: + Access: + Database: + Enabled: true + Debounce: + MinFrequency: 0s + MaxBulkSize: 0 + Execution: + Database: + Enabled: true + Stdout: + Enabled: true + +Quotas: + Access: + ExhaustedCookieKey: "zitadel.quota.limiting" + ExhaustedCookieMaxAge: "60s" + +Projections: + Customizations: + NotificationsQuotas: + RequeueEvery: 1s + +DefaultInstance: + LoginPolicy: + MfaInitSkipLifetime: "0" + diff --git a/internal/integration/integration.go b/internal/integration/integration.go index e5a91f786b..2cba61c2bd 100644 --- a/internal/integration/integration.go +++ b/internal/integration/integration.go @@ -2,11 +2,15 @@ package integration import ( + "bytes" "context" + _ "embed" "fmt" "os" + "strings" "sync" + "github.com/spf13/viper" "github.com/zitadel/logging" "google.golang.org/grpc" "google.golang.org/grpc/credentials/insecure" @@ -15,6 +19,15 @@ import ( "github.com/zitadel/zitadel/cmd/start" ) +var ( + //go:embed config/zitadel.yaml + zitadelYAML []byte + //go:embed config/cockroach.yaml + cockroachYAML []byte + //go:embed config/postgres.yaml + postgresYAML []byte +) + type Tester struct { *start.Server ClientConn *grpc.ClientConn @@ -22,6 +35,8 @@ type Tester struct { wg sync.WaitGroup // used for shutdown } +const commandLine = `start-from-init --masterkey MasterkeyNeedsToHave32Characters --tlsMode disabled` + func (s *Tester) createClientConn(ctx context.Context) { target := fmt.Sprintf("localhost:%d", s.Config.Port) cc, err := grpc.DialContext(ctx, target, @@ -45,16 +60,31 @@ func (s *Tester) Done() { s.wg.Wait() } -func NewTester(ctx context.Context, args []string) *Tester { - tester := new(Tester) +func NewTester(ctx context.Context) *Tester { + args := strings.Split(commandLine, " ") + sc := make(chan *start.Server) + cmd := cmd.New(os.Stdout, os.Stdin, args, sc) + cmd.SetArgs(args) + err := viper.MergeConfig(bytes.NewBuffer(zitadelYAML)) + logging.OnError(err).Fatal() + + flavor := os.Getenv("INTEGRATION_DB_FLAVOR") + switch flavor { + case "cockroach": + err = viper.MergeConfig(bytes.NewBuffer(cockroachYAML)) + case "postgres": + err = viper.MergeConfig(bytes.NewBuffer(postgresYAML)) + default: + logging.New().WithField("flavor", flavor).Fatal("unknown db flavor set in INTEGRATION_DB_FLAVOR") + } + logging.OnError(err).Fatal() + + tester := new(Tester) tester.wg.Add(1) go func(wg *sync.WaitGroup) { - defer wg.Done() - - cmd := cmd.New(os.Stdout, os.Stdin, args, sc) - cmd.SetArgs(args) logging.OnError(cmd.Execute()).Fatal() + wg.Done() }(&tester.wg) select { diff --git a/internal/integration/integration_test.go b/internal/integration/integration_test.go index 4da09350fb..bb9b12f97e 100644 --- a/internal/integration/integration_test.go +++ b/internal/integration/integration_test.go @@ -1,18 +1,17 @@ +//go:build integration + package integration import ( "context" - "strings" "testing" "time" ) -const commandLine = `start-from-init --masterkey MasterkeyNeedsToHave32Characters --tlsMode disabled --config ../../e2e/config/localhost/zitadel.yaml --steps ../../e2e/config/localhost/zitadel.yaml` - func TestNewTester(t *testing.T) { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - s := NewTester(ctx, strings.Split(commandLine, " ")) + s := NewTester(ctx) defer s.Done() }