Skip to content

Commit

Permalink
Merge pull request #38 from sergenyalcin/export-core-functionality
Browse files Browse the repository at this point in the history
Export core functionality of uptest
  • Loading branch information
sergenyalcin authored Jan 28, 2025
2 parents 3f59e12 + 8ede9cd commit 804bb75
Show file tree
Hide file tree
Showing 7 changed files with 342 additions and 46 deletions.
37 changes: 19 additions & 18 deletions cmd/uptest/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
Expand Down Expand Up @@ -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")
}
105 changes: 105 additions & 0 deletions internal/config/builder.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-FileCopyrightText: 2025 The Crossplane Authors <https://crossplane.io>
//
// 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
}
44 changes: 29 additions & 15 deletions internal/prepare.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,39 +40,53 @@ type injectedManifest struct {
Manifest string
}

type preparerOption func(*preparer)
// PreparerOption is a functional option type for configuring a Preparer.
type PreparerOption func(*Preparer)

func withDataSource(path string) preparerOption {
return func(p *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
}
}

func withTestDirectory(path string) preparerOption {
return func(p *preparer) {
// 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
}
}

func newPreparer(testFilePaths []string, opts ...preparerOption) *preparer {
p := &preparer{
// 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
}

type preparer struct {
testFilePaths []string
dataSourcePath string
testDirectory string
// Preparer represents a structure used to prepare testing environments or configurations.
type Preparer struct {
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) {
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)
Expand Down Expand Up @@ -117,7 +131,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)
Expand All @@ -143,7 +157,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 {
Expand Down
4 changes: 2 additions & 2 deletions internal/templates/00-apply.yaml.tmpl
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
# This file belongs to the resource apply step.
{{ if .TestCase.SetupScriptPath -}}
apiVersion: chainsaw.kyverno.io/v1alpha1
kind: Test
metadata:
Expand All @@ -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:
Expand Down Expand Up @@ -64,4 +65,3 @@ spec:
entrypoint: {{ $resource.PostAssertScriptPath }}
{{- end }}
{{- end }}
{{ end }}
Loading

0 comments on commit 804bb75

Please sign in to comment.