Skip to content

Commit

Permalink
add test case for vendor
Browse files Browse the repository at this point in the history
  • Loading branch information
haitham911 committed Jan 20, 2025
1 parent dd3ba4b commit 72a3672
Show file tree
Hide file tree
Showing 11 changed files with 256 additions and 5 deletions.
40 changes: 40 additions & 0 deletions examples/tests/test-vendor/atmos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
base_path: "./"

components:
terraform:
base_path: "components/terraform"
apply_auto_approve: false
deploy_run_init: true
init_run_reconfigure: true
auto_generate_backend_file: false

stacks:
base_path: "stacks"
included_paths:
- "deploy/**/*"
excluded_paths:
- "**/_defaults.yaml"
name_pattern: "{stage}"

vendor:
# Single file
base_path: "./vendor.yaml"

# Directory with multiple files
#base_path: "./vendor"

# Absolute path
#base_path: "vendor.d/vendor1.yaml"

logs:
file: "/dev/stderr"
level: Info

# Custom CLI commands

# No arguments or flags are required
commands:
- name: "test"
description: "Run all tests"
steps:
- atmos vendor pull --everything
13 changes: 13 additions & 0 deletions examples/tests/test-vendor/test-components/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Example Terraform IPinfo Component

This Terraform module retrieves data from the IPinfo API for a specified IP address. If no IP address is specified, it retrieves data for the requester's IP address.

## Usage

### Inputs

- `ip_address` (optional): The IP address to retrieve information for. If not specified, the requester's IP address will be used. The default value is an empty string.

### Outputs

- `metadata`: The data retrieved from IPinfo for the specified IP address, in JSON format.
7 changes: 7 additions & 0 deletions examples/tests/test-vendor/test-components/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
data "http" "ipinfo" {
url = var.ip_address != "" ? "https://ipinfo.io/${var.ip_address}" : "https://ipinfo.io"

request_headers = {
Accept = "application/json"
}
}
4 changes: 4 additions & 0 deletions examples/tests/test-vendor/test-components/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output "metadata" {
description = "The data retrieved from IPinfo for the specified IP address"
value = jsondecode(data.http.ipinfo.response_body)
}
1 change: 1 addition & 0 deletions examples/tests/test-vendor/test-components/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
provider "http" {}
5 changes: 5 additions & 0 deletions examples/tests/test-vendor/test-components/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "ip_address" {
description = "The IP address to retrieve information for (optional)"
type = string
default = ""
}
5 changes: 5 additions & 0 deletions examples/tests/test-vendor/test-components/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
terraform {
required_version = ">= 1.0.0"

required_providers {}
}
43 changes: 43 additions & 0 deletions examples/tests/test-vendor/vendor.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
apiVersion: atmos/v1
kind: AtmosVendorConfig
metadata:
name: demo-vendoring
description: Atmos vendoring manifest for Atmos demo component library
spec:
# Import other vendor manifests, if necessary
imports: []

sources:
- component: "github/stargazers"
source: "github.com/cloudposse/atmos.git//examples/demo-library/{{ .Component }}?ref={{.Version}}"
version: "main"
targets:
- "components/terraform/{{ .Component }}/{{.Version}}"
included_paths:
- "**/*.tf"
- "**/*.tfvars"
- "**/*.md"
tags:
- demo
- github

- component: "test-components"
source: "file:///./test-components"
version: "main"
targets:
- "components/terraform/{{ .Component }}/{{.Version}}"
tags:
- demo

