Skip to content

Conversation

@goruha
Copy link
Contributor

@goruha goruha commented Mar 25, 2025

What

  • Add basic component test
  • Add disabled component test
  • Test component drifting
  • Add any additional use case tests

Why

  • Test basic component features
  • Verify that the component does not create any resources when input enabled: false set
  • Verify that the component does not drift on a second run with the same inputs
  • Add test for any additional than basic use cases for the component

References

Summary by CodeRabbit

  • New Features

    • Introduced additional sample configurations to simplify cloud resource deployment.
    • Added a new CLI application configuration file for enhanced flexibility in managing settings.
    • Included new YAML configuration files for various components, including VPC, EKS cluster, and DNS management.
    • Added a new local variable to aggregate zone names for enhanced domain filtering in DNS configurations.
  • Chores

    • Upgraded module versions for improved stability and reliability.
    • Created a .gitignore file to manage unnecessary files in version control.
  • Tests

    • Added a comprehensive test suite to verify deployments, including multiple test functions.
    • Enhanced ignore rules and dependency management to support a consistent testing environment.
  • Revert

    • Removed an unused test script that had no additional logic or functionality.

@goruha goruha requested review from a team as code owners March 25, 2025 09:05
@goruha goruha linked an issue Mar 25, 2025 that may be closed by this pull request
4 tasks
@coderabbitai
Copy link

coderabbitai bot commented Mar 25, 2025

Walkthrough

This pull request modifies the Helm provider configuration by removing an intermediate local variable and inlining a computed role ARN. It updates the version numbers for several remote state modules and introduces a suite of test assets, including new test configurations and YAML files for managing various Terraform components. Additionally, a Go testing module is created, and an obsolete test script is removed.

Changes

File(s) Change Summary
src/provider-helm.tf Removed the intermediate kube_exec_auth_role_arn local variable and inlined the coalesce function within the exec_role assignment.
src/remote-state.tf Updated module versions for "eks", "dns_gbl_delegated", "dns_gbl_primary", and "additional_dns_components" from "1.5.0" to "1.8.0".
test/(.gitignore, component_test.go, fixtures/**/*.yaml, go.mod, run.sh) Added a new test suite for external DNS validation, introduced multiple YAML configuration files for Atmos, Terraform components, catalog, and organizational defaults, established vendor configurations, and created a new Go module with updated dependencies; removed the obsolete run.sh script.

Sequence Diagram(s)

sequenceDiagram
    participant Runner as TestRunSuite
    participant Suite as ComponentSuite
    participant Client as Dynamic K8s Client
    participant DNS as DNS Service

    Runner->>Suite: Invoke SetupSuite()
    Suite->>Client: Create DNSEndpoint resource
    Client-->>Suite: Return resource metadata
    Suite->>DNS: Verify DNS record in Route 53
    DNS-->>Suite: Respond with status
    Suite->>Runner: Report test results
Loading

Poem

I’m a bunny with a codey rhyme,
Hoppin’ through files one line at a time,
Inline magic now makes it lean,
Modules updated and tests so keen,
Configs and YAMLs fill the burrow tight,
A joyful hop—our code's just right!
🐇✨


🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai plan to trigger planning for file edits and PR creation.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@goruha
Copy link
Contributor Author

goruha commented Mar 25, 2025

/terratest

@mergify
Copy link

mergify bot commented Mar 25, 2025

Merge Protections

Your pull request matches the following merge protections and will not be merged until they are valid.

🟢 Require terratest

Wonderful, this rule succeeded.

This rule require terratest status

  • check-success = test/terratest

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (15)
test/fixtures/stacks/catalog/vpc.yaml (1)

1-20: VPC Configuration: Structure and Commentary

The VPC configuration is comprehensive, defining all the necessary variables. One minor suggestion: the comment on line 13, “# Private subnets do not need internet access”, could be repositioned or further clarified to better indicate its association with the subsequent NAT gateway/instance settings.

test/fixtures/stacks/catalog/eks-alb-controller.yaml (1)

1-37: EKS ALB Controller Configuration: Best Practices

This YAML configuration is thorough and well-documented. A few points to note:

  • Verify that the chart version ("1.7.1") remains current with your deployment practices.
  • The inline comments provide useful context (e.g., for updating IAM policies and handling helm manifest experiments). Ensure that these remain updated as the component evolves.
  • The commented-out block for chart_values is a helpful reference; maintain its clarity for future maintainers.
test/fixtures/vendor.yaml (1)

1-79: Vendor Configuration File Looks Correct

The vendor.yaml file is well structured and clearly defines the Atmos vendor manifest with a list of sources and associated configuration parameters. For consistency with best practices, consider ensuring that the file ends with a trailing newline if one is not already present.

test/fixtures/stacks/catalog/usecase/disabled.yaml (1)

1-37: YAML File: Trailing Newline Missing

The configuration for the disabled use case is comprehensive and clear. However, YAML linting indicates that there is no newline at the end of the file. Please add a newline character at the end to conform to YAML best practices.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 37-37: no new line character at the end of file

(new-line-at-end-of-file)

test/fixtures/stacks/catalog/account-map.yaml (1)

1-47: New Account-Map Configuration is Well Defined

This configuration file accurately defines the Terraform account map, including the static remote state backend. As the commented-out legacy backend configuration is retained for reference, consider removing or archiving it elsewhere if it no longer serves an active purpose.

test/fixtures/stacks/catalog/eks-cluster.yaml (1)

1-94: EKS Cluster Template Configuration is Detailed and Clear
The configuration covers key aspects of the EKS cluster setup, including node group properties, addons configuration, and access settings. Note that YAMLlint reports a missing new line at the end of the file; please add a newline at the end to adhere to best practices.

🧰 Tools
🪛 YAMLlint (1.35.1)

[error] 94-94: no new line character at the end of file

(new-line-at-end-of-file)

test/go.mod (1)

19-186: Comprehensive Dependency Management
The comprehensive list of direct and indirect dependencies indicates careful dependency management, which is critical for the new test suite. It is advisable to periodically review and update these dependencies to mitigate potential vulnerabilities.

test/component_test.go (6)

70-70: Fix typo in variable name

There's a typo in the variable name 'clusrerId' which should be 'clusterId'.

-	clusrerId := atmos.Output(s.T(), clusterOptions, "eks_cluster_id")
+	clusterId := atmos.Output(s.T(), clusterOptions, "eks_cluster_id")

78-80: Avoid using panic in test code

Using panic in test code is usually not recommended as it abruptly terminates all tests. Consider using assert.NoError or require.NoError pattern instead, which is consistent with the error handling used elsewhere in the file.

