istio.io/pkg/test/istioio/builder.go

131 lines
3.5 KiB
Go

// Copyright Istio Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package istioio
import (
"fmt"
"os"
"path"
"path/filepath"
"strings"
"istio.io/istio/pkg/test/env"
"istio.io/istio/pkg/test/scopes"
"istio.io/istio/pkg/test/framework"
)
const (
snippetsFileExtension = ".snippets.txt"
snippetsFileHeaderFormat = `# Created by %s. DO NOT EDIT THIS FILE MANUALLY!
`
)
// Step builds a step of the test pipeline.
type Step interface {
// run this step.
run(ctx Context)
}
// Builder builds a test of a documented workflow from http://istio.io.
type Builder struct {
snippetsFileName string
steps []Step
cleanupSteps []Step
}
// NewBuilder returns an instance of an example test. The name of the snippets file must be provided.
// If the snippets file name does not end with ".snippets.txt", the extension will be appended automatically.
func NewBuilder(snippetsFileName string) *Builder {
if snippetsFileName == "" {
panic("must provide the snippets file name")
}
// Add the appropriate suffix if it's missing.
if !strings.HasSuffix(snippetsFileName, snippetsFileExtension) {
snippetsFileName += snippetsFileExtension
}
return &Builder{
snippetsFileName: snippetsFileName,
}
}
// Add a step to be run.
func (b *Builder) Add(steps ...Step) *Builder {
b.steps = append(b.steps, steps...)
return b
}
// Defer registers a function to be executed when the test completes.
func (b *Builder) Defer(steps ...Step) *Builder {
b.cleanupSteps = append(b.cleanupSteps, steps...)
return b
}
// BuildAndRun is a utility method for building and running the test function in one step.
func (b *Builder) BuildAndRun(ctx framework.TestContext) {
b.Build()(ctx)
}
// Build a run function for the test
func (b *Builder) Build() func(ctx framework.TestContext) {
return func(ctx framework.TestContext) {
scopes.CI.Infof("Executing test %s (%d steps)", ctx.Name(), len(b.steps))
snippetFile, err := os.Create(filepath.Join(ctx.WorkDir(), b.snippetsFileName))
if err != nil {
ctx.Fatalf("failed creating snippets file: %v", err)
}
defer func() { _ = snippetFile.Close() }()
// Write the header to the snippets file.
if _, err := snippetFile.WriteString(fmt.Sprintf(snippetsFileHeaderFormat, ctx.Name())); err != nil {
ctx.Fatalf("failed writing header to snippets file: %v", err)
}
eCtx := Context{
TestContext: ctx,
snippetFile: snippetFile,
snippetMap: make(map[string]string),
}
// create a symbolic link to samples/, for easy access
samplesSymlink := path.Join(ctx.WorkDir(), "samples")
if _, err := os.Stat(samplesSymlink); os.IsNotExist(err) {
err = os.Symlink(path.Join(env.IstioSrc, "samples"), samplesSymlink)
if err != nil {
scopes.CI.Warnf("Could not create symlink to samples/ directory at %s", samplesSymlink)
} else {
defer func() {
_ = os.Remove(samplesSymlink)
}()
}
}
// Run cleanup functions at the end.
defer func() {
for _, step := range b.cleanupSteps {
step.run(eCtx)
}
}()
for _, step := range b.steps {
step.run(eCtx)
}
}
}