feat(provider): Added acceptance tests (#891)

* feat(provider): Added acceptance tests

Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de>

* Remove argus custom endpoint from provider. This code was removed.

Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de>

---------

Signed-off-by: Alexander Dahmen <alexander.dahmen@inovex.de>
This commit is contained in:
Alexander Dahmen 2025-06-27 09:44:25 +02:00 committed by GitHub
parent 38fdb60e69
commit 2f06bc590d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 323 additions and 28 deletions

View file

@ -151,7 +151,6 @@ Note: AWS specific checks must be skipped as they do not work on STACKIT. For de
### Optional
- `argus_custom_endpoint` (String, Deprecated) Custom endpoint for the Argus service
- `authorization_custom_endpoint` (String) Custom endpoint for the Membership service
- `cdn_custom_endpoint` (String) Custom endpoint for the CDN service
- `credentials_path` (String) Path of JSON from where the credentials are read. Takes precedence over the env var `STACKIT_CREDENTIALS_PATH`. Default value is `~/.stackit/credentials.json`.

View file

@ -21,7 +21,6 @@ type ProviderData struct {
// Deprecated: Use DefaultRegion instead
Region string
DefaultRegion string
ArgusCustomEndpoint string
AuthorizationCustomEndpoint string
CdnCustomEndpoint string
DnsCustomEndpoint string

View file

@ -50,7 +50,6 @@ var (
// TestImageLocalFilePath is the local path to an image file used for image acceptance tests
TestImageLocalFilePath = getenv("TF_ACC_TEST_IMAGE_LOCAL_FILE_PATH", "default")
ArgusCustomEndpoint = os.Getenv("TF_ACC_ARGUS_CUSTOM_ENDPOINT")
CdnCustomEndpoint = os.Getenv("TF_ACC_CDN_CUSTOM_ENDPOINT")
DnsCustomEndpoint = os.Getenv("TF_ACC_DNS_CUSTOM_ENDPOINT")
GitCustomEndpoint = os.Getenv("TF_ACC_GIT_CUSTOM_ENDPOINT")
@ -78,22 +77,6 @@ var (
// Provider config helper functions
func ArgusProviderConfig() string {
if ArgusCustomEndpoint == "" {
return `provider "stackit" {
default_region = "eu01"
}`
}
return fmt.Sprintf(`
provider "stackit" {
argus_custom_endpoint = "%s"
}`,
ArgusCustomEndpoint,
)
}
// Provider config helper functions
func ObservabilityProviderConfig() string {
if ObservabilityCustomEndpoint == "" {
return `provider "stackit" {
@ -299,7 +282,7 @@ func RedisProviderConfig() string {
}
func ResourceManagerProviderConfig() string {
token := getTestProjectServiceAccountToken("")
token := GetTestProjectServiceAccountToken("")
if ResourceManagerCustomEndpoint == "" || AuthorizationCustomEndpoint == "" {
return fmt.Sprintf(`
provider "stackit" {
@ -458,7 +441,7 @@ func ResourceNameWithDateTime(name string) string {
return fmt.Sprintf("tf-acc-%s-%s", name, dateTimeTrimmed)
}
func getTestProjectServiceAccountToken(path string) string {
func GetTestProjectServiceAccountToken(path string) string {
var err error
token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN")
if !tokenSet || token == "" {

View file

@ -115,7 +115,6 @@ type providerModel struct {
// Deprecated: Use DefaultRegion instead
Region types.String `tfsdk:"region"`
DefaultRegion types.String `tfsdk:"default_region"`
ArgusCustomEndpoint types.String `tfsdk:"argus_custom_endpoint"`
CdnCustomEndpoint types.String `tfsdk:"cdn_custom_endpoint"`
DNSCustomEndpoint types.String `tfsdk:"dns_custom_endpoint"`
GitCustomEndpoint types.String `tfsdk:"git_custom_endpoint"`
@ -157,7 +156,6 @@ func (p *Provider) Schema(_ context.Context, _ provider.SchemaRequest, resp *pro
"service_account_email": "Service account email. It can also be set using the environment variable STACKIT_SERVICE_ACCOUNT_EMAIL. It is required if you want to use the resource manager project resource.",
"region": "Region will be used as the default location for regional services. Not all services require a region, some are global",
"default_region": "Region will be used as the default location for regional services. Not all services require a region, some are global",
"argus_custom_endpoint": "Custom endpoint for the Argus service",
"cdn_custom_endpoint": "Custom endpoint for the CDN service",
"dns_custom_endpoint": "Custom endpoint for the DNS service",
"git_custom_endpoint": "Custom endpoint for the Git service",
@ -233,11 +231,6 @@ func (p *Provider) Schema(_ context.Context, _ provider.SchemaRequest, resp *pro
stringvalidator.ConflictsWith(path.MatchRoot("region")),
},
},
"argus_custom_endpoint": schema.StringAttribute{
Optional: true,
Description: descriptions["argus_custom_endpoint"],
DeprecationMessage: "Argus service has been deprecated and integration will be removed after February 26th 2025. Please use `observability_custom_endpoint` and `observability` resources instead, which offer the exact same functionality.",
},
"cdn_custom_endpoint": schema.StringAttribute{
Optional: true,
Description: descriptions["cdn_custom_endpoint"],

View file

@ -0,0 +1,259 @@
package stackit_test
import (
_ "embed"
"fmt"
"os"
"path"
"regexp"
"runtime"
"testing"
"github.com/hashicorp/terraform-plugin-testing/config"
"github.com/hashicorp/terraform-plugin-testing/helper/acctest"
"github.com/hashicorp/terraform-plugin-testing/helper/resource"
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/testutil"
)
//go:embed testdata/provider-credentials.tf
var providerCredentialConfig string
//go:embed testdata/provider-invalid-attribute.tf
var providerInvalidAttribute string
//go:embed testdata/provider-all-attributes.tf
var providerValidAttributes string
var testConfigProviderCredentials = config.Variables{
"project_id": config.StringVariable(testutil.ProjectId),
"name": config.StringVariable(fmt.Sprintf("tf-acc-prov%s", acctest.RandStringFromCharSet(3, acctest.CharSetAlphaNum))),
}
// Helper function to obtain the home directory on different systems.
// Based on os.UserHomeDir().
func getHomeEnvVariableName() string {
env := "HOME"
switch runtime.GOOS {
case "windows":
env = "USERPROFILE"
case "plan9":
env = "home"
}
return env
}
// create temporary home and initialize the credentials file as well
func createTemporaryHome(createValidCredentialsFile bool, t *testing.T) string {
// create a temporary file
tempHome, err := os.MkdirTemp("", "tempHome")
if err != nil {
t.Fatalf("Failed to create temporary home directory: %v", err)
}
// create credentials file in temp directory
stackitFolder := path.Join(tempHome, ".stackit")
if err := os.Mkdir(stackitFolder, 0o750); err != nil {
t.Fatalf("Failed to create stackit folder: %v", err)
}
filePath := path.Join(stackitFolder, "credentials.json")
file, err := os.Create(filePath)
if err != nil {
t.Fatalf("Failed to create credentials file: %v", err)
}
defer func() {
if err := file.Close(); err != nil {
t.Fatalf("Error while closing the file: %v", err)
}
}()
// Define content, default = invalid token
token := "foo_token"
if createValidCredentialsFile {
token = testutil.GetTestProjectServiceAccountToken("")
}
content := fmt.Sprintf(`
{
"STACKIT_SERVICE_ACCOUNT_TOKEN": "%s"
}`, token)
if _, err = file.WriteString(content); err != nil {
t.Fatalf("Error writing to file: %v", err)
}
return tempHome
}
// Function to overwrite the home folder
func setTemporaryHome(tempHomePath string) {
env := getHomeEnvVariableName()
if err := os.Setenv(env, tempHomePath); err != nil {
fmt.Printf("Error setting temporary home directory %v", err)
}
}
// cleanup the temporary home and reset the environment variable
func cleanupTemporaryHome(tempHomePath string, t *testing.T) {
if err := os.RemoveAll(tempHomePath); err != nil {
t.Fatalf("Error cleaning up temporary folder: %v", err)
}
originalHomeDir, err := os.UserHomeDir()
if err != nil {
t.Fatalf("Failed to restore home directory back to normal: %v", err)
}
// revert back to original home folder
env := getHomeEnvVariableName()
if err := os.Setenv(env, originalHomeDir); err != nil {
fmt.Printf("Error resetting temporary home directory %v", err)
}
}
func getServiceAccountToken() (string, error) {
token, set := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN")
if !set || token == "" {
return "", fmt.Errorf("Token not set, please set TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN to a valid token to perform tests")
}
return token, nil
}
func TestAccEnvVarTokenValid(t *testing.T) {
// Check if acceptance tests should be run
if v := os.Getenv(resource.EnvTfAcc); v == "" {
t.Skipf(
"Acceptance tests skipped unless env '%s' set",
resource.EnvTfAcc)
return
}
token, err := getServiceAccountToken()
if err != nil {
t.Fatalf("Can't get token: %v", err)
}
t.Setenv("STACKIT_CREDENTIALS_PATH", "")
t.Setenv("STACKIT_SERVICE_ACCOUNT_TOKEN", token)
tempHomeFolder := createTemporaryHome(false, t)
defer cleanupTemporaryHome(tempHomeFolder, t)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
PreConfig: func() { setTemporaryHome(tempHomeFolder) },
ConfigVariables: testConfigProviderCredentials,
Config: providerCredentialConfig,
},
},
})
}
func TestAccEnvVarTokenInvalid(t *testing.T) {
t.Setenv("STACKIT_CREDENTIALS_PATH", "")
t.Setenv("STACKIT_SERVICE_ACCOUNT_TOKEN", "foo")
tempHomeFolder := createTemporaryHome(false, t)
defer cleanupTemporaryHome(tempHomeFolder, t)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
PreConfig: func() { setTemporaryHome(tempHomeFolder) },
ConfigVariables: testConfigProviderCredentials,
Config: providerCredentialConfig,
ExpectError: regexp.MustCompile(`undefined response type, status code 401`),
},
},
})
}
func TestAccCredentialsFileValid(t *testing.T) {
t.Setenv("STACKIT_CREDENTIALS_PATH", "")
t.Setenv("STACKIT_SERVICE_ACCOUNT_TOKEN", "")
tempHomeFolder := createTemporaryHome(true, t)
defer cleanupTemporaryHome(tempHomeFolder, t)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
PreConfig: func() { setTemporaryHome(tempHomeFolder) },
ConfigVariables: testConfigProviderCredentials,
Config: providerCredentialConfig,
},
},
})
}
func TestAccCredentialsFileInvalid(t *testing.T) {
t.Setenv("STACKIT_CREDENTIALS_PATH", "")
t.Setenv("STACKIT_SERVICE_ACCOUNT_TOKEN", "")
tempHomeFolder := createTemporaryHome(false, t)
defer cleanupTemporaryHome(tempHomeFolder, t)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{
PreConfig: func() { setTemporaryHome(tempHomeFolder) },
ConfigVariables: testConfigProviderCredentials,
Config: providerCredentialConfig,
ExpectError: regexp.MustCompile(`Jwt is not in(\r\n|\r|\n)the form of Header.Payload.Signature`),
},
},
})
}
func TestAccProviderConfigureValidValues(t *testing.T) {
// Check if acceptance tests should be run
if v := os.Getenv(resource.EnvTfAcc); v == "" {
t.Skipf(
"Acceptance tests skipped unless env '%s' set",
resource.EnvTfAcc)
return
}
// use service account token for these tests
token, err := getServiceAccountToken()
if err != nil {
t.Fatalf("Can't get token: %v", err)
}
t.Setenv("STACKIT_CREDENTIALS_PATH", "")
t.Setenv("STACKIT_SERVICE_ACCOUNT_TOKEN", token)
tempHomeFolder := createTemporaryHome(true, t)
defer cleanupTemporaryHome(tempHomeFolder, t)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{ // valid provider attributes
ConfigVariables: testConfigProviderCredentials,
Config: providerValidAttributes,
},
},
})
}
func TestAccProviderConfigureAnInvalidValue(t *testing.T) {
// Check if acceptance tests should be run
if v := os.Getenv(resource.EnvTfAcc); v == "" {
t.Skipf(
"Acceptance tests skipped unless env '%s' set",
resource.EnvTfAcc)
return
}
// use service account token for these tests
token, err := getServiceAccountToken()
if err != nil {
t.Fatalf("Can't get token: %v", err)
}
t.Setenv("STACKIT_CREDENTIALS_PATH", "")
t.Setenv("STACKIT_SERVICE_ACCOUNT_TOKEN", token)
tempHomeFolder := createTemporaryHome(true, t)
defer cleanupTemporaryHome(tempHomeFolder, t)
resource.Test(t, resource.TestCase{
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
Steps: []resource.TestStep{
{ // invalid test attribute should throw an error
ConfigVariables: testConfigProviderCredentials,
Config: providerInvalidAttribute,
ExpectError: regexp.MustCompile(`An argument named "test" is not expected here\.`),
},
},
})
}