-	if err != nil {
-		panic(fmt.Errorf("failed to create dynamic client: %v", err))
-	}
+	assert.NoError(s.T(), err, "failed to create dynamic client")
+	assert.NotNil(s.T(), dynamicClient)

124-124: Remove commented line or improve comment format

This line has an unnecessary double slash at the beginning, which appears to be a leftover from editing.

-	// // Wait for the DnsEndpoint to be updated with the LoadBalancer metadata
+	// Wait for the DnsEndpoint to be updated with the LoadBalancer metadata

173-180: Add context timeout for select statement

The select statement uses a 1-minute timeout which could be longer than needed for test execution. Consider adding a context with timeout and cancellation to make it more controllable and consistent with best practices for Go concurrency.

+	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
+	defer cancel()

	select {
		case <-stopChannel:
			msg := "Dns endpoint created"
			fmt.Println(msg)
-		case <-time.After(1 * time.Minute):
+		case <-ctx.Done():
			msg := "Dns endpoint creation timed out"
			assert.Fail(s.T(), msg)
	}

30-186: Improve error logging in TestBasic

The TestBasic function uses a mix of error handling approaches - sometimes using fmt.Printf for errors, sometimes using assert.NoError. Consider using a consistent approach for error logging and handling throughout the test to improve readability and maintainability.

For example, replace print statements with test logging:

-				fmt.Printf("Error getting status: %v\n", err)
+				s.T().Logf("Error getting status: %v", err)

And similarly for other fmt.Printf statements.

🧰 Tools
🪛 golangci-lint (1.64.8)

132-132: Error return value of informer.AddEventHandler is not checked

(errcheck)


30-186: Add meaningful test assertions

While the test does verify the DNS record creation, it would be valuable to add more specific assertions to verify the exact state and configuration of the created resources. This would make the test more robust and help catch regressions.

Consider adding assertions to verify:

  1. The correct values in the DNSEndpoint resource after creation
  2. The specific Route53 record properties beyond just the name
  3. The absence of errors in the component's status or logs
🧰 Tools
🪛 golangci-lint (1.64.8)

132-132: Error return value of informer.AddEventHandler is not checked

(errcheck)

test/fixtures/atmos.yaml (2)

26-26: Consider setting apply_auto_approve to false for safety

Setting apply_auto_approve: true means Terraform will not prompt for confirmation before applying changes. While this makes sense for automated tests, it could be risky if this configuration file is reused in other contexts or environments.

Consider adding a comment indicating this setting is specifically for automated testing purposes, or conditionally setting it based on environment:

    # Can also be set using `ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE` ENV var
-    apply_auto_approve: true
+    # Set to true for automated testing, but should be false in production environments
+    apply_auto_approve: true

58-60: Consider setting a more verbose log level for testing

For testing purposes, it might be beneficial to set a more verbose log level like Debug instead of Info to capture more detailed information about test execution and any potential issues.

logs:
  file: "/dev/stdout"
  # Supported log levels: Trace, Debug, Info, Warning, Off
-  level: Info
+  level: Debug
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e64c0ea and 6100585.

