Skip to content

Commit

Permalink
Merge pull request #97 from zitadel/run-tests-on-pr
Browse files Browse the repository at this point in the history
chore: run tests on PR
  • Loading branch information
eliobischof authored May 24, 2023
2 parents 1298854 + a5ceee1 commit 587149a
Show file tree
Hide file tree
Showing 10 changed files with 182 additions and 18 deletions.
14 changes: 14 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
### Definition of Ready

- [ ] Short description of the feature/issue is added in the pr description
- [ ] PR is linked to the corresponding user story
- [ ] Acceptance criteria are met
- [ ] All open todos and follow ups are defined in a new ticket and justified
- [ ] Deviations from the acceptance criteria and design are agreed with the PO and documented.
- [ ] No debug or dead code
- [ ] My code has no repetitions
- [ ] All non-functional requirements are met
- [ ] The generic lifecycle acceptance test passes for affected resources.
- [ ] Examples are up-to-date and meaningful. The provider version is incremented.
- [ ] Docs are generated.
- [ ] Code is generated where possible.
55 changes: 55 additions & 0 deletions .github/workflows/pull_request.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Test Provider

on: pull_request

jobs:
test:

runs-on: ubuntu-20.04

permissions:
contents: read

steps:

- name: Checkout Code
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Make Machinekey Directory Writable
working-directory: acceptance
run: "chmod -R 777 machinekey"

- name: Set up ZITADEL
working-directory: acceptance
run: docker compose up -d zitadel

- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.19

- name: Download Go Modules
run: go mod download

- name: Await ZITADEL
working-directory: acceptance
run: docker compose run wait_for_zitadel

- name: Run Acceptance Tests
run: TF_ACC=1 TF_ACC_ZITADEL_TOKEN=$(pwd)/acceptance/machinekey/zitadel-admin-sa.json go test ./...

- name: Save ZITADEL Logs
working-directory: acceptance
if: always()
run: docker compose logs zitadel > .zitadel.log

- name: Archive ZITADEL Logs
if: always()
uses: actions/upload-artifact@v3
with:
name: pull-request-tests
path: |
acceptance/.zitadel.log
retention-days: 30
23 changes: 16 additions & 7 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,26 +6,35 @@
```bash
# export the printed environment variable from the go run ./... -debug command above. E.g.
export TF_REATTACH_PROVIDERS='{"registry.terraform.io/zitadel/zitadel":{"Protocol":"grpc","ProtocolVersion":6,"Pid":8123,"Test":true,"Addr":{"Network":"unix","String":"/tmp/plugin275634719"}}}'

# go to a directory containing .tf files.
cd /my-zitadel-terraform-files

# apply them
terraform apply
```
4. The execution stops at your breakpoints.

# Run Acceptance Tests