- component: "weather"
source: "git::https://github.com/cloudposse/atmos.git//examples/demo-library/{{ .Component }}?ref={{.Version}}"
version: "main"
targets:
- "components/terraform/{{ .Component }}/{{.Version}}"
tags:
- demo
- component: "my-vpc1"
source: "oci://public.ecr.aws/cloudposse/components/terraform/stable/aws/vpc:{{.Version}}"
version: "latest"
targets:
- "components/terraform/infra/my-vpc1"
9 changes: 9 additions & 0 deletions internal/exec/vendor_component_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"context"
"errors"
"fmt"
"net/url"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -244,6 +245,14 @@ func ExecuteComponentVendorInternal(
sourceIsLocalFile = true
}
}
u, err := url.Parse(uri)
if err == nil && u.Scheme != "" {
if u.Scheme == "file" {
trimmedPath := strings.TrimPrefix(filepath.ToSlash(u.Path), "/")
uri = filepath.Clean(trimmedPath)
useLocalFileSystem = true
}
}
}
var pType pkgType
if useOciScheme {
Expand Down
99 changes: 94 additions & 5 deletions tests/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import (
"errors"
"flag"
"fmt"
"io"
"log"
"os"
"os/exec"
"path/filepath" // For resolving absolute paths
Expand Down Expand Up @@ -84,7 +86,13 @@ func (m *MatchPattern) UnmarshalYAML(value *yaml.Node) error {
}

func loadTestSuite(filePath string) (*TestSuite, error) {
data, err := os.ReadFile(filePath)
// Open the file
f, err := os.Open(filePath)
if err != nil {
log.Fatalf("Failed to open file: %v", err)
}
defer f.Close()
data, err := io.ReadAll(f)
if err != nil {
return nil, err
}
Expand Down Expand Up @@ -449,6 +457,76 @@ func TestCLICommands(t *testing.T) {
// Run with `t.Run` for non-TTY tests
t.Run(tc.Name, func(t *testing.T) {
runCLICommandTest(t, tc)
defer func() {
// Change back to the original working directory after the test
if err := os.Chdir(startingDir); err != nil {
t.Fatalf("Failed to change back to the starting directory: %v", err)
}
}()

// Change to the specified working directory
if tc.Workdir != "" {
err := os.Chdir(tc.Workdir)
if err != nil {
t.Fatalf("Failed to change directory to %q: %v", tc.Workdir, err)
}
}

// Check if the binary exists
binaryPath, err := exec.LookPath(tc.Command)
if err != nil {
t.Fatalf("Binary not found: %s. Current PATH: %s", tc.Command, pathManager.GetPath())
}

// Prepare the command
cmd := exec.Command(binaryPath, tc.Args...)

// Set environment variables
envVars := os.Environ()
for key, value := range tc.Env {
envVars = append(envVars, fmt.Sprintf("%s=%s", key, value))
}
cmd.Env = envVars

var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr

// Run the command
err = cmd.Run()

// Validate exit code
exitCode := 0
if err != nil {
if exitErr, ok := err.(*exec.ExitError); ok {
exitCode = exitErr.ExitCode()
}
}
if exitCode != tc.Expect.ExitCode {
t.Errorf("Description: %s", tc.Description)
t.Errorf("Reason: Expected exit code %d, got %d", tc.Expect.ExitCode, exitCode)
t.Errorf("error: %v", cmd.Stderr)
}

// Validate stdout
if !verifyOutput(t, "stdout", stdout.String(), tc.Expect.Stdout) {
t.Errorf("Description: %s", tc.Description)
}

// Validate stderr
if !verifyOutput(t, "stderr", stderr.String(), tc.Expect.Stderr) {
t.Errorf("Description: %s", tc.Description)
}

// Validate file existence
if !verifyFileExists(t, tc.Expect.FileExists) {
t.Errorf("Description: %s", tc.Description)
}

// Validate file contents
if !verifyFileContains(t, tc.Expect.FileContains) {
t.Errorf("Description: %s", tc.Description)
}
})
}
}
Expand Down Expand Up @@ -512,12 +590,17 @@ func verifyOutput(t *testing.T, outputType, output string, patterns []MatchPatte
}
return success
}

func verifyFileExists(t *testing.T, files []string) bool {
success := true
for _, file := range files {
if _, err := os.Stat(file); errors.Is(err, os.ErrNotExist) {
t.Errorf("Reason: Expected file does not exist: %q", file)
fileAbs, err := filepath.Abs(file)
if err != nil {
log.Println(err)
return false
}

if _, err := os.Stat(fileAbs); errors.Is(err, os.ErrNotExist) {
t.Errorf("Reason: Expected file does not exist: %q", fileAbs)
success = false
}
}
Expand All @@ -527,7 +610,13 @@ func verifyFileExists(t *testing.T, files []string) bool {
func verifyFileContains(t *testing.T, filePatterns map[string][]MatchPattern) bool {
success := true
for file, patterns := range filePatterns {
content, err := os.ReadFile(file)
// Open the file
f, err := os.Open(file)
if err != nil {
log.Fatalf("Failed to open file: %v", err)
}
defer f.Close()
content, err := io.ReadAll(f)
if err != nil {
t.Errorf("Reason: Failed to read file %q: %v", file, err)
success = false
Expand Down
35 changes: 35 additions & 0 deletions tests/test-cases/demo-stacks.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -130,3 +130,38 @@ tests:
stderr:
- "^$"
exit_code: 0
- name: atmos vendor pull
enabled: true
description: "Ensure atmos vendor pull command executes without errors and files are present."
workdir: "../examples/tests/test-vendor/"
command: "atmos"
args:
- "vendor"
- "pull"
expect:
file_exists: [
"./components/terraform/github/stargazers/main/main.tf",
"./components/terraform/github/stargazers/main/outputs.tf",
"./components/terraform/github/stargazers/main/providers.tf",
"./components/terraform/github/stargazers/main/variables.tf",
"./components/terraform/github/stargazers/main/versions.tf",

"./components/terraform/infra/my-vpc1/main.tf",
"./components/terraform/infra/my-vpc1/outputs.tf",
"./components/terraform/infra/my-vpc1/providers.tf",
"./components/terraform/infra/my-vpc1/variables.tf",
"./components/terraform/infra/my-vpc1/versions.tf",

"./components/terraform/test-components/main/main.tf",
"./components/terraform/test-components/main/outputs.tf",
"./components/terraform/test-components/main/providers.tf",
"./components/terraform/test-components/main/variables.tf",
"./components/terraform/test-components/main/versions.tf",

"./components/terraform/weather/main/main.tf",
"./components/terraform/weather/main/outputs.tf",
"./components/terraform/weather/main/providers.tf",
"./components/terraform/weather/main/variables.tf",
"./components/terraform/weather/main/versions.tf",
]
exit_code: 0

0 comments on commit 72a3672

Please sign in to comment.