⛔ Files ignored due to path filters (1)
  • test/go.sum is excluded by !**/*.sum
📒 Files selected for processing (18)
  • src/provider-helm.tf (1 hunks)
  • src/remote-state.tf (4 hunks)
  • test/.gitignore (1 hunks)
  • test/component_test.go (1 hunks)
  • test/fixtures/atmos.yaml (1 hunks)
  • test/fixtures/stacks/catalog/account-map.yaml (1 hunks)
  • test/fixtures/stacks/catalog/dns-delegated.yaml (1 hunks)
  • test/fixtures/stacks/catalog/dns-primary.yaml (1 hunks)
  • test/fixtures/stacks/catalog/eks-alb-controller.yaml (1 hunks)
  • test/fixtures/stacks/catalog/eks-cluster.yaml (1 hunks)
  • test/fixtures/stacks/catalog/usecase/basic.yaml (1 hunks)
  • test/fixtures/stacks/catalog/usecase/disabled.yaml (1 hunks)
  • test/fixtures/stacks/catalog/vpc.yaml (1 hunks)
  • test/fixtures/stacks/orgs/default/test/_defaults.yaml (1 hunks)
  • test/fixtures/stacks/orgs/default/test/tests.yaml (1 hunks)
  • test/fixtures/vendor.yaml (1 hunks)
  • test/go.mod (1 hunks)
  • test/run.sh (0 hunks)
💤 Files with no reviewable changes (1)
  • test/run.sh
🧰 Additional context used
🪛 YAMLlint (1.35.1)
test/fixtures/stacks/catalog/usecase/disabled.yaml

[error] 37-37: no new line character at the end of file

(new-line-at-end-of-file)

test/fixtures/stacks/catalog/eks-cluster.yaml

[error] 94-94: no new line character at the end of file

(new-line-at-end-of-file)

🪛 golangci-lint (1.64.8)
test/component_test.go

132-132: Error return value of informer.AddEventHandler is not checked

(errcheck)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🔇 Additional comments (14)
test/.gitignore (1)

1-6: .gitignore File: Appropriate Ignore Patterns

The ignore patterns cover state directories, cache files, and test artifacts effectively. Ensure these patterns match your project's directory structure and future test outputs.

test/fixtures/stacks/catalog/dns-primary.yaml (1)

1-10: DNS-Primary Configuration: Structure and Intent

The configuration for the dns-primary component is clearly structured. The empty list for record_config appears intentional; just verify that downstream processes or tests handle an empty configuration as expected.

test/fixtures/stacks/catalog/dns-delegated.yaml (1)

1-11: DNS-Delegated Configuration: Clarity and Validity

The YAML layout is clean and adheres to expected patterns. Confirm that setting request_acm_certificate to true is aligned with your deployment requirements and testing scenarios.

test/fixtures/stacks/orgs/default/test/tests.yaml (1)

1-10: Test Imports File Configured Properly

The import list covers all necessary configuration modules—including the basic and disabled use cases—and sets a modular foundation for the test framework. Please make sure that all referenced import files (e.g., catalog/usecase/basic and catalog/usecase/disabled) exist and reflect the intended configurations.

src/remote-state.tf (4)

2-3: Module Version Update for eks Module

The version update to "1.8.0" for the eks module helps align with the latest configurations. Verify that this upgrade does not introduce breaking changes in related functionality.


10-12: Module Version Update for dns_gbl_delegated Module

The dns_gbl_delegated module now uses version "1.8.0". Confirm that associated DNS configuration and backend interactions continue to behave as expected with this update.


24-26: Module Version Update for dns_gbl_primary Module

Updating the dns_gbl_primary module version to "1.8.0" is consistent with the overall enhancements. Please verify that any potential changes in module defaults have been accounted for in your configurations.


40-43: Module Version Update for additional_dns_components Module

The dynamic block for additional_dns_components now references version "1.8.0". Ensure that this change is tested, particularly around any dynamic role lookups or environment-specific behaviors.

test/fixtures/stacks/catalog/usecase/basic.yaml (1)

1-44: Basic Use-Case YAML Configuration Looks Solid
The new YAML file clearly defines the external-dns deployment for an enabled scenario, including resource specifications, chart details, and custom chart_values. Verify that the chosen values (e.g., resource limits, chart version) meet the desired deployments across environments.

src/provider-helm.tf (1)

136-138: Inline Role ARN Assignment Update
The shift from an intermediary local variable to an inline use of coalesce(var.kube_exec_auth_role_arn, module.iam_roles.terraform_role_arn) in the exec_role assignment improves clarity and reduces redundancy. Ensure that both var.kube_exec_auth_role_arn and module.iam_roles.terraform_role_arn reliably provide the expected role ARN in all runtime scenarios.

test/fixtures/stacks/orgs/default/test/_defaults.yaml (1)

1-67: New Organizational Defaults YAML Configuration is Comprehensive
This file sets robust defaults for the Terraform backend and account mapping. The use of environment variable fallbacks for state paths and account details is well thought out. Make sure that the getenv expressions return the correct values in different environments.

test/go.mod (2)

1-8: Go Module Declaration and Versioning
The go.mod file is well defined, with an appropriate module declaration, Go version, and toolchain version. The direct dependency declarations (e.g., for github.com/cloudposse/test-helpers and github.com/gruntwork-io/terratest) are clear and aligned with the new testing enhancements.


17-18: Dependency Replacement Directive
The replace directive for github.com/rebuy-de/aws-nuke/v2/mocks to use github.com/ekristen/aws-nuke/v3/ v3.29.0 is correctly applied. Please double-check that the replacement version is fully compatible with all dependent packages.

test/fixtures/atmos.yaml (1)

1-78: LGTM: Well-documented configuration file

The Atmos configuration file is well-structured and thoroughly documented with comments explaining the purpose of each setting and how to override them using environment variables or command-line arguments.

@goruha
Copy link
Contributor Author

goruha commented Mar 25, 2025

/terratest

@mergify mergify bot added the needs-test Needs testing label Mar 25, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (6)
test/component_test.go (6)

34-240: Consider refactoring the TestBasic method for better readability.

The TestBasic method is quite long (200+ lines), making it harder to understand and maintain. Consider breaking it down into smaller helper methods with clear responsibilities:

  1. Setup - create namespace and inputs
  2. Deploy component and verify metadata
  3. Create DNS endpoint and configure informer
  4. Wait for DNS endpoint to be ready
  5. Verify Route53 record
  6. Cleanup resources

For example, you could extract the DNS endpoint creation and informer setup into a helper method:

func (s *ComponentSuite) createDNSEndpoint(dynamicClient dynamic.Interface, namespace, dnsEndpointName, dnsRecordHostName string) error {
    // Define the GroupVersionResource for the DNSEndpoint CRD
    dnsEndpointGVR := schema.GroupVersionResource{
        Group:    "externaldns.k8s.io",
        Version:  "v1alpha1",
        Resource: "dnsendpoints",
    }

    // Create the DNSEndpoint object as an unstructured resource
    dnsEndpoint := &unstructured.Unstructured{
        Object: map[string]interface{}{
            // ... existing definition ...
        },
    }

    // Create the DNSEndpoint resource
    _, err := dynamicClient.Resource(dnsEndpointGVR).Namespace(namespace).Create(context.Background(), dnsEndpoint, metav1.CreateOptions{})
    return err
}
🧰 Tools
🪛 golangci-lint (1.64.8)

136-136: Error return value of informer.AddEventHandler is not checked

(errcheck)


177-184: Improve timeout handling with context.

The current code uses a simple select with time.After for timeout handling. Consider using a context with timeout for better cancellation control and more idiomatic Go.

+	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
+	defer cancel()

	select {
		case <-stopChannel:
			msg := "Dns endpoint created"
			fmt.Println(msg)
-		case <-time.After(1 * time.Minute):
+		case <-ctx.Done():
			msg := "Dns endpoint creation timed out"
			assert.Fail(s.T(), msg)
	}

190-237: Simplify Route53 cleanup code with assert.NoError usage.

The cleanup code contains several error checks that silently return without proper assertions. Consider using assert.NoError consistently.

	defer func() {
		route53Client, err := awsTerratest.NewRoute53ClientE(s.T(), awsRegion)
-		if err != nil {
-			return
-		}
+		assert.NoError(s.T(), err, "Failed to create Route53 client")
+		if err != nil {
+			return
+		}

		o, err := route53Client.ListResourceRecordSets(context.Background(), &route53.ListResourceRecordSetsInput{
			HostedZoneId:    &defaultDNSZoneId,
			MaxItems:        aws.Int32(100),
		})
-		if err != nil {
-			return
-		}
+		assert.NoError(s.T(), err, "Failed to list resource record sets")
+		if err != nil {
+			return
+		}

		// Rest of the code remains the same

190-237: Use consistent error handling throughout the cleanup code.

The cleanup function handles errors inconsistently. At the end of the function, there's an assertion for the ChangeResourceRecordSets error, but earlier errors are silently ignored. Strive for consistency in error handling.

This cleanup function could be extracted into a separate helper method with clear documentation about its purpose and error handling approach.


74-75: Fix typo in variable name.

There's a typo in the variable name clusrerId, which should be clusterId.

-	clusrerId := atmos.Output(s.T(), clusterOptions, "eks_cluster_id")
-	cluster := awsHelper.GetEksCluster(s.T(), context.Background(), awsRegion, clusrerId)
+	clusterId := atmos.Output(s.T(), clusterOptions, "eks_cluster_id")
+	cluster := awsHelper.GetEksCluster(s.T(), context.Background(), awsRegion, clusterId)

128-128: Remove commented code.

There's a commented line with an extra comment marker that should be removed.

-	// // Wait for the DnsEndpoint to be updated with the LoadBalancer metadata
+	// Wait for the DnsEndpoint to be updated with the LoadBalancer metadata
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6100585 and 39a69f4.

📒 Files selected for processing (1)
  • test/component_test.go (1 hunks)
🧰 Additional context used
🪛 golangci-lint (1.64.8)
test/component_test.go

136-136: Error return value of informer.AddEventHandler is not checked

(errcheck)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🔇 Additional comments (2)
test/component_test.go (2)

136-174: Handle error return value from informer.AddEventHandler

The error return value from informer.AddEventHandler is not checked, which was flagged by static analysis.

Apply this change to properly handle the error:

-	informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
+	if err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		UpdateFunc: func(oldObj, newObj interface{}) {
			_, ok := oldObj.(*unstructured.Unstructured)
			if !ok {
				return
			}
			newDNS, ok := newObj.(*unstructured.Unstructured)
			if !ok {
				return
			}

			observedGeneration, found, err := unstructured.NestedInt64(newDNS.Object, "status", "observedGeneration")
			if err != nil {
				fmt.Printf("Error getting status: %v\n", err)
				return
			}
			if !found {
				fmt.Printf("Status not found\n")
				return
			}

			name, found, err := unstructured.NestedString(newDNS.Object, "metadata", "name")
			if err != nil {
				fmt.Printf("Error getting name: %v\n", err)
				return
			}
			if !found {
				fmt.Printf("Name not found\n")
				return
			}

			if observedGeneration > 0 {
				fmt.Printf("Dns Record %s is ready\n", name)
				close(stopChannel)
			} else {
				fmt.Printf("Dns Record %s is not ready yet\n", name)
			}
		},
-	})
+	}); err != nil {
+		assert.NoError(s.T(), err, "failed to add event handler")
+	}
🧰 Tools
🪛 golangci-lint (1.64.8)

136-136: Error return value of informer.AddEventHandler is not checked

(errcheck)


54-56:

❓ Verification inconclusive

Check both return values from DeployAtmosComponent.

You're capturing both return values from DeployAtmosComponent but only checking options. Consider checking the second return value (likely an error) as well.


🏁 Script executed:

#!/bin/bash
# Find the DeployAtmosComponent function to verify its return values
# and how they should be handled
rg -A 5 "func.*DeployAtmosComponent" --type go

Length of output: 48


Action Required: Verify Error Handling for DeployAtmosComponent

The test currently only verifies that the primary return value (options) is non-nil but ignores the second return value. It’s unclear from our automated search whether the second value is indeed an error that should be checked. Please manually verify the signature of DeployAtmosComponent to confirm its return types and update the test accordingly:

  • Confirm that the function returns an error (or another meaningful value) as its second return value.
  • Update the test to check that the error is handled appropriately (e.g., assert that it is nil when no error is expected).

@goruha
Copy link
Contributor Author

goruha commented Mar 26, 2025

/terratest

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (1)
test/component_test.go (1)

122-124: Improve error handling in defer function

The error handling in the deferred deletion function only prints the error but doesn't assert or fail the test. Consider adding an assertion to catch cleanup failures.

	defer func() {
		if err := dynamicClient.Resource(dnsEndpointGVR).Namespace(namespace).Delete(context.Background(), dnsEndpointName, metav1.DeleteOptions{}); err != nil {
-			fmt.Printf("Error deleting external dns %s: %v\n", dnsEndpointName, err)
+			s.T().Logf("Error deleting external dns %s: %v\n", dnsEndpointName, err)
+			assert.NoError(s.T(), err, "failed to clean up DNS endpoint resource")
		}
	}()
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39a69f4 and 9f8cbfe.

📒 Files selected for processing (2)
  • src/main.tf (2 hunks)
  • test/component_test.go (1 hunks)
🧰 Additional context used
🪛 golangci-lint (1.64.8)
test/component_test.go

136-136: Error return value of informer.AddEventHandler is not checked

(errcheck)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🔇 Additional comments (7)
src/main.tf (2)

15-19: Clean implementation of zone_names local variable

The new zone_names local variable follows the same pattern as the existing zone_ids variable, making the code consistent and easy to understand. This is a good approach for extracting the zone names from multiple DNS modules.


107-107: Good use of zone filtering

Adding domain filters to the external-dns configuration is a security best practice. It restricts the DNS controller to only manage records in the specified zones, preventing unintended modifications to other DNS zones.

test/component_test.go (5)

82-84: Replace panic with proper test assertions.

Using panic in test code is not recommended as it stops test execution and doesn't provide a clear test failure message. Instead, use the testify assertion framework that is already imported.

-	if err != nil {
-		panic(fmt.Errorf("failed to create dynamic client: %v", err))
-	}
+	assert.NoError(s.T(), err, "failed to create dynamic client")
+	assert.NotNil(s.T(), dynamicClient)

136-174: Handle error return value from informer.AddEventHandler

The static analysis tool detected that the error return value from informer.AddEventHandler is not checked on line 136.

-	informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
+	if err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		UpdateFunc: func(oldObj, newObj interface{}) {
			_, ok := oldObj.(*unstructured.Unstructured)
			if !ok {
				return
			}
			newDNS, ok := newObj.(*unstructured.Unstructured)
			if !ok {
				return
			}

			observedGeneration, found, err := unstructured.NestedInt64(newDNS.Object, "status", "observedGeneration")
			if err != nil {
				fmt.Printf("Error getting status: %v\n", err)
				return
			}
			if !found {
				fmt.Printf("Status not found\n")
				return
			}

			name, found, err := unstructured.NestedString(newDNS.Object, "metadata", "name")
			if err != nil {
				fmt.Printf("Error getting name: %v\n", err)
				return
			}
			if !found {
				fmt.Printf("Name not found\n")
				return
			}

			if observedGeneration > 0 {
				fmt.Printf("Dns Record %s is ready\n", name)
				close(stopChannel)
			} else {
				fmt.Printf("Dns Record %s is not ready yet\n", name)
			}
		},
-	})
+	}); err != nil {
+		assert.NoError(s.T(), err, "failed to add event handler")
+	}
🧰 Tools
🪛 golangci-lint (1.64.8)

136-136: Error return value of informer.AddEventHandler is not checked

(errcheck)


34-240: Comprehensive test implementation for basic functionality

The TestBasic function provides a thorough end-to-end test case that:

  1. Sets up necessary AWS and Kubernetes resources
  2. Deploys the external-dns component with Helm
  3. Creates a DNS endpoint custom resource
  4. Waits for DNS propagation
  5. Verifies the DNS record in Route53
  6. Cleans up resources
  7. Tests for configuration drift

This is an excellent implementation that ensures the component works correctly and remains stable across deployments.

🧰 Tools
🪛 golangci-lint (1.64.8)

136-136: Error return value of informer.AddEventHandler is not checked

(errcheck)


242-246: LGTM: Properly testing disabled functionality

The TestEnabledFlag function correctly tests that no resources are created when the component is disabled, which is an important verification.


254-302: Well-structured test suite setup

The test setup properly creates all required dependencies (VPC, EKS cluster, DNS zones) before running the external-dns tests. The use of random IDs for test resources prevents conflicts between test runs and enables parallel testing.

@goruha
Copy link
Contributor Author

goruha commented Mar 26, 2025

/terratest

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
test/component_test.go (1)

133-175: ⚠️ Potential issue

Handle error return value from informer.AddEventHandler

The static analysis tool detected that the error return value from informer.AddEventHandler is not checked.

-	informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
+	if err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		UpdateFunc: func(oldObj, newObj interface{}) {
			_, ok := oldObj.(*unstructured.Unstructured)
			if !ok {
				return
			}
			newDNS, ok := newObj.(*unstructured.Unstructured)
			if !ok {
				return
			}

			name, found, err := unstructured.NestedString(newDNS.Object, "metadata", "name")
			if err != nil {
				fmt.Printf("Error getting name: %v\n", err)
				return
			}
			if !found {
				fmt.Printf("Name not found\n")
				return
			}
			if name != dnsEndpointName {
				fmt.Printf("DNS record is not %s\n", dnsEndpointName)
				return
			}

			observedGeneration, found, err := unstructured.NestedString(newDNS.Object, "status", "observedGeneration")
			if err != nil {
				fmt.Printf("Error getting status: %v\n", err)
				return
			}
			if !found {
				fmt.Printf("Status not found\n")
				return
			}

			if observedGeneration > 0 {
				fmt.Printf("Dns Record %s is ready\n", name)
				close(stopChannel)
			} else {
				fmt.Printf("Dns Record %s is not ready yet\n", name)
			}
		},
-	})
+	}); err != nil {
+		assert.NoError(s.T(), err, "failed to add event handler")
+	}
🧰 Tools
🪛 golangci-lint (1.64.8)

133-133: Error return value of informer.AddEventHandler is not checked

(errcheck)

🧹 Nitpick comments (6)
test/component_test.go (5)

119-122: Improve error handling in defer block

The current error handling in the defer block only prints the error but doesn't assert it. Consider adding a better error handling mechanism or test assertion.

	defer func() {
		if err := dynamicClient.Resource(dnsEndpointGVR).Namespace(namespace).Delete(context.Background(), dnsEndpointName, metav1.DeleteOptions{}); err != nil {
-			fmt.Printf("Error deleting external dns %s: %v\n", dnsEndpointName, err)
+			// Log but don't fail the test for cleanup errors
+			fmt.Printf("Error deleting external dns %s: %v\n", dnsEndpointName, err)
+			// Alternatively, use t.Logf instead of fmt.Printf for test-specific logging
		}
	}()

178-185: Add timeout explanation and consider making it configurable

The test waits for 1 minute for the DNS endpoint to be created, which is hardcoded. Consider adding a comment explaining this timeout value or making it configurable.

+	// Wait up to 1 minute for the DNS endpoint to be properly created and updated
	select {
		case <-stopChannel:
			msg := "Dns endpoint created"
			fmt.Println(msg)
-		case <-time.After(1 * time.Minute):
+		case <-time.After(1 * time.Minute): // Consider making this timeout configurable
			msg := "Dns endpoint creation timed out"
			assert.Fail(s.T(), msg)
	}

50-52: Consider adding more context in test inputs

The test inputs are minimal. Consider adding more context or comments to explain the significance of these inputs for better test documentation.

	inputs := map[string]interface{}{
+		// Namespace where the external-dns component will be deployed
		"kubernetes_namespace": namespace,
	}

46-48: Extract common test variables to constants

The test uses several string formatting patterns. Consider extracting these to constants at the test suite level for better readability and maintenance.

+	// Constants for resource naming patterns
+	const (
+		namespaceFormat    = "external-dns-%s"
+		dnsEndpointFormat  = "example-dns-record-%s"
+		dnsRecordHostFormat = "%s.%s"
+	)

-	namespace := fmt.Sprintf("external-dns-%s", randomID)
-	dnsEndpointName := fmt.Sprintf("example-dns-record-%s", randomID)
-	dnsRecordHostName := fmt.Sprintf("%s.%s", randomID, delegatedDomainName)
+	namespace := fmt.Sprintf(namespaceFormat, randomID)
+	dnsEndpointName := fmt.Sprintf(dnsEndpointFormat, randomID)
+	dnsRecordHostName := fmt.Sprintf(dnsRecordHostFormat, randomID, delegatedDomainName)

90-112: Consider extracting DNSEndpoint creation to a helper function

The DNSEndpoint creation logic is quite verbose. Consider extracting this to a helper function for better readability and potential reuse.

+// createDNSEndpoint creates a DNSEndpoint resource with the given name, namespace, and hostname
+func createDNSEndpoint(name, namespace, hostname string) *unstructured.Unstructured {
+	return &unstructured.Unstructured{
+		Object: map[string]interface{}{
+			"apiVersion": "externaldns.k8s.io/v1alpha1",
+			"kind":       "DNSEndpoint",
+			"metadata": map[string]interface{}{
+				"name":	name,
+				"namespace": namespace,
+			},
+			"spec": map[string]interface{}{
+				"endpoints": []interface{}{
+					map[string]interface{}{
+						"dnsName": hostname,
+						"recordTTL":  300,
+						"recordType": "A",
+						"targets": []interface{}{
+							"127.0.0.1",
+						},
+					},
+				},
+			},
+		},
+	}
+}

// In the test function:
-	// Create the DNSEndpoint object as an unstructured resource
-	dnsEndpoint := &unstructured.Unstructured{
-		Object: map[string]interface{}{
-			"apiVersion": "externaldns.k8s.io/v1alpha1",
-			"kind":       "DNSEndpoint",
-			"metadata": map[string]interface{}{
-				"name":	dnsEndpointName,
-				"namespace": namespace,
-			},
-			"spec": map[string]interface{}{
-				"endpoints": []interface{}{
-					map[string]interface{}{
-						"dnsName": dnsRecordHostName,
-						"recordTTL":  300,
-						"recordType": "A",
-						"targets": []interface{}{
-							"127.0.0.1",
-						},
-					},
-				},
-			},
-		},
-	}
+	// Create the DNSEndpoint object as an unstructured resource
+	dnsEndpoint := createDNSEndpoint(dnsEndpointName, namespace, dnsRecordHostName)
test/go.mod (1)

17-17: Fix or remove the commented out replace directive

The replace directive is commented out, which suggests it might be needed but is currently disabled. Either remove it completely if not needed or enable it properly.

-// replace github.com/rebuy-de/aws-nuke/v2/mocks => github.com/ekristen/aws-nuke/v3/ v3.29.0
+replace github.com/rebuy-de/aws-nuke/v2/mocks => github.com/ekristen/aws-nuke/v3 v3.29.0

Or if it's not needed:

-// replace github.com/rebuy-de/aws-nuke/v2/mocks => github.com/ekristen/aws-nuke/v3/ v3.29.0
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9f8cbfe and 2e4e389.

⛔ Files ignored due to path filters (1)
  • test/go.sum is excluded by !**/*.sum
