mirror of https://github.com/fluxcd/flux2.git
Refactor test helpers
- move test helpers to main - add support for inline golden values - add test for `flux --version` Signed-off-by: Stefan Prodan <stefan.prodan@gmail.com>pull/1682/head
parent
2290880389
commit
dd0f17d7a5
@ -0,0 +1,158 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/fluxcd/flux2/internal/utils"
|
||||
"github.com/google/go-cmp/cmp"
|
||||
"github.com/mattn/go-shellwords"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
|
||||
"sigs.k8s.io/controller-runtime/pkg/client"
|
||||
fakeclient "sigs.k8s.io/controller-runtime/pkg/client/fake"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Ensure tests print consistent timestamps regardless of timezone
|
||||
os.Setenv("TZ", "UTC")
|
||||
}
|
||||
|
||||
func readYamlObjects(objectFile string) ([]client.Object, error) {
|
||||
obj, err := ioutil.ReadFile(objectFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objects := []client.Object{}
|
||||
reader := k8syaml.NewYAMLReader(bufio.NewReader(bytes.NewReader(obj)))
|
||||
for {
|
||||
doc, err := reader.Read()
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
unstructuredObj := &unstructured.Unstructured{}
|
||||
decoder := k8syaml.NewYAMLOrJSONDecoder(bytes.NewBuffer(doc), len(doc))
|
||||
err = decoder.Decode(unstructuredObj)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
objects = append(objects, unstructuredObj)
|
||||
}
|
||||
return objects, nil
|
||||
}
|
||||
|
||||
// A KubeManager that can create objects that are subject to a test.
|
||||
type fakeKubeManager struct {
|
||||
fakeClient client.Client
|
||||
}
|
||||
|
||||
func (m *fakeKubeManager) NewClient(kubeconfig string, kubecontext string) (client.Client, error) {
|
||||
return m.fakeClient, nil
|
||||
}
|
||||
|
||||
func (m *fakeKubeManager) CreateObjects(clientObjects []client.Object) error {
|
||||
for _, obj := range clientObjects {
|
||||
err := m.fakeClient.Create(context.Background(), obj)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func NewFakeKubeManager() *fakeKubeManager {
|
||||
c := fakeclient.NewClientBuilder().WithScheme(utils.NewScheme()).Build()
|
||||
return &fakeKubeManager{
|
||||
fakeClient: c,
|
||||
}
|
||||
}
|
||||
|
||||
// Run the command and return the captured output.
|
||||
func executeCommand(cmd string) (string, error) {
|
||||
args, err := shellwords.Parse(cmd)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
buf := new(bytes.Buffer)
|
||||
|
||||
rootCmd.SetOut(buf)
|
||||
rootCmd.SetErr(buf)
|
||||
rootCmd.SetArgs(args)
|
||||
|
||||
_, err = rootCmd.ExecuteC()
|
||||
result := buf.String()
|
||||
|
||||
return result, err
|
||||
}
|
||||
|
||||
// Structure used for each test to load objects into kubernetes, run
|
||||
// commands and assert on the expected output.
|
||||
type cmdTestCase struct {
|
||||
// The command line arguments to test.
|
||||
args string
|
||||
// When true, the test expects the command to fail.
|
||||
wantError bool
|
||||
// String literal that contains the expected test output.
|
||||
goldenValue string
|
||||
// Filename that contains the expected test output.
|
||||
goldenFile string
|
||||
// Filename that contains yaml objects to load into Kubernetes
|
||||
objectFile string
|
||||
}
|
||||
|
||||
func (cmd *cmdTestCase) runTestCmd(t *testing.T) {
|
||||
km := NewFakeKubeManager()
|
||||
rootCtx.kubeManager = km
|
||||
|
||||
if cmd.objectFile != "" {
|
||||
clientObjects, err := readYamlObjects(cmd.objectFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Error loading yaml: '%v'", err)
|
||||
}
|
||||
err = km.CreateObjects(clientObjects)
|
||||
if err != nil {
|
||||
t.Fatalf("Error creating test objects: '%v'", err)
|
||||
}
|
||||
}
|
||||
|
||||
actual, err := executeCommand(cmd.args)
|
||||
if (err != nil) != cmd.wantError {
|
||||
t.Fatalf("Expected error='%v', Got: %v", cmd.wantError, err)
|
||||
}
|
||||
if err != nil {
|
||||
actual = err.Error()
|
||||
}
|
||||
|
||||
var expected string
|
||||
if cmd.goldenValue != "" {
|
||||
expected = cmd.goldenValue
|
||||
}
|
||||
if cmd.goldenFile != "" {
|
||||
expectedOutput, err := ioutil.ReadFile(cmd.goldenFile)
|
||||
if err != nil {
|
||||
t.Fatalf("Error reading golden file: '%s'", err)
|
||||
}
|
||||
expected = string(expectedOutput)
|
||||
}
|
||||
|
||||
diff := cmp.Diff(expected, actual)
|
||||
if diff != "" {
|
||||
t.Errorf("Mismatch from '%s' (-want +got):\n%s", cmd.goldenFile, diff)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVersion(t *testing.T) {
|
||||
cmd := cmdTestCase{
|
||||
args: "--version",
|
||||
goldenValue: "flux version 0.0.0-dev.0\n",
|
||||
}
|
||||
cmd.runTestCmd(t)
|
||||
}
|
@ -1 +0,0 @@
|
||||
object name is required
|
Loading…
Reference in New Issue