From ab90e15d58b7c9841139e125b6fe07cab9c20fae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergen=20Yal=C3=A7=C4=B1n?= Date: Thu, 9 Jan 2025 17:53:27 +0300 Subject: [PATCH 1/3] Export core functionality of uptest MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sergen Yalçın --- cmd/uptest/main.go | 37 ++++++++-------- internal/config/builder.go | 84 +++++++++++++++++++++++++++++++++++++ internal/prepare.go | 22 +++++----- internal/tester.go | 14 +++---- {internal => pkg}/runner.go | 15 +++---- 5 files changed, 129 insertions(+), 43 deletions(-) create mode 100644 internal/config/builder.go rename {internal => pkg}/runner.go (63%) diff --git a/cmd/uptest/main.go b/cmd/uptest/main.go index a3d2547..33c38c0 100644 --- a/cmd/uptest/main.go +++ b/cmd/uptest/main.go @@ -12,8 +12,7 @@ import ( "gopkg.in/alecthomas/kingpin.v2" - "github.com/crossplane/uptest/internal" - "github.com/crossplane/uptest/internal/config" + "github.com/crossplane/uptest/pkg" ) var ( @@ -88,21 +87,23 @@ func e2eTests() { kingpin.FatalIfError(err, "cannot get absolute path of teardown script") } } - o := &config.AutomatedTest{ - ManifestPaths: examplePaths, - DataSourcePath: *dataSourcePath, - SetupScriptPath: setupPath, - TeardownScriptPath: teardownPath, - DefaultConditions: strings.Split(*defaultConditions, ","), - DefaultTimeout: *defaultTimeout, - Directory: *testDir, - SkipDelete: *skipDelete, - SkipUpdate: *skipUpdate, - SkipImport: *skipImport, - OnlyCleanUptestResources: *onlyCleanUptestResources, - RenderOnly: *renderOnly, - LogCollectionInterval: *logCollectInterval, - } - kingpin.FatalIfError(internal.RunTest(o), "cannot run e2e tests successfully") + builder := pkg.NewAutomatedTestBuilder() + automatedTest := builder. + SetManifestPaths(examplePaths). + SetDataSourcePath(*dataSourcePath). + SetSetupScriptPath(setupPath). + SetTeardownScriptPath(teardownPath). + SetDefaultConditions(strings.Split(*defaultConditions, ",")). + SetDefaultTimeout(*defaultTimeout). + SetDirectory(*testDir). + SetSkipDelete(*skipDelete). + SetSkipUpdate(*skipUpdate). + SetSkipImport(*skipImport). + SetOnlyCleanUptestResources(*onlyCleanUptestResources). + SetRenderOnly(*renderOnly). + SetLogCollectionInterval(*logCollectInterval). + Build() + + kingpin.FatalIfError(pkg.RunTest(automatedTest), "cannot run e2e tests successfully") } diff --git a/internal/config/builder.go b/internal/config/builder.go new file mode 100644 index 0000000..43ec43a --- /dev/null +++ b/internal/config/builder.go @@ -0,0 +1,84 @@ +package config + +import ( + "time" +) + +type Builder struct { + test AutomatedTest +} + +func NewBuilder() *Builder { + return &Builder{ + test: AutomatedTest{}, + } +} + +func (b *Builder) SetDirectory(directory string) *Builder { + b.test.Directory = directory + return b +} + +func (b *Builder) SetManifestPaths(manifestPaths []string) *Builder { + b.test.ManifestPaths = manifestPaths + return b +} + +func (b *Builder) SetDataSourcePath(dataSourcePath string) *Builder { + b.test.DataSourcePath = dataSourcePath + return b +} + +func (b *Builder) SetSetupScriptPath(setupScriptPath string) *Builder { + b.test.SetupScriptPath = setupScriptPath + return b +} + +func (b *Builder) SetTeardownScriptPath(teardownScriptPath string) *Builder { + b.test.TeardownScriptPath = teardownScriptPath + return b +} + +func (b *Builder) SetDefaultTimeout(defaultTimeout time.Duration) *Builder { + b.test.DefaultTimeout = defaultTimeout + return b +} + +func (b *Builder) SetDefaultConditions(defaultConditions []string) *Builder { + b.test.DefaultConditions = defaultConditions + return b +} + +func (b *Builder) SetSkipDelete(skipDelete bool) *Builder { + b.test.SkipDelete = skipDelete + return b +} + +func (b *Builder) SetSkipUpdate(skipUpdate bool) *Builder { + b.test.SkipUpdate = skipUpdate + return b +} + +func (b *Builder) SetSkipImport(skipImport bool) *Builder { + b.test.SkipImport = skipImport + return b +} + +func (b *Builder) SetOnlyCleanUptestResources(onlyCleanUptestResources bool) *Builder { + b.test.OnlyCleanUptestResources = onlyCleanUptestResources + return b +} + +func (b *Builder) SetRenderOnly(renderOnly bool) *Builder { + b.test.RenderOnly = renderOnly + return b +} + +func (b *Builder) SetLogCollectionInterval(logCollectionInterval time.Duration) *Builder { + b.test.LogCollectionInterval = logCollectionInterval + return b +} + +func (b *Builder) Build() *AutomatedTest { + return &b.test +} diff --git a/internal/prepare.go b/internal/prepare.go index 7e9d8e8..f9d6ff3 100644 --- a/internal/prepare.go +++ b/internal/prepare.go @@ -40,22 +40,22 @@ type injectedManifest struct { Manifest string } -type preparerOption func(*preparer) +type PreparerOption func(*Preparer) -func withDataSource(path string) preparerOption { - return func(p *preparer) { +func WithDataSource(path string) PreparerOption { + return func(p *Preparer) { p.dataSourcePath = path } } -func withTestDirectory(path string) preparerOption { - return func(p *preparer) { +func WithTestDirectory(path string) PreparerOption { + return func(p *Preparer) { p.testDirectory = path } } -func newPreparer(testFilePaths []string, opts ...preparerOption) *preparer { - p := &preparer{ +func NewPreparer(testFilePaths []string, opts ...PreparerOption) *Preparer { + p := &Preparer{ testFilePaths: testFilePaths, testDirectory: os.TempDir(), } @@ -65,14 +65,14 @@ func newPreparer(testFilePaths []string, opts ...preparerOption) *preparer { return p } -type preparer struct { +type Preparer struct { testFilePaths []string dataSourcePath string testDirectory string } //nolint:gocyclo // This function is not complex, gocyclo threshold was reached due to the error handling. -func (p *preparer) prepareManifests() ([]config.Manifest, error) { +func (p *Preparer) PrepareManifests() ([]config.Manifest, error) { caseDirectory := filepath.Join(p.testDirectory, caseDirectory) if err := os.RemoveAll(caseDirectory); err != nil { return nil, errors.Wrapf(err, "cannot clean directory %s", caseDirectory) @@ -117,7 +117,7 @@ func (p *preparer) prepareManifests() ([]config.Manifest, error) { return manifests, nil } -func (p *preparer) injectVariables() ([]injectedManifest, error) { +func (p *Preparer) injectVariables() ([]injectedManifest, error) { dataSourceMap := make(map[string]string) if p.dataSourcePath != "" { dataSource, err := os.ReadFile(p.dataSourcePath) @@ -143,7 +143,7 @@ func (p *preparer) injectVariables() ([]injectedManifest, error) { return inputs, nil } -func (p *preparer) injectValues(manifestData string, dataSourceMap map[string]string) string { +func (p *Preparer) injectValues(manifestData string, dataSourceMap map[string]string) string { // Inject data source values such as tenantID, objectID, accountID dataSourceKeys := dataSourceRegex.FindAllStringSubmatch(manifestData, -1) for _, dataSourceKey := range dataSourceKeys { diff --git a/internal/tester.go b/internal/tester.go index 676edd5..b03be3d 100644 --- a/internal/tester.go +++ b/internal/tester.go @@ -32,19 +32,19 @@ var testFiles = []string{ "03-delete.yaml", } -func newTester(ms []config.Manifest, opts *config.AutomatedTest) *tester { - return &tester{ +func NewTester(ms []config.Manifest, opts *config.AutomatedTest) *Tester { + return &Tester{ options: opts, manifests: ms, } } -type tester struct { +type Tester struct { options *config.AutomatedTest manifests []config.Manifest } -func (t *tester) executeTests() error { +func (t *Tester) ExecuteTests() error { if err := writeTestFile(t.manifests, t.options.Directory); err != nil { return errors.Wrap(err, "cannot write test manifest files") } @@ -74,7 +74,7 @@ func (t *tester) executeTests() error { return nil } -func executeSingleTestFile(t *tester, tf string, timeout time.Duration, resources []config.Resource) error { +func executeSingleTestFile(t *Tester, tf string, timeout time.Duration, resources []config.Resource) error { chainsawCommand := fmt.Sprintf(`"${CHAINSAW}" test --test-dir %s --test-file %s --skip-delete --parallel 1 2>&1`, filepath.Clean(filepath.Join(t.options.Directory, caseDirectory)), filepath.Clean(tf)) @@ -139,7 +139,7 @@ func logCollector(done chan bool, ticker *time.Ticker, mutex sync.Locker, resour } } -func (t *tester) prepareConfig() (*config.TestCase, []config.Resource, error) { //nolint:gocyclo // TODO: can we break this? +func (t *Tester) prepareConfig() (*config.TestCase, []config.Resource, error) { //nolint:gocyclo // TODO: can we break this? tc := &config.TestCase{ Timeout: t.options.DefaultTimeout, SetupScriptPath: t.options.SetupScriptPath, @@ -263,7 +263,7 @@ func (t *tester) prepareConfig() (*config.TestCase, []config.Resource, error) { return tc, examples, nil } -func (t *tester) writeChainsawFiles() ([]config.Resource, time.Duration, error) { +func (t *Tester) writeChainsawFiles() ([]config.Resource, time.Duration, error) { tc, examples, err := t.prepareConfig() if err != nil { return nil, 0, errors.Wrap(err, "cannot build examples config") diff --git a/internal/runner.go b/pkg/runner.go similarity index 63% rename from internal/runner.go rename to pkg/runner.go index 2538d78..bbecb08 100644 --- a/internal/runner.go +++ b/pkg/runner.go @@ -1,8 +1,4 @@ -// SPDX-FileCopyrightText: 2024 The Crossplane Authors -// -// SPDX-License-Identifier: CC0-1.0 - -package internal +package pkg import ( "log" @@ -10,6 +6,7 @@ import ( "github.com/crossplane/crossplane-runtime/pkg/errors" + "github.com/crossplane/uptest/internal" "github.com/crossplane/uptest/internal/config" ) @@ -24,15 +21,19 @@ func RunTest(o *config.AutomatedTest) error { } // Read examples and inject data source values to manifests - manifests, err := newPreparer(o.ManifestPaths, withDataSource(o.DataSourcePath), withTestDirectory(o.Directory)).prepareManifests() + manifests, err := internal.NewPreparer(o.ManifestPaths, internal.WithDataSource(o.DataSourcePath), internal.WithTestDirectory(o.Directory)).PrepareManifests() if err != nil { return errors.Wrap(err, "cannot prepare manifests") } // Prepare assert environment and run tests - if err := newTester(manifests, o).executeTests(); err != nil { + if err := internal.NewTester(manifests, o).ExecuteTests(); err != nil { return errors.Wrap(err, "cannot execute tests") } return nil } + +func NewAutomatedTestBuilder() *config.Builder { + return config.NewBuilder() +} From e379bca1360a70688aafae738034190a0006fa62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergen=20Yal=C3=A7=C4=B1n?= Date: Thu, 23 Jan 2025 18:35:41 +0300 Subject: [PATCH 2/3] Remove the setup script requirement for the apply step MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sergen Yalçın --- internal/templates/00-apply.yaml.tmpl | 4 +- internal/templates/renderer_test.go | 165 ++++++++++++++++++++++++++ 2 files changed, 167 insertions(+), 2 deletions(-) diff --git a/internal/templates/00-apply.yaml.tmpl b/internal/templates/00-apply.yaml.tmpl index 52697bb..e45988b 100644 --- a/internal/templates/00-apply.yaml.tmpl +++ b/internal/templates/00-apply.yaml.tmpl @@ -1,5 +1,4 @@ # This file belongs to the resource apply step. -{{ if .TestCase.SetupScriptPath -}} apiVersion: chainsaw.kyverno.io/v1alpha1 kind: Test metadata: @@ -10,11 +9,13 @@ spec: assert: {{ .TestCase.Timeout }} exec: {{ .TestCase.Timeout }} steps: + {{- if .TestCase.SetupScriptPath }} - name: Run Setup Script description: Setup the test environment by running the setup script. try: - command: entrypoint: {{ .TestCase.SetupScriptPath }} + {{- end }} - name: Apply Resources description: Apply resources to the cluster. try: @@ -64,4 +65,3 @@ spec: entrypoint: {{ $resource.PostAssertScriptPath }} {{- end }} {{- end }} -{{ end }} \ No newline at end of file diff --git a/internal/templates/renderer_test.go b/internal/templates/renderer_test.go index 6c6b7b7..219afd4 100644 --- a/internal/templates/renderer_test.go +++ b/internal/templates/renderer_test.go @@ -202,6 +202,171 @@ spec: "03-delete.yaml": `# This file belongs to the resource delete step. apiVersion: chainsaw.kyverno.io/v1alpha1 kind: Test +metadata: + name: delete +spec: + timeouts: + exec: 10m0s + steps: + - name: Delete Resources + description: Delete resources. If needs ordered deletion, the pre-delete scripts were used. + try: + - script: + content: | + ${KUBECTL} delete s3.aws.upbound.io/example-bucket --wait=false --ignore-not-found + - name: Assert Deletion + description: Assert deletion of resources. + try: + - wait: + apiVersion: bucket.s3.aws.upbound.io/v1alpha1 + kind: Bucket + name: example-bucket + for: + deletion: {} + - script: + content: | + ${KUBECTL} wait managed --all --for=delete --timeout -1s +`, + }, + }, + }, + "SuccessSingleResourceWithNoSetupScript": { + args: args{ + tc: &config.TestCase{ + Timeout: 10 * time.Minute, + TestDirectory: "/tmp/test-input.yaml", + }, + resources: []config.Resource{ + { + Name: "example-bucket", + APIVersion: "bucket.s3.aws.upbound.io/v1alpha1", + Kind: "Bucket", + KindGroup: "s3.aws.upbound.io", + YAML: bucketManifest, + Conditions: []string{"Test"}, + }, + }, + }, + want: want{ + out: map[string]string{ + "00-apply.yaml": `# This file belongs to the resource apply step. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: apply +spec: + timeouts: + apply: 10m0s + assert: 10m0s + exec: 10m0s + steps: + - name: Apply Resources + description: Apply resources to the cluster. + try: + - apply: + file: /tmp/test-input.yaml + - script: + content: | + echo "Runnning annotation script" + ${KUBECTL} annotate s3.aws.upbound.io/example-bucket upjet.upbound.io/test=true --overwrite + - name: Assert Status Conditions + description: | + Assert applied resources. First, run the pre-assert script if exists. + Then, check the status conditions. Finally run the post-assert script if it + exists. + try: + - assert: + resource: + apiVersion: bucket.s3.aws.upbound.io/v1alpha1 + kind: Bucket + metadata: + name: example-bucket + status: + ((conditions[?type == 'Test'])[0]): + status: "True" +`, + "01-update.yaml": `# This file belongs to the resource update step. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: update +spec: + timeouts: + apply: 10m0s + assert: 10m0s + exec: 10m0s + steps: + - name: Update Root Resource + description: | + Update the root resource by using the specified update-parameter in annotation. + Before updating the resources, the status conditions are cleaned. + try: + - name: Assert Updated Resource + description: | + Assert update operation. Firstly check the status conditions. Then assert + the updated field in status.atProvider. +`, + "02-import.yaml": `# This file belongs to the resource import step. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test +metadata: + name: import +spec: + timeouts: + apply: 10m0s + assert: 10m0s + exec: 10m0s + steps: + - name: Remove State + description: | + Removes the resource statuses from MRs and controllers. For controllers + the scale down&up was applied. For MRs status conditions are patched. + Also, for the assertion step, the ID before import was stored in the + uptest-old-id annotation. + try: + - script: + content: | + ${KUBECTL} annotate s3.aws.upbound.io/example-bucket crossplane.io/paused=true --overwrite + ${KUBECTL} scale deployment crossplane -n ${CROSSPLANE_NAMESPACE} --replicas=0 --timeout 10s + ${KUBECTL} -n ${CROSSPLANE_NAMESPACE} get deploy --no-headers -o custom-columns=":metadata.name" | grep "provider-" | xargs ${KUBECTL} -n ${CROSSPLANE_NAMESPACE} scale deploy --replicas=0 + - sleep: + duration: 10s + - script: + content: | + ${KUBECTL} scale deployment crossplane -n ${CROSSPLANE_NAMESPACE} --replicas=1 --timeout 10s + ${KUBECTL} -n ${CROSSPLANE_NAMESPACE} get deploy --no-headers -o custom-columns=":metadata.name" | grep "provider-" | xargs ${KUBECTL} -n ${CROSSPLANE_NAMESPACE} scale deploy --replicas=1 + curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/check_endpoints.sh -o /tmp/check_endpoints.sh && chmod +x /tmp/check_endpoints.sh + curl -sL https://raw.githubusercontent.com/crossplane/uptest/main/hack/patch.sh -o /tmp/patch.sh && chmod +x /tmp/patch.sh + /tmp/check_endpoints.sh + /tmp/patch.sh s3.aws.upbound.io example-bucket + ${KUBECTL} annotate s3.aws.upbound.io/example-bucket --all crossplane.io/paused=false --overwrite + - name: Assert Status Conditions and IDs + description: | + Assert imported resources. Firstly check the status conditions. Then + compare the stored ID and the new populated ID. For successful test, + the ID must be the same. + try: + - assert: + resource: + apiVersion: bucket.s3.aws.upbound.io/v1alpha1 + kind: Bucket + metadata: + name: example-bucket + status: + ((conditions[?type == 'Test'])[0]): + status: "True" + - assert: + timeout: 1m + resource: + apiVersion: bucket.s3.aws.upbound.io/v1alpha1 + kind: Bucket + metadata: + name: example-bucket + ("status.atProvider.id" == "metadata.annotations.uptest-old-id"): true +`, + "03-delete.yaml": `# This file belongs to the resource delete step. +apiVersion: chainsaw.kyverno.io/v1alpha1 +kind: Test metadata: name: delete spec: From 8ede9cdc4a686f8f7ea517970fac05dc2b39f51e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergen=20Yal=C3=A7=C4=B1n?= Date: Tue, 28 Jan 2025 13:59:10 +0300 Subject: [PATCH 3/3] Add code comments for exported packages MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sergen Yalçın --- internal/config/builder.go | 21 +++++++++++++++++++++ internal/prepare.go | 22 ++++++++++++++++++---- internal/tester.go | 4 ++++ pkg/runner.go | 6 ++++++ 4 files changed, 49 insertions(+), 4 deletions(-) diff --git a/internal/config/builder.go b/internal/config/builder.go index 43ec43a..d63e35f 100644 --- a/internal/config/builder.go +++ b/internal/config/builder.go @@ -1,84 +1,105 @@ +// SPDX-FileCopyrightText: 2025 The Crossplane Authors +// +// SPDX-License-Identifier: CC0-1.0 + +// Package config contains configuration options for configuring uptest runtime. package config import ( "time" ) +// Builder is a struct that helps construct an AutomatedTest instance step-by-step. type Builder struct { test AutomatedTest } +// NewBuilder initializes and returns a new Builder instance. func NewBuilder() *Builder { return &Builder{ test: AutomatedTest{}, } } +// SetDirectory sets the directory path for the AutomatedTest and returns the Builder. func (b *Builder) SetDirectory(directory string) *Builder { b.test.Directory = directory return b } +// SetManifestPaths sets the paths of the manifest files for the AutomatedTest and returns the Builder. func (b *Builder) SetManifestPaths(manifestPaths []string) *Builder { b.test.ManifestPaths = manifestPaths return b } +// SetDataSourcePath sets the data source path for the AutomatedTest and returns the Builder. func (b *Builder) SetDataSourcePath(dataSourcePath string) *Builder { b.test.DataSourcePath = dataSourcePath return b } +// SetSetupScriptPath sets the setup script path for the AutomatedTest and returns the Builder. func (b *Builder) SetSetupScriptPath(setupScriptPath string) *Builder { b.test.SetupScriptPath = setupScriptPath return b } +// SetTeardownScriptPath sets the teardown script path for the AutomatedTest and returns the Builder. func (b *Builder) SetTeardownScriptPath(teardownScriptPath string) *Builder { b.test.TeardownScriptPath = teardownScriptPath return b } +// SetDefaultTimeout sets the default timeout duration for the AutomatedTest and returns the Builder. func (b *Builder) SetDefaultTimeout(defaultTimeout time.Duration) *Builder { b.test.DefaultTimeout = defaultTimeout return b } +// SetDefaultConditions sets the default conditions for the AutomatedTest and returns the Builder. func (b *Builder) SetDefaultConditions(defaultConditions []string) *Builder { b.test.DefaultConditions = defaultConditions return b } +// SetSkipDelete sets whether the AutomatedTest should skip resource deletion and returns the Builder. func (b *Builder) SetSkipDelete(skipDelete bool) *Builder { b.test.SkipDelete = skipDelete return b } +// SetSkipUpdate sets whether the AutomatedTest should skip resource updates and returns the Builder. func (b *Builder) SetSkipUpdate(skipUpdate bool) *Builder { b.test.SkipUpdate = skipUpdate return b } +// SetSkipImport sets whether the AutomatedTest should skip resource imports and returns the Builder. func (b *Builder) SetSkipImport(skipImport bool) *Builder { b.test.SkipImport = skipImport return b } +// SetOnlyCleanUptestResources sets whether the AutomatedTest should clean up only test-specific resources and returns the Builder. func (b *Builder) SetOnlyCleanUptestResources(onlyCleanUptestResources bool) *Builder { b.test.OnlyCleanUptestResources = onlyCleanUptestResources return b } +// SetRenderOnly sets whether the AutomatedTest should only render outputs without execution and returns the Builder. func (b *Builder) SetRenderOnly(renderOnly bool) *Builder { b.test.RenderOnly = renderOnly return b } +// SetLogCollectionInterval sets the interval for log collection during the AutomatedTest and returns the Builder. func (b *Builder) SetLogCollectionInterval(logCollectionInterval time.Duration) *Builder { b.test.LogCollectionInterval = logCollectionInterval return b } +// Build finalizes and returns the constructed AutomatedTest instance. func (b *Builder) Build() *AutomatedTest { return &b.test } diff --git a/internal/prepare.go b/internal/prepare.go index f9d6ff3..ad57dd8 100644 --- a/internal/prepare.go +++ b/internal/prepare.go @@ -40,37 +40,51 @@ type injectedManifest struct { Manifest string } +// PreparerOption is a functional option type for configuring a Preparer. type PreparerOption func(*Preparer) +// WithDataSource is a functional option that sets the data source path for the Preparer. func WithDataSource(path string) PreparerOption { return func(p *Preparer) { p.dataSourcePath = path } } +// WithTestDirectory is a functional option that sets the test directory for the Preparer. func WithTestDirectory(path string) PreparerOption { return func(p *Preparer) { p.testDirectory = path } } +// NewPreparer creates a new Preparer instance with the provided test file paths and optional configurations. +// It applies any provided PreparerOption functions to customize the Preparer. func NewPreparer(testFilePaths []string, opts ...PreparerOption) *Preparer { p := &Preparer{ testFilePaths: testFilePaths, - testDirectory: os.TempDir(), + testDirectory: os.TempDir(), // Default test directory is the system's temporary directory. } + // Apply each provided option to configure the Preparer. for _, f := range opts { f(p) } return p } +// Preparer represents a structure used to prepare testing environments or configurations. type Preparer struct { - testFilePaths []string - dataSourcePath string - testDirectory string + testFilePaths []string // Paths to the test files. + dataSourcePath string // Path to the data source file. + testDirectory string // Directory where tests will be executed. } +// PrepareManifests prepares and processes manifests from test files. +// It performs the following steps: +// 1. Cleans and recreates the case directory. +// 2. Injects variables into test files. +// 3. Decodes, processes, and validates each manifest file, skipping any that require manual intervention. +// 4. Returns the processed manifests or an error if any step fails. +// //nolint:gocyclo // This function is not complex, gocyclo threshold was reached due to the error handling. func (p *Preparer) PrepareManifests() ([]config.Manifest, error) { caseDirectory := filepath.Join(p.testDirectory, caseDirectory) diff --git a/internal/tester.go b/internal/tester.go index b03be3d..c1e5e9b 100644 --- a/internal/tester.go +++ b/internal/tester.go @@ -32,6 +32,7 @@ var testFiles = []string{ "03-delete.yaml", } +// NewTester returns a Tester object. func NewTester(ms []config.Manifest, opts *config.AutomatedTest) *Tester { return &Tester{ options: opts, @@ -39,11 +40,14 @@ func NewTester(ms []config.Manifest, opts *config.AutomatedTest) *Tester { } } +// Tester is responsible preparing and storing the test data&configurations, +// and executing the tests. type Tester struct { options *config.AutomatedTest manifests []config.Manifest } +// ExecuteTests execute tests via chainsaw. func (t *Tester) ExecuteTests() error { if err := writeTestFile(t.manifests, t.options.Directory); err != nil { return errors.Wrap(err, "cannot write test manifest files") diff --git a/pkg/runner.go b/pkg/runner.go index bbecb08..1540174 100644 --- a/pkg/runner.go +++ b/pkg/runner.go @@ -1,3 +1,8 @@ +// SPDX-FileCopyrightText: 2025 The Crossplane Authors +// +// SPDX-License-Identifier: CC0-1.0 + +// Package pkg contains configuration options for configuring uptest runtime. package pkg import ( @@ -34,6 +39,7 @@ func RunTest(o *config.AutomatedTest) error { return nil } +// NewAutomatedTestBuilder returns a Builder for AutomatedTest object func NewAutomatedTestBuilder() *config.Builder { return config.NewBuilder() }