📒 Files selected for processing (2)
  • test/component_test.go (1 hunks)
  • test/go.mod (1 hunks)
🧰 Additional context used
🪛 golangci-lint (1.64.8)
test/component_test.go

133-133: Error return value of informer.AddEventHandler is not checked

(errcheck)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🔇 Additional comments (3)
test/component_test.go (2)

79-81: Replace panic with proper test assertions.

Using panic in test code is not recommended as it stops test execution and doesn't provide a clear test failure message. Instead, use the testify assertion framework that is already imported.

-	if err != nil {
-		panic(fmt.Errorf("failed to create dynamic client: %v", err))
-	}
+	assert.NoError(s.T(), err, "failed to create dynamic client")
+	assert.NotNil(s.T(), dynamicClient)

158-166: ⚠️ Potential issue

Type mismatch in observedGeneration retrieval

The function unstructured.NestedString is being used to retrieve observedGeneration, but based on the comparison with an integer value (line 168), this should be retrieved as an integer using NestedInt64.

-			observedGeneration, found, err := unstructured.NestedString(newDNS.Object, "status", "observedGeneration")
+			observedGeneration, found, err := unstructured.NestedInt64(newDNS.Object, "status", "observedGeneration")

Likely an incorrect or invalid review comment.

test/go.mod (1)