View file

@ -0,0 +1,41 @@
variable "project_id" {}
variable "name" {}
provider "stackit" {
default_region = "eu01"
credentials_path = "~/.stackit/credentials.json"
service_account_token = ""
service_account_key_path = ""
service_account_key = ""
private_key_path = ""
private_key = ""
service_account_email = "abc@abc.de"
cdn_custom_endpoint = "https://cdn.api.eu01.stackit.cloud"
dns_custom_endpoint = "https://dns.api.stackit.cloud"
git_custom_endpoint = "https://git.api.stackit.cloud"
iaas_custom_endpoint = "https://iaas.api.stackit.cloud"
mongodbflex_custom_endpoint = "https://mongodbflex.api.stackit.cloud"
modelserving_custom_endpoint = "https://modelserving.api.stackit.cloud"
loadbalancer_custom_endpoint = "https://load-balancer.api.stackit.cloud"
mariadb_custom_endpoint = "https://mariadb.api.stackit.cloud"
authorization_custom_endpoint = "https://authorization.api.stackit.cloud"
objectstorage_custom_endpoint = "https://objectstorage.api.stackit.cloud"
observability_custom_endpoint = "https://observability.api.stackit.cloud"
opensearch_custom_endpoint = "https://opensearch.api.stackit.cloud"
postgresflex_custom_endpoint = "https://postgresflex.api.stackit.cloud"
redis_custom_endpoint = "https://redis.api.stackit.cloud"
server_backup_custom_endpoint = "https://server-backup.api.stackit.cloud"
server_update_custom_endpoint = "https://server-update.api.stackit.cloud"
service_account_custom_endpoint = "https://service-account.api.stackit.cloud"
resourcemanager_custom_endpoint = "https://resourcemanager.api.stackit.cloud"
sqlserverflex_custom_endpoint = "https://sqlserverflex.api.stackit.cloud"
ske_custom_endpoint = "https://ske.api.stackit.cloud"
service_enablement_custom_endpoint = "https://service-enablement.api.stackit.cloud"
token_custom_endpoint = "https://token.api.stackit.cloud"
enable_beta_resources = "true"
}
resource "stackit_network" "network" {
name = var.name
project_id = var.project_id
}

View file

@ -0,0 +1,10 @@
variable "project_id" {}
variable "name" {}
provider "stackit" {
}
resource "stackit_network" "network" {
name = var.name
project_id = var.project_id
}

View file

@ -0,0 +1,11 @@
variable "project_id" {}
variable "name" {}
provider "stackit" {
test = "test"
}
resource "stackit_network" "network" {
name = var.name
project_id = var.project_id
}