diff --git a/.github/workflows/test_integration_jaas.yaml b/.github/workflows/test_integration_jaas.yaml new file mode 100644 index 00000000..e5745901 --- /dev/null +++ b/.github/workflows/test_integration_jaas.yaml @@ -0,0 +1,90 @@ +# A similar set of tests to test_integration but against a JAAS controller +name: Integration tests with JAAS + +# This GitHub action runs your tests for each pull request. +on: + pull_request: + paths-ignore: + - "README.md" + - "project-docs/**" + - ".github/ISSUE_TEMPLATE/**" + - ".github/PULL_REQUEST_TEMPLATE.md" + push: + branches: + - "main" + paths-ignore: + - "README.md" + - "project-docs/**" + - ".github/ISSUE_TEMPLATE/**" + - ".github/PULL_REQUEST_TEMPLATE.md" + workflow_dispatch: + +# Testing needs read permission and access to Github's container registry to pull JIMM. +permissions: + contents: read + packages: read + +jobs: + # Ensure project builds before running test + build: + name: Build + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + cache: true + - run: go build -v . + + test: + name: Integration + needs: build + runs-on: ubuntu-latest + strategy: + fail-fast: false + timeout-minutes: 60 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: "go.mod" + cache: true + - uses: hashicorp/setup-terraform@v3 + with: + terraform_version: "1.9.*" + terraform_wrapper: false + # Starting JAAS will start the JIMM controller and dependencies and create a Juju controller on LXD and connect it to JIMM. + - name: Setup JAAS + uses: canonical/jimm/.github/actions/test-server@v3 + id: jaas + with: + jimm-version: v3.1.8 + juju-channel: 3/stable + ghcr-pat: ${{ secrets.GITHUB_TOKEN }} + - name: Create additional networks when testing with LXD + run: | + sudo lxc network create management-br ipv4.address=10.150.40.1/24 ipv4.nat=true ipv6.address=none ipv6.nat=false + sudo lxc network create public-br ipv4.address=10.170.80.1/24 ipv4.nat=true ipv6.address=none ipv6.nat=false + - name: "Set environment to configure provider" + # language=bash + run: | + CONTROLLER=$(juju whoami --format yaml | yq .controller) + + echo "IS_JAAS=true" >> $GITHUB_ENV + echo "JUJU_AGENT_VERSION=$(juju show-controller | yq .$CONTROLLER.details.agent-version |tr -d '"')" >> $GITHUB_ENV + echo "JUJU_CONTROLLER_ADDRESSES=$(juju show-controller | yq .$CONTROLLER.details.api-endpoints | yq -r '. | join(",")')" >> $GITHUB_ENV + echo "JUJU_CLIENT_ID=${{ steps.jaas.outputs.client-id }}" >> $GITHUB_ENV + echo "JUJU_CLIENT_SECRET=${{ steps.jaas.outputs.client-secret }}" >> $GITHUB_ENV + echo "JUJU_CA_CERT<> $GITHUB_ENV + echo "${{ steps.jaas.outputs.ca-cert }}" >> $GITHUB_ENV + echo "EOF" >> $GITHUB_ENV + echo "TEST_MANAGEMENT_BR=10.150.40.0/24" >> $GITHUB_ENV + echo "TEST_PUBLIC_BR=10.170.80.0/24" >> $GITHUB_ENV + - run: go mod download + - env: + TF_ACC: "1" + TEST_CLOUD: "lxd" + run: go test -parallel 1 -timeout 40m -v -cover ./internal/provider/ + timeout-minutes: 40 diff --git a/internal/provider/provider_test.go b/internal/provider/provider_test.go index 6027c911..42eeadd6 100644 --- a/internal/provider/provider_test.go +++ b/internal/provider/provider_test.go @@ -21,7 +21,10 @@ import ( "github.com/juju/terraform-provider-juju/internal/juju" ) -const TestProviderStableVersion = "0.12.0" +const ( + TestProviderStableVersion = "0.12.0" + isJaasEnvKey = "IS_JAAS" +) // providerFactories are used to instantiate the Framework provider during // acceptance testing. @@ -43,6 +46,24 @@ func init() { } } +// SkipJAAS should be called at the top of any tests that are not appropriate to +// run against JAAS. These include things like Juju access related tests where a +// JAAS specific resource is available. +func SkipJAAS(t *testing.T) { + if _, ok := os.LookupEnv("IS_JAAS"); ok { + t.Skip("Skipping test when running against JAAS") + } +} + +// OnlyTestAgainstJAAS should be called at the top of any tests that are not +// appropriate to run against a Juju controller. This includes tests for all JAAS +// specific resources where only JAAS implements the necessary API methods. +func OnlyTestAgainstJAAS(t *testing.T) { + if _, ok := os.LookupEnv("IS_JAAS"); !ok { + t.Skip("Skipping JAAS specific test against Juju") + } +} + func TestProviderConfigure(t *testing.T) { testAccPreCheck(t) jujuProvider := NewJujuProvider("dev") @@ -51,6 +72,7 @@ func TestProviderConfigure(t *testing.T) { } func TestProviderConfigureUsernameFromEnv(t *testing.T) { + SkipJAAS(t) testAccPreCheck(t) jujuProvider := NewJujuProvider("dev") userNameValue := "the-username" @@ -65,6 +87,7 @@ func TestProviderConfigureUsernameFromEnv(t *testing.T) { } func TestProviderConfigurePasswordFromEnv(t *testing.T) { + SkipJAAS(t) testAccPreCheck(t) jujuProvider := NewJujuProvider("dev") passwordValue := "the-password" @@ -78,6 +101,7 @@ func TestProviderConfigurePasswordFromEnv(t *testing.T) { } func TestProviderConfigureClientIDAndSecretFromEnv(t *testing.T) { + SkipJAAS(t) testAccPreCheck(t) jujuProvider := NewJujuProvider("dev") emptyValue := "" @@ -118,6 +142,7 @@ const ( // TODO: find an alternative way of running test on Mac func TestProviderConfigurex509FromEnv(t *testing.T) { + SkipJAAS(t) if runtime.GOOS == "darwin" { //Due to a bug in Go this test does not work on darwin OS //https://github.com/golang/go/issues/52010 @@ -135,6 +160,7 @@ func TestProviderConfigurex509FromEnv(t *testing.T) { } func TestProviderConfigurex509InvalidFromEnv(t *testing.T) { + SkipJAAS(t) jujuProvider := NewJujuProvider("dev") //Set the CA to the invalid one above //Juju will ignore the system trust store if we set the CA property @@ -153,6 +179,28 @@ func testAccPreCheck(t *testing.T) { if TestClient != nil { return } + if val, ok := os.LookupEnv(isJaasEnvKey); ok && val == "true" { + validateJAASTestConfig(t) + } else { + validateJujuTestConfig(t) + } + confResp := configureProvider(t, Provider) + assert.Equal(t, confResp.Diagnostics.HasError(), false, confResp.Diagnostics.Errors()) + testClient, ok := confResp.ResourceData.(*juju.Client) + assert.Truef(t, ok, "ResourceData, not of type juju client") + TestClient = testClient +} + +func validateJAASTestConfig(t *testing.T) { + if v := os.Getenv(JujuClientIDEnvKey); v == "" { + t.Fatalf("%s must be set for acceptance tests", JujuClientIDEnvKey) + } + if v := os.Getenv(JujuClientSecretEnvKey); v == "" { + t.Fatalf("%s must be set for acceptance tests", JujuClientSecretEnvKey) + } +} + +func validateJujuTestConfig(t *testing.T) { if v := os.Getenv(JujuUsernameEnvKey); v == "" { t.Fatalf("%s must be set for acceptance tests", JujuUsernameEnvKey) } @@ -171,11 +219,6 @@ func testAccPreCheck(t *testing.T) { t.Fatalf("%s must be set for acceptance tests", JujuCACertEnvKey) } } - confResp := configureProvider(t, Provider) - assert.Equal(t, confResp.Diagnostics.HasError(), false) - testClient, ok := confResp.ResourceData.(*juju.Client) - assert.Truef(t, ok, "ResourceData, not of type juju client") - TestClient = testClient } func configureProvider(t *testing.T, p provider.Provider) provider.ConfigureResponse { diff --git a/internal/provider/resource_access_model_test.go b/internal/provider/resource_access_model_test.go index a0262151..e93858ac 100644 --- a/internal/provider/resource_access_model_test.go +++ b/internal/provider/resource_access_model_test.go @@ -13,6 +13,7 @@ import ( ) func TestAcc_ResourceAccessModel(t *testing.T) { + SkipJAAS(t) userName := acctest.RandomWithPrefix("tfuser") userPassword := acctest.RandomWithPrefix("tf-test-user") userName2 := acctest.RandomWithPrefix("tfuser") @@ -67,6 +68,7 @@ func TestAcc_ResourceAccessModel(t *testing.T) { } func TestAcc_ResourceAccessModel_UpgradeProvider(t *testing.T) { + SkipJAAS(t) if testingCloud != LXDCloudTesting { t.Skip(t.Name() + " only runs with LXD") } diff --git a/internal/provider/resource_offer_test.go b/internal/provider/resource_offer_test.go index 982acbbd..b9e11c5d 100644 --- a/internal/provider/resource_offer_test.go +++ b/internal/provider/resource_offer_test.go @@ -5,6 +5,7 @@ package provider import ( "fmt" + "os" "testing" "github.com/hashicorp/terraform-plugin-testing/helper/acctest" @@ -27,8 +28,8 @@ func TestAcc_ResourceOffer(t *testing.T) { Config: testAccResourceOffer(modelName, "base = \"ubuntu@22.04\""), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("juju_offer.this", "model", modelName), - resource.TestCheckResourceAttr("juju_offer.this", "url", fmt.Sprintf("%v/%v.%v", "admin", modelName, "this")), - resource.TestCheckResourceAttr("juju_offer.this", "id", fmt.Sprintf("%v/%v.%v", "admin", modelName, "this")), + resource.TestCheckResourceAttr("juju_offer.this", "url", fmt.Sprintf("%v/%v.%v", expectedOfferUser(), modelName, "this")), + resource.TestCheckResourceAttr("juju_offer.this", "id", fmt.Sprintf("%v/%v.%v", expectedOfferUser(), modelName, "this")), ), }, { @@ -40,7 +41,7 @@ func TestAcc_ResourceOffer(t *testing.T) { map[string]string{"name": "apptwo", "endpoint": "db", "offer_url": ""}), resource.TestCheckTypeSetElemNestedAttrs("juju_integration.int", "application.*", - map[string]string{"name": "", "endpoint": "", "offer_url": fmt.Sprintf("%v/%v.%v", "admin", + map[string]string{"name": "", "endpoint": "", "offer_url": fmt.Sprintf("%v/%v.%v", expectedOfferUser(), modelName2, "appone")}), ), }, @@ -124,8 +125,8 @@ func TestAcc_ResourceOffer_UpgradeProvider(t *testing.T) { Config: testAccResourceOffer(modelName, "series = \"focal\""), Check: resource.ComposeTestCheckFunc( resource.TestCheckResourceAttr("juju_offer.this", "model", modelName), - resource.TestCheckResourceAttr("juju_offer.this", "url", fmt.Sprintf("%v/%v.%v", "admin", modelName, "this")), - resource.TestCheckResourceAttr("juju_offer.this", "id", fmt.Sprintf("%v/%v.%v", "admin", modelName, "this")), + resource.TestCheckResourceAttr("juju_offer.this", "url", fmt.Sprintf("%v/%v.%v", expectedOfferUser(), modelName, "this")), + resource.TestCheckResourceAttr("juju_offer.this", "id", fmt.Sprintf("%v/%v.%v", expectedOfferUser(), modelName, "this")), ), }, { @@ -161,3 +162,13 @@ resource "juju_offer" "this" { } `, modelName, os) } + +func expectedOfferUser() string { + // Only 1 field is expected to be populated. + username := os.Getenv(JujuUsernameEnvKey) + clientId := os.Getenv(JujuClientIDEnvKey) + if clientId != "" { + clientId = clientId + "@serviceaccount" + } + return username + clientId +} diff --git a/internal/provider/resource_user_test.go b/internal/provider/resource_user_test.go index 4f84b1a8..3658b962 100644 --- a/internal/provider/resource_user_test.go +++ b/internal/provider/resource_user_test.go @@ -12,6 +12,7 @@ import ( ) func TestAcc_ResourceUser(t *testing.T) { + SkipJAAS(t) userName := acctest.RandomWithPrefix("tfuser") userPassword := acctest.RandomWithPrefix("tf-test-user") @@ -49,6 +50,7 @@ resource "juju_user" "user" { } func TestAcc_ResourceUser_UpgradeProvider(t *testing.T) { + SkipJAAS(t) userName := acctest.RandomWithPrefix("tfuser") userPassword := acctest.RandomWithPrefix("tf-test-user")