3-5:

❓ Verification inconclusive

Verify Go version compatibility with CI/CD environment

The module specifies Go 1.24.0 and toolchain 1.24.1, which are very recent versions. Ensure that your CI/CD environment supports these versions.


🏁 Script executed:

#!/bin/bash
# Check if there's any CI configuration file that might specify Go versions
# This helps determine if the specified Go version is compatible with CI setup

# Look for common CI configuration files
files=$(fd -t f -e yaml -e yml -e json -e toml "^(.travis|.github/workflows/|.circleci/|.gitlab-ci)" --exclude node_modules)

if [ -n "$files" ]; then
  echo "Found CI configuration files:"
  for file in $files; do
    echo "==== $file ===="
    cat "$file" | grep -i "go " || echo "No explicit Go version found in $file"
  done
else
  echo "No CI configuration files found"
fi

# Check if there are any Go version requirements in other parts of the codebase
echo "==== Looking for Go version references in the codebase ===="
rg -i "go[ \t]*version|go[ \t]*[0-9]" --type yaml --type toml

Length of output: 409


Action Required: Confirm CI/CD Environment Supports Go 1.24.x

The go.mod file now specifies go 1.24.0 and uses toolchain go1.24.1. Our scan for CI configuration files (e.g. YAML, TOML) did not return any files explicitly enforcing a Go version. Please verify manually that your CI/CD environment either defaults to or is explicitly configured to use Go 1.24.x. If not, consider updating your CI configuration to specify the required version to avoid any compatibility issues.

