terraform-provider-stackitp.../internal/testutils/testutils.go

218 lines
7.4 KiB
Go

package testutils
import (
"fmt"
"log"
"os"
"os/exec"
"path/filepath"
"strings"
"time"
"github.com/hashicorp/terraform-plugin-framework/providerserver"
"github.com/hashicorp/terraform-plugin-go/tfprotov6"
"github.com/hashicorp/terraform-plugin-testing/config"
"github.com/hashicorp/terraform-plugin-testing/echoprovider"
"github.com/joho/godotenv"
"tf-provider.git.onstackit.cloud/stackit-dev-tools/terraform-provider-stackitprivatepreview/stackit"
)
const (
// Default location of credentials JSON
// credentialsFilePath = ".stackit/credentials.json" //nolint:gosec // linter false positive
serviceAccountFilePath = ".stackit/service_account.json"
)
var (
// TestAccProtoV6ProviderFactories is used to instantiate a provider during
// acceptance testing. The factory function will be invoked for every Terraform
// CLI command executed to create a provider server to which the CLI can
// reattach.
TestAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
"stackitprivatepreview": providerserver.NewProtocol6WithError(stackit.New("test-version")()),
}
// TestEphemeralAccProtoV6ProviderFactories is used to instantiate a provider during
// acceptance testing. The factory function will be invoked for every Terraform
// CLI command executed to create a provider server to which the CLI can
// reattach.
//
// See the Terraform acceptance test documentation on ephemeral resources for more information:
// https://developer.hashicorp.com/terraform/plugin/testing/acceptance-tests/ephemeral-resources
TestEphemeralAccProtoV6ProviderFactories = map[string]func() (tfprotov6.ProviderServer, error){
"stackitprivatepreview": providerserver.NewProtocol6WithError(stackit.New("test-version")()),
"echo": echoprovider.NewProviderServer(),
}
// E2ETestsEnabled checks if end-to-end tests should be run.
// It is enabled when the TF_ACC environment variable is set to "1".
E2ETestsEnabled = os.Getenv("TF_ACC") == "1"
// OrganizationId is the id of organization used for tests
OrganizationId = os.Getenv("TF_ACC_ORGANIZATION_ID")
// ProjectId is the id of project used for tests
ProjectId = os.Getenv("TF_ACC_PROJECT_ID")
Region = os.Getenv("TF_ACC_REGION")
// ServiceAccountFile is the json file of the service account
ServiceAccountFile = os.Getenv("TF_ACC_SERVICE_ACCOUNT_FILE")
// ServerId is the id of a server used for some tests
ServerId = getenv("TF_ACC_SERVER_ID", "")
// TestProjectParentContainerID is the container id of the parent resource under which projects are created as part of the resource-manager acceptance tests
TestProjectParentContainerID = os.Getenv("TF_ACC_TEST_PROJECT_PARENT_CONTAINER_ID")
// TestProjectParentUUID is the uuid of the parent resource under which projects are created as part of the resource-manager acceptance tests
TestProjectParentUUID = os.Getenv("TF_ACC_TEST_PROJECT_PARENT_UUID")
// TestProjectServiceAccountEmail is the e-mail of a service account with admin permissions on the organization under which projects are created as part of the resource-manager acceptance tests
TestProjectServiceAccountEmail = os.Getenv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_EMAIL")
// TestProjectUserEmail is the e-mail of a user for the project created as part of the resource-manager acceptance tests
// Default email: acc-test@sa.stackit.cloud
TestProjectUserEmail = getenv("TF_ACC_TEST_PROJECT_USER_EMAIL", "acc-test@sa.stackit.cloud")
// TestImageLocalFilePath is the local path to an image file used for image acceptance tests
TestImageLocalFilePath = getenv("TF_ACC_TEST_IMAGE_LOCAL_FILE_PATH", "default")
)
func Setup() {
root, err := getRoot()
if err != nil {
log.Fatalln(err)
}
err = godotenv.Load(fmt.Sprintf("%s/.env", *root))
if err != nil {
log.Println("could not find .env file - not loading .env")
return
}
log.Println("loaded .env file", "path", *root)
}
func getRoot() (*string, error) {
cmd := exec.Command("git", "rev-parse", "--show-toplevel")
out, err := cmd.Output()
if err != nil {
return nil, err
}
lines := strings.Split(string(out), "\n")
return &lines[0], nil
}
func ResourceNameWithDateTime(name string) string {
dateTime := time.Now().Format(time.RFC3339)
// Remove timezone to have a smaller datetime
dateTimeTrimmed, _, _ := strings.Cut(dateTime, "+")
return fmt.Sprintf("tf-acc-%s-%s", name, dateTimeTrimmed)
}
func GetTestProjectServiceAccountJson(path string) string {
var err error
token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_JSON")
if !tokenSet || token == "" {
token, err = readTestServiceAccountJsonFromFile(path)
if err != nil {
return ""
}
}
return token
}
// func GetTestProjectServiceAccountToken(path string) string {
// var err error
// token, tokenSet := os.LookupEnv("TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN")
// if !tokenSet || token == "" {
// token, err = readTestTokenFromCredentialsFile(path)
// if err != nil {
// return ""
// }
// }
// return token
//}
//
// func readTestTokenFromCredentialsFile(path string) (string, error) {
// if path == "" {
// customPath, customPathSet := os.LookupEnv("STACKIT_CREDENTIALS_PATH")
// if !customPathSet || customPath == "" {
// path = credentialsFilePath
// home, err := os.UserHomeDir()
// if err != nil {
// return "", fmt.Errorf("getting home directory: %w", err)
// }
// path = filepath.Join(home, path)
// } else {
// path = customPath
// }
// }
//
// credentialsRaw, err := os.ReadFile(path)
// if err != nil {
// return "", fmt.Errorf("opening file: %w", err)
// }
//
// var credentials struct {
// TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN string `json:"TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN"`
// }
// err = json.Unmarshal(credentialsRaw, &credentials)
// if err != nil {
// return "", fmt.Errorf("unmarshalling credentials: %w", err)
// }
// return credentials.TF_ACC_TEST_PROJECT_SERVICE_ACCOUNT_TOKEN, nil
//}
func readTestServiceAccountJsonFromFile(path string) (string, error) {
if path == "" {
customPath, customPathSet := os.LookupEnv("STACKIT_SERVICE_ACCOUNT_PATH")
if !customPathSet || customPath == "" {
path = serviceAccountFilePath
home, err := os.UserHomeDir()
if err != nil {
return "", fmt.Errorf("getting home directory: %w", err)
}
path = filepath.Join(home, path)
} else {
path = customPath
}
}
credentialsRaw, err := os.ReadFile(path)
if err != nil {
return "", fmt.Errorf("opening file: %w", err)
}
return string(credentialsRaw), nil
}
func getenv(key, defaultValue string) string {
val := os.Getenv(key)
if val == "" {
return defaultValue
}
return val
}
// CreateDefaultLocalFile is a helper for local_file_path. No real data is created
func CreateDefaultLocalFile() os.File {
// Define the file name and size
fileName := "test-512k.img"
size := 512 * 1024 // 512 KB
// Create the file
file, err := os.Create(fileName)
if err != nil {
panic(err)
}
// Seek to the desired position (512 KB)
_, err = file.Seek(int64(size), 0)
if err != nil {
panic(err)
}
return *file
}
func ConvertConfigVariable(variable config.Variable) string {
tmpByteArray, _ := variable.MarshalJSON()
// In case the variable is a string, the quotes should be removed
if tmpByteArray[0] == '"' && tmpByteArray[len(tmpByteArray)-1] == '"' {
result := string(tmpByteArray[1 : len(tmpByteArray)-1])
// Replace escaped quotes which where added MarshalJSON
rawString := strings.ReplaceAll(result, `\"`, `"`)
return rawString
}
return string(tmpByteArray)
}