Ensure ZITADEL listens at http://localhost:8080 and you have a service account key in your local filesystem.
The easiest way to achieve that is [to follow this guide](https://zitadel.com/docs/self-hosting/deploy/compose#docker-compose-with-service-account).
Run a local ZITADEL instance using docker compose.

```bash
TF_ACC=1 TF_ACC_ZITADEL_TOKEN=/my-token.json go test ./...
# To have the machine key written with the correct ownership, set your current users ID.
export ZITADEL_DEV_UID="$(id -u)"

# Pull Images
docker compose --file ./acceptance/docker-compose.yaml pull

# Setup ZITADEL
docker compose --file ./acceptance/docker-compose.yaml run wait_for_zitadel
```

The tests are flaky when resources should be cleaned up.
This results in dangling resources.
Run the accepance tests using the machine key generated by ZITADEL.

```bash
TF_ACC=1 TF_ACC_ZITADEL_TOKEN=$(pwd)/acceptance/machinekey/zitadel-admin-sa.json go test ./...
```

# Generate Docs

Expand Down
34 changes: 34 additions & 0 deletions acceptance/docker-compose.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
version: '3.8'

services:
zitadel:
user: '${ZITADEL_DEV_UID}'
image: '${ZITADEL_IMAGE:-ghcr.io/zitadel/zitadel:latest}'
command: 'start-from-init --masterkey "MasterkeyNeedsToHave32Characters" --tlsMode disabled --config /zitadel.yaml --steps /zitadel.yaml'
ports:
- "8080:8080"
volumes:
- ./machinekey:/machinekey
- ./zitadel.yaml:/zitadel.yaml
depends_on:
db:
condition: 'service_healthy'

db:
image: 'cockroachdb/cockroach:v22.2.2'
command: 'start-single-node --insecure --http-addr :9090'
healthcheck:
test: ['CMD', 'curl', '-f', 'http://localhost:9090/health?ready=1']
interval: '10s'
timeout: '30s'
retries: 5
start_period: '20s'
ports:
- "26257:26257"
- "9090:9090"

wait_for_zitadel:
image: curlimages/curl:8.00.1
command: [ "/bin/sh", "-c", "i=0; while ! curl http://zitadel:8080/debug/ready && [ $$i -lt 30 ]; do sleep 1; i=$$((i+1)); done; [ $$i -eq 30 ] && exit 1 || exit 0" ]
depends_on:
- zitadel
1 change: 1 addition & 0 deletions acceptance/machinekey/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
zitadel-admin-sa.json
Empty file added acceptance/machinekey/.gitkeep
Empty file.
18 changes: 18 additions & 0 deletions acceptance/zitadel.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
FirstInstance:
MachineKeyPath: /machinekey/zitadel-admin-sa.json
Org:
Machine:
Machine:
Username: zitadel-admin-sa
Name: Admin
MachineKey:
Type: 1

Database:
Cockroach:
Host: db

Logstore:
Access:
Stdout:
Enabled: true
24 changes: 24 additions & 0 deletions zitadel/v2/helper/test_utils/checks.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package test_utils

import (
"fmt"
"regexp"
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
Expand All @@ -14,3 +16,25 @@ func CheckStateHasIDSet(frame BaseTestFrame) resource.TestCheckFunc {
return resource.TestMatchResourceAttr(frame.TerraformName, "id", idPattern)(state)
}
}

func CheckAMinute(check resource.TestCheckFunc) resource.TestCheckFunc {
return func(state *terraform.State) error {
return retryAMinute(func() error {
return check(state)
})
}
}

func retryAMinute(try func() error) error {
start := time.Now()
for {
err := try()
if err == nil {
return nil
}
if time.Since(start) > time.Minute {
return fmt.Errorf("function failed after retrying for a minute: %w", err)
}
time.Sleep(time.Second)
}
}
6 changes: 3 additions & 3 deletions zitadel/v2/helper/test_utils/lifecyletest.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func RunLifecyleTest(
}, { // Check resource is created
Config: initialConfig,
Check: resource.ComposeAggregateTestCheckFunc(
checkRemoteProperty(initialProperty),
CheckAMinute(checkRemoteProperty(initialProperty)),
CheckStateHasIDSet(frame),
),
}, { // Check updating name has a diff
Expand All @@ -43,7 +43,7 @@ func RunLifecyleTest(
PlanOnly: true,
}, { // Check remote state can be updated
Config: updatedNameConfig,
Check: checkRemoteProperty(updatedProperty),
Check: CheckAMinute(checkRemoteProperty(updatedProperty)),
},
}
if secretAttribute != "" {
Expand Down Expand Up @@ -77,7 +77,7 @@ func RunLifecyleTest(
}
resource.Test(t, resource.TestCase{
ProviderFactories: ZitadelProviderFactories(frame.ConfiguredProvider),
CheckDestroy: checkDestroy,
CheckDestroy: CheckAMinute(checkDestroy),
Steps: steps,
})
}
25 changes: 17 additions & 8 deletions zitadel/v2/helper/test_utils/org_frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,25 @@ func NewOrgTestFrame(resourceType string) (*OrgTestFrame, error) {
if err != nil {
return nil, err
}
org, err := mgmtClient.GetOrgByDomainGlobal(baseFrame, &management.GetOrgByDomainGlobalRequest{Domain: fmt.Sprintf("%s.%s", orgName, domain)})
orgID := org.GetOrg().GetId()
if status.Code(err) == codes.NotFound {
var newOrg *management.AddOrgResponse
newOrg, err = mgmtClient.AddOrg(baseFrame, &management.AddOrgRequest{Name: orgName})
orgID = newOrg.GetId()
}
if err != nil {
org, err := mgmtClient.AddOrg(baseFrame, &management.AddOrgRequest{Name: orgName})
alreadyExists := status.Code(err) == codes.AlreadyExists
if err != nil && !alreadyExists {
return nil, err
}
orgID := org.GetId()
if alreadyExists {
err := retryAMinute(func() error {
getOrgResp, getOrgErr := mgmtClient.GetOrgByDomainGlobal(baseFrame, &management.GetOrgByDomainGlobalRequest{Domain: fmt.Sprintf("%s.%s", orgName, domain)})
if getOrgErr != nil {
return getOrgErr
}
orgID = getOrgResp.GetOrg().GetId()
return nil
})
if err != nil {
return nil, err
}
}
mgmtClient, err = helper.GetManagementClient(baseFrame.ClientInfo, orgID)
return &OrgTestFrame{
BaseTestFrame: *baseFrame,
Expand Down

0 comments on commit 587149a

Please sign in to comment.