@goruha
Copy link
Contributor Author

goruha commented Mar 26, 2025

/terratest

@goruha
Copy link
Contributor Author

goruha commented Mar 26, 2025

/terratest

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
test/component_test.go (3)

31-196: Consider breaking down the TestBasic method into smaller functions

The TestBasic method is quite long and handles multiple responsibilities, which could make it harder to maintain and debug. Consider extracting logical sections into helper methods to improve readability and maintainability.

You could extract the following sections into helper methods:

  1. EKS and DNS setup (lines 36-55)
  2. Creating and verifying the external-DNS deployment (lines 56-78)
  3. Setting up Kubernetes clients (lines 79-87)
  4. Creating and monitoring DNSEndpoint (lines 89-190)
  5. Verifying Route53 records (lines 192-194)

For example:

func (s *ComponentSuite) setupEnvironment(stack string) (string, string, string, string) {
    const awsRegion = "us-east-2"
    
    // Get cluster info
    clusterOptions := s.GetAtmosOptions("eks/cluster", stack, nil)
    clusterId := atmos.Output(s.T(), clusterOptions, "eks_cluster_id")
    cluster := awsHelper.GetEksCluster(s.T(), context.Background(), awsRegion, clusterId)
    
    // Get DNS info
    dnsDelegatedOptions := s.GetAtmosOptions("dns-delegated", stack, nil)
    delegatedDomainName := atmos.Output(s.T(), dnsDelegatedOptions, "default_domain_name")
    defaultDNSZoneId := atmos.Output(s.T(), dnsDelegatedOptions, "default_dns_zone_id")
    
    // Setup cleanup
    defer func() {
        if err := awsHelper.CleanDNSZoneID(s.T(), context.Background(), defaultDNSZoneId, awsRegion); err != nil {
            fmt.Printf("Error cleaning DNS zone %s: %v\n", defaultDNSZoneId, err)
        }
    }()
    
    // Generate random identifiers
    randomID := strings.ToLower(random.UniqueId())
    
    return randomID, defaultDNSZoneId, delegatedDomainName, awsRegion
}
🧰 Tools
🪛 golangci-lint (1.64.8)

138-138: Error return value of informer.AddEventHandler is not checked

(errcheck)


187-190: Consider making the timeout configurable or longer

The current timeout for DNS endpoint creation is fixed at 1 minute, which might not be enough in some environments where DNS propagation is slower.

Consider making this timeout configurable or extending it to account for potentially slower DNS propagation:

-	case <-time.After(1 * time.Minute):
+	case <-time.After(5 * time.Minute): // Longer timeout for DNS propagation

Alternatively, make it configurable:

+	const dnsEndpointTimeout = 5 * time.Minute // Configurable timeout at the top of the file

// Later in the code
-	case <-time.After(1 * time.Minute):
+	case <-time.After(dnsEndpointTimeout):

139-179: Improve error handling in the event handler function

The current implementation uses fmt.Printf for error logging. In a test environment, it's better to use proper test assertions or structured logging.

Consider updating the error handling approach:

