blob: 6aac22e36e35e16647bbc5c1021c9565790105cd [file] [edit]
// Copyright 2024 Google LLC
//
// 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
//
// https://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 run
import (
"context"
"fmt"
"reflect"
"strings"
"testing"
)
type command struct {
arguments []string
result string
shouldFail bool
}
// testRunner is a fake runner for testing, since with batch we are not really
// interested in testing the actual command execution but the layer on top of
// that (parsing command, processing template and sequencing execution) we can
// fake all test executions.
type testRunner struct {
commands []*command
}
func (tr *testRunner) findCommand(name string, args ...string) *command {
for _, curr := range tr.commands {
if reflect.DeepEqual(curr.arguments, append([]string{name}, args...)) {
return curr
}
}
return nil
}
func (tr *testRunner) WithContext(ctx context.Context, opts Options) (*Result, error) {
cmd := tr.findCommand(opts.Name, opts.Args...)
if cmd == nil {
return nil, fmt.Errorf("command %s not found", opts.Name)
}
if cmd.shouldFail {
return nil, fmt.Errorf("command %s should fail", opts.Name)
}
return &Result{Output: cmd.result, OutputType: OutputCombined}, nil
}
func prepareTest(t *testing.T) *testRunner {
t.Helper()
result := &testRunner{}
defaultClient := Client
Client = result
t.Cleanup(func() {
Client = defaultClient
})
return result
}
func TestCommandSpecSuccess(t *testing.T) {
type commandData struct {
Data string
}
tests := []struct {
name string
spec CommandSpec
data commandData
command string
}{
{
name: "success_echo_data",
spec: CommandSpec{"echo {{.Data}}", "failed to echo {{.Data}}"},
data: commandData{"foobar"},
command: "echo foobar",
},
{
name: "success_cat_data",
spec: CommandSpec{"cat {{.Data}}", "failed to cat file {{.Data}}"},
data: commandData{"/proc/cpuinfo"},
command: "cat /proc/cpuinfo",
},
{
name: "success_echo_foobar_data",
spec: CommandSpec{"echo 'foobar' >> {{.Data}}", "failed to write to file {{.Data}}"},
data: commandData{"/tmp/file.data"},
command: "echo 'foobar' >> /tmp/file.data",
},
}
testRunner := prepareTest(t)
for _, curr := range tests {
testRunner.commands = append(testRunner.commands, &command{
arguments: strings.Split(curr.command, " "),
shouldFail: false,
})
}
for _, curr := range tests {
t.Run(curr.name, func(t *testing.T) {
if err := curr.spec.WithContext(context.Background(), curr.data); err != nil {
t.Errorf("RunQuiet(%v) = %v, want: nil", curr.data, err)
}
})
}
}
func TestCommandSpecFailure(t *testing.T) {
type commandData struct {
Data string
}
tests := []struct {
name string
spec CommandSpec
data commandData
command string
result string
internalError error
}{
{
name: "empty_command",
spec: CommandSpec{"", "failed to echo {{.Data}}"},
data: commandData{"foobar"},
internalError: ErrCommandTemplate,
},
{
name: "invalid_field",
spec: CommandSpec{"invalid field {{.UnknownField}}", "failed to echo {{.Data}}"},
data: commandData{"foobar"},
internalError: ErrCommandTemplate,
},
{
name: "invalid_template",
spec: CommandSpec{"echo {{.Data}}", "invalid data {{.UnknownField}}"},
data: commandData{"foobar"},
command: "echo foobar",
internalError: ErrTemplateError,
},
{
name: "invalid_data_command",
spec: CommandSpec{"echoxx {{.Data}}", "invalid data {{.Data}}"},
data: commandData{"foobar"},
command: "echoxx foobar",
result: "invalid data foobar",
},
}
for _, curr := range tests {
t.Run(curr.name, func(t *testing.T) {
err := curr.spec.WithContext(context.Background(), curr.data)
if curr.internalError != nil && err != curr.internalError {
t.Errorf("RunQuiet(%v) = %v, want: %v", curr.data, err, curr.internalError)
} else if err == nil {
t.Errorf("RunQuiet(%v) = %v, want: non-nil", curr.data, err)
}
})
}
}