UpdateFunc: func(oldObj, newObj interface{}) {
    _, ok := oldObj.(*unstructured.Unstructured)
    if !ok {
-       return
+       s.T().Logf("oldObj is not an Unstructured object: %T", oldObj)
+       return
    }
    newDNS, ok := newObj.(*unstructured.Unstructured)
    if !ok {
-       return
+       s.T().Logf("newObj is not an Unstructured object: %T", newObj)
+       return
    }

    name, found, err := unstructured.NestedString(newDNS.Object, "metadata", "name")
    if err != nil {
-       fmt.Printf("Error getting name: %v\n", err)
+       s.T().Logf("Error getting name: %v", err)
        return
    }
    if !found {
-       fmt.Printf("Name not found\n")
+       s.T().Log("Name not found in object")
        return
    }
    // ... similar changes for other error handling
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2e4e389 and e13e1e5.

📒 Files selected for processing (1)
  • test/component_test.go (1 hunks)
🧰 Additional context used
🪛 golangci-lint (1.64.8)
test/component_test.go

138-138: Error return value of informer.AddEventHandler is not checked

(errcheck)

⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🔇 Additional comments (2)
test/component_test.go (2)

85-87: Replace panic with proper test assertions.

Using panic in test code is not recommended as it stops test execution abruptly and doesn't provide a clear test failure message. Instead, use the testify assertion framework that's already imported.

Apply this diff to fix the issue:

-	if err != nil {
-		panic(fmt.Errorf("failed to create dynamic client: %v", err))
-	}
+	assert.NoError(s.T(), err, "failed to create dynamic client")
+	assert.NotNil(s.T(), dynamicClient)

138-180: Handle error return value from informer.AddEventHandler

The return value from informer.AddEventHandler needs to be checked for errors, as indicated by the static analysis tool.

Apply this diff to add proper error handling:

-	informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
+	if err := informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
		UpdateFunc: func(oldObj, newObj interface{}) {
			_, ok := oldObj.(*unstructured.Unstructured)
			if !ok {
				return
			}
			newDNS, ok := newObj.(*unstructured.Unstructured)
			if !ok {
				return
			}

			name, found, err := unstructured.NestedString(newDNS.Object, "metadata", "name")
			if err != nil {
				fmt.Printf("Error getting name: %v\n", err)
				return
			}
			if !found {
				fmt.Printf("Name not found\n")
				return
			}
			if name != dnsEndpointName {
				fmt.Printf("DNS record is not %s\n", dnsEndpointName)
				return
			}

			observedGeneration, found, err := unstructured.NestedInt64(newDNS.Object, "status", "observedGeneration")
			if err != nil {
				fmt.Printf("Error getting status: %v\n", err)
				return
			}
			if !found {
				fmt.Printf("Status not found\n")
				return
			}

			if observedGeneration > 0 {
				fmt.Printf("Dns Record %s is ready\n", name)
				close(stopChannel)
			} else {
				fmt.Printf("Dns Record %s is not ready yet\n", name)
			}
		},
-	})
+	}); err != nil {
+		assert.NoError(s.T(), err, "failed to add event handler")
+	}
🧰 Tools
🪛 golangci-lint (1.64.8)

138-138: Error return value of informer.AddEventHandler is not checked

(errcheck)

@goruha
Copy link
Contributor Author

goruha commented Mar 26, 2025

/terratest

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
test/component_test.go (3)

130-130: Replace fixed sleep with polling or wait mechanism.

Using a fixed sleep duration (2 minutes) is brittle and can lead to either unnecessary waiting or test failures if DNS propagation takes longer than expected. Consider implementing a polling mechanism with timeout instead.

-	time.Sleep(2 * time.Minute)
+	// Poll for the DNS record with exponential backoff
+	timeout := 5 * time.Minute
+	interval := 10 * time.Second
+	maxInterval := 30 * time.Second
+	found := false
+	
+	err = awsHelper.WaitForCondition(s.T(), timeout, interval, maxInterval, func() (bool, error) {
+		delegatedNSRecord, err := awsTerratest.GetRoute53RecordE(s.T(), defaultDNSZoneId, dnsRecordHostName, "A", awsRegion)
+		if err != nil {
+			return false, nil // Not found yet, continue waiting
+		}
+		found = true
+		return found, nil
+	})
+	
+	assert.True(s.T(), found, "DNS record was not created within the timeout period")

132-191: Either implement or remove commented code.

The commented code contains a more robust implementation for waiting for the DNSEndpoint resource to be ready. Either implement this code (with proper error handling as noted in the previous review) or remove it entirely to maintain code cleanliness.

If you decide to implement it, remember to uncomment the imports on lines 23-24 and add error handling for the AddEventHandler method as suggested in the previous review.


23-24: Either use or remove commented imports.

These imports are only used in the commented-out code block. Either implement that code block with proper error handling or remove these imports.

-// "k8s.io/client-go/dynamic/dynamicinformer"
-// "k8s.io/client-go/tools/cache"
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e13e1e5 and 0c6b0b4.

📒 Files selected for processing (1)
  • test/component_test.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🔇 Additional comments (2)
test/component_test.go (2)

85-87: Replace panic with proper test assertions.

Using panic in test code is not recommended as it stops test execution and doesn't provide a clear test failure message. Instead, use the testify assertion framework that is already imported.

-	if err != nil {
-		panic(fmt.Errorf("failed to create dynamic client: %v", err))
-	}
+	assert.NoError(s.T(), err, "failed to create dynamic client")
+	assert.NotNil(s.T(), dynamicClient)

196-196:

❓ Verification inconclusive

Verify drift test behavior for DNS records.

The drift test checks that Terraform doesn't report any resource changes when applied twice with the same configuration. However, it's unclear if this would detect a scenario where the DNS record is modified outside of Terraform (e.g., manually or by another process).


🏁 Script executed:

#!/bin/bash
# Look for any drift handling mechanisms in the component code
echo "Searching for drift detection patterns in external-dns component..."
rg -A 5 "drift|reconcile|sync" components/terraform/eks/external-dns

Length of output: 293


Drift Test – External DNS Record Modifications
The current drift test in test/component_test.go (line 196) invokes s.DriftTest(component, stack, &inputs), which verifies that applying the Terraform configuration twice does not yield any changes. However, it remains unclear whether this test would catch a scenario where a DNS record is modified externally (e.g., manually or via another process).

  • Note that our initial search for drift detection logic in the expected components/terraform/eks/external-dns directory returned an error (directory not found), so it's possible that any specialized handling for external DNS drift might reside elsewhere—or may not exist.
  • Action: Please manually verify whether external modifications to DNS records are detected by the system. If not, consider extending the test to simulate an external change (or document that such a scenario is intentionally out of scope).

@goruha
Copy link
Contributor Author

goruha commented Mar 26, 2025

/terratest

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (6)
test/component_test.go (6)

35-35: Fix typo in variable name.

The variable name "clusrerId" contains a typo and should be "clusterId" for better readability and consistency.

-	clusrerId := atmos.Output(s.T(), clusterOptions, "eks_cluster_id")
-	cluster := awsHelper.GetEksCluster(s.T(), context.Background(), awsRegion, clusrerId)
+	clusterId := atmos.Output(s.T(), clusterOptions, "eks_cluster_id")
+	cluster := awsHelper.GetEksCluster(s.T(), context.Background(), awsRegion, clusterId)

42-46: Improve error handling in defer function.

The current implementation only logs errors during cleanup without asserting or failing the test. This could lead to silent failures and resources not being properly cleaned up.

	defer func() {
		if err := awsHelper.CleanDNSZoneID(s.T(), context.Background(), defaultDNSZoneId, awsRegion); err != nil {
-			fmt.Printf("Error cleaning DNS zone %s: %v\n", defaultDNSZoneId, err)
+			s.T().Logf("Error cleaning DNS zone %s: %v", defaultDNSZoneId, err)
+			s.T().Errorf("Failed to clean up DNS zone: %v", err)
		}
	}()

123-126: Improve error handling in resource cleanup.

Similar to the DNS zone cleanup, errors during DNSEndpoint resource deletion are only logged and don't fail the test. This could lead to orphaned resources.

	defer func() {
		if err := dynamicClient.Resource(dnsEndpointGVR).Namespace(namespace).Delete(context.Background(), dnsEndpointName, metav1.DeleteOptions{}); err != nil {
-			fmt.Printf("Error deleting external dns %s: %v\n", dnsEndpointName, err)
+			s.T().Logf("Error deleting external dns %s: %v", dnsEndpointName, err)
+			s.T().Errorf("Failed to delete DNSEndpoint resource: %v", err)
		}
	}()

32-32: Make region configurable.

The AWS region is hardcoded as "us-east-2" which could make the tests less flexible when running in different environments or regions.

-	const awsRegion = "us-east-2"
+	// Use a configurable region or default to us-east-2
+	awsRegion := s.GetRegionOrDefault("us-east-2")

Consider adding a helper method to the TestSuite to retrieve the region from environment variables or configuration:

func (s *TestSuite) GetRegionOrDefault(defaultRegion string) string {
	region := os.Getenv("AWS_REGION")
	if region == "" {
		region = defaultRegion
	}
	return region
}

68-75: Extract version assertions to constants or configuration.

Hardcoded version assertions make tests brittle as they need to be updated whenever the component versions change. Consider making these configurable or using version comparisons instead of exact matches.

-	assert.Equal(s.T(), metadata.AppVersion, "0.14.0")
-	assert.Equal(s.T(), metadata.Chart, "external-dns")
+	// Define expected versions in constants or config
+	const (
+		ExpectedAppVersion = "0.14.0"
+		ExpectedChartName  = "external-dns"
+		ExpectedChartVersion = "6.33.0"
+	)
+	
+	assert.Equal(s.T(), metadata.AppVersion, ExpectedAppVersion, "App version mismatch")
+	assert.Equal(s.T(), metadata.Chart, ExpectedChartName, "Chart name mismatch")
	assert.NotNil(s.T(), metadata.FirstDeployed)
	assert.NotNil(s.T(), metadata.LastDeployed)
	assert.Equal(s.T(), metadata.Name, "external-dns")
	assert.Equal(s.T(), metadata.Namespace, namespace)
	assert.NotNil(s.T(), metadata.Values)
-	assert.Equal(s.T(), metadata.Version, "6.33.0")
+	assert.Equal(s.T(), metadata.Version, ExpectedChartVersion, "Chart version mismatch")

138-142: Add a detailed comment explaining the TestEnabledFlag functionality.

The TestEnabledFlag method's purpose is not immediately clear from the code. Add documentation explaining what VerifyEnabledFlag does and what specific behavior is being tested.

+/**
+ * TestEnabledFlag verifies that when the external-dns component is disabled,
+ * no resources are created. This is a crucial test to ensure that the 'enabled'
+ * flag works correctly to completely prevent resource creation when set to false.
+ */
func (s *ComponentSuite) TestEnabledFlag() {
	const component = "eks/external-dns/disabled"
	const stack = "default-test"
	s.VerifyEnabledFlag(component, stack, nil)
}
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0c6b0b4 and bfb3490.

📒 Files selected for processing (1)
  • test/component_test.go (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🔇 Additional comments (1)
test/component_test.go (1)

83-85: Replace panic with proper test assertions.

Using panic in test code is not recommended as it stops test execution and doesn't provide a clear test failure message. Instead, use the testify assertion framework that is already imported.

-	if err != nil {
-		panic(fmt.Errorf("failed to create dynamic client: %v", err))
-	}
+	assert.NoError(s.T(), err, "failed to create dynamic client")
+	assert.NotNil(s.T(), dynamicClient)

@goruha
Copy link
Contributor Author

goruha commented Mar 31, 2025

/terratest

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (4)
test/go.mod (4)

1-2: Module Declaration and Naming
The module is declared as module test, which correctly initializes a new Go module for tests. Consider whether the generic name "test" is sufficiently descriptive for its purpose (e.g., "component_test"), especially if multiple test modules might exist in the repository.


7-15: Direct Dependencies Grouping
The first require block cleanly lists essential and direct dependencies (including packages such as github.com/cloudposse/test-helpers, github.com/gruntwork-io/terratest, and github.com/stretchr/testify). It’s good to see clear version pinning here. Optionally, you might add comments or re-group dependencies if you later need to differentiate between runtime and test-specific packages for clarity.


17-18: Replacement Directive
The replace directive for
github.com/rebuy-de/aws-nuke/v2/mocks to github.com/ekristen/aws-nuke/v3/ v3.29.0 is properly noted. Please verify that this substitution aligns with your dependency management strategy and that the new replacement does not introduce any incompatibilities.


24-185: Extensive Indirect Dependencies Listing
The third require block includes a detailed list of indirect dependencies. While it’s common for Go modules to accumulate many indirect requirements, periodically running go mod tidy can help remove any that are no longer necessary. Additionally, verify that these versions do not conflict with your direct dependencies or future upgrades.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfb3490 and 4b9293f.

⛔ Files ignored due to path filters (1)
  • test/go.sum is excluded by !**/*.sum
📒 Files selected for processing (1)
  • test/go.mod (1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Mergify Merge Protections
  • GitHub Check: Summary
🔇 Additional comments (3)
test/go.mod (3)

3-4: Go Version Specification
Declaring the Go version as 1.24.0 is clear and ensures consistency in builds. Confirm that all dependencies are compatible with this Go version.


5-6: Toolchain Directive
Including the toolchain directive (toolchain go1.24.1) is a useful practice to enforce a specific build environment. Ensure that your CI/CD pipeline and local development setups support this specific toolchain version.


19-22: Additional Dependencies Grouping
The second require block, which groups dependencies for Kubernetes API machinery and external DNS (k8s.io/apimachinery and sigs.k8s.io/external-dns), is straightforward. Ensure that these version constraints meet your project's integration requirements.

@goruha goruha merged commit 00d3656 into main Mar 31, 2025
19 checks passed
@goruha goruha deleted the add-tests branch March 31, 2025 12:08
@github-actions
Copy link

These changes were released in v1.535.1.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-test Needs testing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add component tests

2 participants