From 266ed4b5151fc060b63bd95b4d4bf01ffb151c10 Mon Sep 17 00:00:00 2001 From: Martin Mulholland Date: Mon, 14 Dec 2020 14:00:08 -0500 Subject: [PATCH 1/8] Add parser tests part 1 --- go.mod | 1 + go.sum | 1 + tests/src/tests/README.md | 231 +++++++++++++++ tests/src/tests/command_test_utils.go | 256 ++++++++++++++++ tests/src/tests/component_test_utils.go | 228 +++++++++++++++ tests/src/tests/endpoint-test-utils.go | 59 ++++ tests/src/tests/parser_v200_verify_test.go | 278 ++++++++++++++++++ tests/src/tests/project_test_utils.go | 10 + tests/src/tests/test_utils.go | 324 +++++++++++++++++++++ 9 files changed, 1388 insertions(+) create mode 100644 tests/src/tests/README.md create mode 100644 tests/src/tests/command_test_utils.go create mode 100644 tests/src/tests/component_test_utils.go create mode 100644 tests/src/tests/endpoint-test-utils.go create mode 100644 tests/src/tests/parser_v200_verify_test.go create mode 100644 tests/src/tests/project_test_utils.go create mode 100644 tests/src/tests/test_utils.go diff --git a/go.mod b/go.mod index 7537dcf1..7d41e82c 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,7 @@ require ( github.com/fatih/color v1.7.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 github.com/gobwas/glob v0.2.3 + github.com/google/go-cmp v0.4.0 github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 github.com/mattn/go-colorable v0.1.2 // indirect diff --git a/go.sum b/go.sum index 68bd42ff..7993348d 100644 --- a/go.sum +++ b/go.sum @@ -158,6 +158,7 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= diff --git a/tests/src/tests/README.md b/tests/src/tests/README.md new file mode 100644 index 00000000..3c665b91 --- /dev/null +++ b/tests/src/tests/README.md @@ -0,0 +1,231 @@ +# Devfile Parser Library Tests + +## About + +The tests use the go language and are intended to test every apsect of the parser for every schema attribute. Some basic aspects of the tests: + +* A first test (parser_v200_schema_test.go) feeds pre-created devfiles to the parser to ensure the parser can parse all attribues and return an approproate error when the devfile contains an error. +* A second set of tests (parser_v200_verify_test.go) create devfile content at runtime: + * Devfile content is randomly generated and as a result the tests are designed to run multiple times. + * Parser functions covered: + * Read an existing devfile. + * Write a new devfile. + * Modify Content of a devfile. + * Multi-threaded access to the parser. + * The tests use the devfile schema to create a structure containing expected content for a devfile. These structures are compared with those returned by the parser. + * sigs.k8s.io/yaml is used to write out devfiles. + * github.com/google/go-cmp/cmp is used to compare structures. + +## Current tests: + +The tests using pre-created devfiles are complete (but update in progress due to schema changes) + +The tests which generate devfiles with random content at run time currently cover the following properties and items. + +* Commands: + * Exec + * Composite +* Components + * Container + * Volume + +## Running the tests + +1. Go to directory tests/src/tests +1. Run ```go test``` or ```go test -v``` +1. The test creates the following files: + 1. ```./tmp/test.log``` contains log output from the tests. + 1. ```./tmp/parser_v200_verify_test/Test_*.yaml``` are the devfiles which are randomly generated at runtime. The file name matches the name of the test function which resulted in them being created. + 1. ```./tmp/parser_v200_schema_test/*.yaml``` are the pre-created devfiles. + 1. If a test detects an error when compariing properties returned by the parser with expected properties + * ```./tmp/parser_v200_schema_test/Test_*__Parser.yaml``` - property as returned by the parser + * ```./tmp/parser_v200_schema_test/Test_*__Test.yaml``` - property as expected by the test + +Note: each run of the test removes the existing conents of the ```./tmp``` directory + +## Anatomy of parser_v200_verify_test.go test + +Each test in ```parser_v200_verify_test.go``` sets values in a test structure which defines the test to run (additions will new made for new properties as support is added): + + type TestContent struct { + CommandTypes []schema.CommandType + ComponentTypes []schema.ComponentType + FileName string + CreateWithParser bool + EditContent bool + } + + +The test then uses one (or both) of two functions to run a test + +* For a single thread test: + * ```func runTest(testContent TestContent, t *testing.T)``` +* For a multi-thread test: + * ```func runMultiThreadTest(testContent TestContent, t *testing.T)``` + +An example test: + + func Test_MultiCommand(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType, schema.CompositeCommandType} + testContent.CreateWithParser = true + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) + } + +Note: ```GetDevFileName()``` is a function which returns the name of a temporary file to create which uses the name of the test file as a subdirectory and the name of test function function as file name. In this example it returns ```./tmp/parser_v200_verify_test/Test_MultiCommand``` + +There are also some constants which control execution of the tests: + + const numThreads = 5 // Number of threads used by multi-thread tests + const maxCommands = 10 // The maximum number of commands to include in a generated devfile + const maxComponents = 10 // The maximum number of components to include in a generated devfile + +## Basic principles of the tests which randomly generates devfiles + +* Each devfile is created in a schema structure. +* Which attributes are set and the values used are randomized. +* Once the schema structure is complete it is written in one of two ways. + * using the sigs.k8s.io/yaml. + * using the parser. +* Once the devfile is created on disk the parser is used to read and validate it. +* If editing the devfile + * each object is retrieved, modified and written back to the parser + * the parser is used to write the devfile to disk + * the parser is then used to read and validate the modified devfile. +* Each array of objects in then devfile are then retrieved from the parser and compared. If this fails: + * Each object returned by the parser is compared to the equivalent object tracked in the test. + * if the obejcts do not match the test fails + * Files are output with the content of each object. + * If the parser returns more or fewer objects than expected, the test fails. + +## Updating tests + +### Files +* ```parser_v200_verify_test.go``` contains the tests +* ```test-utils.go``` provides property agnostic functions for use by the tests and other utils +* ```-test-utils.go``` for example ```command-test-utils.go```, provides property related functions + +### Adding, modifying attributes of existing properties. + +In the ```-test-utils.go``` files there are: +* ```setValues``` functions. + * for example in ```command-test-utils.go``` : + * ```func setExecCommandValues(execCommand *schema.ExecCommand)``` + * ```func setCompositeCommandValues(compositeCommand *schema.CompositeCommand)``` +* These may use utility functions to set more complex attributes. +* Modify these functions to add/modify test for new/changed attributes. + +### Add new item to an existing property. + +For example add support for apply command to existing command support: + +1. In ```command-test-utils.go``` + * add functions: + * ```func createApplyCommand() *schema.ApplyCommand``` + * creates the apply command object and calls setApplyCommandValues to add attribute values + * ```func setApplyCommandValues(applyCommand *schema.ApplyCommand)``` + * randomly set attribute values in the provided apply command object + * follow the implementation of other similar functions. + * modify: + * ```func generateCommand(command *schema.Command, genericCommand *GenericCommand)``` + * add logic to call createApplyCommand if commandType indicates such. + * ```func (devfile *TestDevfile) UpdateCommand(command *schema.Command) error``` + * add logic to call setApplyCommandValues if commandType indicates such. +1. In ```parser_v200_verify_test.go``` + * add new tests. for example: + * Test_ApplyCommand - CreateWithParser set to false, EditContent set to false + * Test_CreateApplyCommand - CreateWithParser set to true, EditContent set to false + * Test_EditApplyCommand - CreateWithParser set to false, EditContent set to true + * Test_CreateEditApplyCommand - CreateWithParser set to true, EditContent set to true + * modify existing test to include Apply commands + * Test_MultiCommand + * Test_Everything + +### Add new property + +Using existing support for commands as an illustration, any new property support added should follow the same structure: + +1. ```command-test-utils.go```: + * Specific to commands + * Commands require support for 5 different command types: + * Exec + * Appy (to be implemented) + * Composite + * VSCodeLaunch (to be implemented) + * VSCodeTask (to be implemented) + * Each of these command-types have equivalent functions: + * ```func createCommand() *schema.``` + * creates the command object and calls ```setCommandValues``` to add attribute values + * for example see: ```func createExecCommand(execCommand *schema.ExecCommand)``` + * ```func setCommandValues(project-sourceProject *schema.)``` + * sets random attributes into the provided object + * for example see: ```func setExecCommandValues(execCommand *schema.ExecCommand)``` + * Functions general to all commands + * ```func (devfile *TestDevfile) addCommand(commandType schema.CommandType) string``` + * main entry point for a test to add a command + * maintains the array of commands in the schema structure + * calls generateCommand() + * ```func generateCommand(command *schema.Command, genericCommand *GenericCommand)``` + * includes logic to call the ```createCommand``` function for the command-Type of the supplied command object. + * ```func (devfile *TestDevfile) UpdateCommand(command *schema.Command) error``` + * includes logic to call setCommandValues for each commandType. + * ```func (devfile TestDevfile) VerifyCommands(parserCommands []schema.Command) error``` + * Includes logic to compare the array of commands obtained from the parser with those created by the test. if the compare fails: + * each individual command is compared. + * if a command compare fails, the parser version and test version of the command are oputput as yaml files to the tmp directory + * a check is made to determine if the parser returned a command not known to the test or the pasrer omitted a command expected by the test. +1. ```test-utils.go``` + * ```func (devfile TestDevfile) Verify()``` + * Includes code to get object from the paser and verify their content. + * For commands code is required to: + 1. Retrieve each command from the parser + 1. Use command id to obtain the GenericCommand object which matches + 1. compare the command structure returned by the parser with the command structure saved in the GenericCommand object. + * ```func (devfile TestDevfile) EditCommands() error``` + * Specific to command objects. + 1. Ensure devfile is written to disk + 1. use parser to read devfile and get all command object + 1. for each command call: + * ```func (devfile *TestDevfile) UpdateCommand(command *schema.Command) error``` + 1. when all commands have been updated, use parser to write the updated devfile to disk +1. ```parser-v200-test.go``` + * ```type TestContent struct``` + * includes an array of command types: ```CommandTypes []schema.CommandType``` + * ```func Test_ExecCommand(t *testing.T)``` + 1. Creates a TestContent object + 1. Adds a single entry array containg schema.ExecCommandType to the array of command types + 1. Calls runTest for a single thread test + 1. Calls runMultiThreadTest for a multi-thread test. + * See also + *```func Test_ExecCommand(t *testing.T)``` + *```func Test_MultiCommand(t *testing.T)``` + *```func Test_Everything(t *testing.T)``` + * add logic to ```func runTest(testContent TestContent, t *testing.T)``` includes logic + 1. Add commands to the test + 2. Starts edits of commands if required. + + +#### Code flow + +Create, modify and verify an exec command: +1. parser_v200_verify_test.Test_ExecCommand + 1. parser-v200-test.runTest + 1. command-test-utils.AddCommand + 1. command-test-utils.GenerateCommand + 1. command-test-utils.createExecCommand + 1. command-test-utils.setExecCommandValues + 1. test-utils.CreateDevfile + 1. test-utils.EditCommands + 1. command-test-utils.UpdateCommand + 1. command-test-utils.setExecCommandValues + 1. test-utils.Verify + 1. command-test-utils.VerifyCommands + + + + + + diff --git a/tests/src/tests/command_test_utils.go b/tests/src/tests/command_test_utils.go new file mode 100644 index 00000000..fd468674 --- /dev/null +++ b/tests/src/tests/command_test_utils.go @@ -0,0 +1,256 @@ +package tests + +import ( + "errors" + "fmt" + "io/ioutil" + + "github.com/google/go-cmp/cmp" + "sigs.k8s.io/yaml" + + schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +func AddEnv(numEnv int) []schema.EnvVar { + commandEnvs := make([]schema.EnvVar, numEnv) + for i := 0; i < numEnv; i++ { + commandEnvs[i].Name = "Name_" + GetRandomString(5, false) + commandEnvs[i].Value = "Value_" + GetRandomString(5, false) + LogMessage(fmt.Sprintf(" ....... Add Env: %s", commandEnvs[i])) + } + return commandEnvs +} + +func AddAttributes(numAtrributes int) map[string]string { + attributes := make(map[string]string) + for i := 0; i < numAtrributes; i++ { + AttributeName := "Name_" + GetRandomString(6, false) + attributes[AttributeName] = "Value_" + GetRandomString(6, false) + LogMessage(fmt.Sprintf(" ....... Add attribute : %s = %s", AttributeName, attributes[AttributeName])) + } + return attributes +} + +func addGroup() *schema.CommandGroup { + + commandGroup := schema.CommandGroup{} + + commandGroup.Kind = GetRandomGroupKind() + LogMessage(fmt.Sprintf(" ....... group Kind: %s", commandGroup.Kind)) + commandGroup.IsDefault = GetBinaryDecision() + LogMessage(fmt.Sprintf(" ....... group isDefault: %t", commandGroup.IsDefault)) + + return &commandGroup +} + +func (devfile *TestDevfile) addCommand(commandType schema.CommandType) string { + + var commands []schema.Command + index := 0 + if devfile.SchemaDevFile.Commands != nil { + // Commands already exist so expand the current slice + currentSize := len(devfile.SchemaDevFile.Commands) + commands = make([]schema.Command, currentSize+1) + for _, command := range devfile.SchemaDevFile.Commands { + commands[index] = command + index++ + } + } else { + commands = make([]schema.Command, 1) + } + + generateCommand(&commands[index], commandType) + devfile.SchemaDevFile.Commands = commands + + return commands[index].Id + +} + +func generateCommand(command *schema.Command, commandType schema.CommandType) { + command.Id = GetRandomUniqueString(8, true) + LogMessage(fmt.Sprintf(" ....... id: %s", command.Id)) + + if commandType == schema.ExecCommandType { + command.Exec = createExecCommand() + } else if commandType == schema.CompositeCommandType { + command.Composite = createCompositeCommand() + } +} + +func (devfile *TestDevfile) UpdateCommand(parserCommand *schema.Command) error { + + errorString := "" + testCommand, found := getSchemaCommand(devfile.SchemaDevFile.Commands, parserCommand.Id) + if found { + LogMessage(fmt.Sprintf(" ....... Updating command id: %s", parserCommand.Id)) + if testCommand.Exec != nil { + setExecCommandValues(parserCommand.Exec) + } else if testCommand.Composite != nil { + setCompositeCommandValues(parserCommand.Composite) + } + devfile.replaceSchemaCommand(*parserCommand) + } else { + errorString += LogMessage(fmt.Sprintf(" ....... Command not found in test : %s", parserCommand.Id)) + } + + var err error + if errorString != "" { + err = errors.New(errorString) + } + return err +} + +func createExecCommand() *schema.ExecCommand { + + LogMessage("Create an exec command :") + + execCommand := schema.ExecCommand{} + + setExecCommandValues(&execCommand) + + return &execCommand + +} + +func setExecCommandValues(execCommand *schema.ExecCommand) { + + execCommand.Component = GetRandomString(8, false) + LogMessage(fmt.Sprintf(" ....... component: %s", execCommand.Component)) + + execCommand.CommandLine = GetRandomString(4, false) + " " + GetRandomString(4, false) + LogMessage(fmt.Sprintf(" ....... commandLine: %s", execCommand.CommandLine)) + + if GetRandomDecision(2, 1) { + execCommand.Group = addGroup() + } else { + execCommand.Group = nil + } + + if GetBinaryDecision() { + execCommand.Label = GetRandomString(12, false) + LogMessage(fmt.Sprintf(" ....... label: %s", execCommand.Label)) + } else { + execCommand.Label = "" + } + + if GetBinaryDecision() { + execCommand.WorkingDir = "./tmp" + LogMessage(fmt.Sprintf(" ....... WorkingDir: %s", execCommand.WorkingDir)) + } else { + execCommand.WorkingDir = "" + } + + execCommand.HotReloadCapable = GetBinaryDecision() + LogMessage(fmt.Sprintf(" ....... HotReloadCapable: %t", execCommand.HotReloadCapable)) + + if GetBinaryDecision() { + execCommand.Env = AddEnv(GetRandomNumber(4)) + } else { + execCommand.Env = nil + } + +} + +func (devfile TestDevfile) replaceSchemaCommand(command schema.Command) { + for i := 0; i < len(devfile.SchemaDevFile.Commands); i++ { + if devfile.SchemaDevFile.Commands[i].Id == command.Id { + devfile.SchemaDevFile.Commands[i] = command + break + } + } +} + +func getSchemaCommand(commands []schema.Command, id string) (*schema.Command, bool) { + found := false + var schemaCommand schema.Command + for _, command := range commands { + if command.Id == id { + schemaCommand = command + found = true + break + } + } + return &schemaCommand, found +} + +func createCompositeCommand() *schema.CompositeCommand { + + compositeCommand := schema.CompositeCommand{} + + setCompositeCommandValues(&compositeCommand) + + return &compositeCommand +} + +func setCompositeCommandValues(compositeCommand *schema.CompositeCommand) { + numCommands := GetRandomNumber(3) + + compositeCommand.Commands = make([]string, numCommands) + for i := 0; i < numCommands; i++ { + compositeCommand.Commands[i] = GetRandomUniqueString(8, false) + LogMessage(fmt.Sprintf(" ....... command %d of %d : %s", i, numCommands, compositeCommand.Commands[i])) + } + + if GetRandomDecision(2, 1) { + compositeCommand.Group = addGroup() + } + + if GetBinaryDecision() { + compositeCommand.Label = GetRandomString(12, false) + LogMessage(fmt.Sprintf(" ....... label: %s", compositeCommand.Label)) + } + + if GetBinaryDecision() { + compositeCommand.Parallel = true + LogMessage(fmt.Sprintf(" ....... Parallel: %t", compositeCommand.Parallel)) + } +} + +func (devfile TestDevfile) VerifyCommands(parserCommands []schema.Command) error { + + LogMessage("Enter VerifyCommands") + errorString := "" + + // Compare entire array of commands + if !cmp.Equal(parserCommands, devfile.SchemaDevFile.Commands) { + errorString += LogMessage(fmt.Sprintf(" --> ERROR: Command array compare failed.")) + // Array compare failed. Narrow down by comparing indivdual commands + for _, command := range parserCommands { + if testCommand, found := getSchemaCommand(devfile.SchemaDevFile.Commands, command.Id); found { + if !cmp.Equal(command, *testCommand) { + parserFilename := AddSuffixToFileName(devfile.FileName, "_"+command.Id+"_Parser") + testFilename := AddSuffixToFileName(devfile.FileName, "_"+command.Id+"_Test") + LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", devfile.FileName)) + c, err := yaml.Marshal(command) + if err == nil { + err = ioutil.WriteFile(parserFilename, c, 0644) + } + LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", devfile.FileName)) + c, err = yaml.Marshal(testCommand) + if err == nil { + err = ioutil.WriteFile(testFilename, c, 0644) + } + errorString += LogMessage(fmt.Sprintf(" --> ERROR: Command %s did not match, see files : %s and %s", command.Id, parserFilename, testFilename)) + } else { + LogMessage(fmt.Sprintf(" --> Command matched : %s", command.Id)) + } + } else { + errorString += LogMessage(fmt.Sprintf(" --> ERROR: Command from parser not known to test - id : %s ", command.Id)) + } + + } + for _, command := range devfile.SchemaDevFile.Commands { + if _, found := getSchemaCommand(parserCommands, command.Id); !found { + errorString += LogMessage(fmt.Sprintf(" --> ERROR: Command from test not returned by parser : %s ", command.Id)) + } + } + } else { + LogMessage(fmt.Sprintf(" --> Command structures matched")) + } + + var err error + if errorString != "" { + err = errors.New(errorString) + } + return err +} diff --git a/tests/src/tests/component_test_utils.go b/tests/src/tests/component_test_utils.go new file mode 100644 index 00000000..d7262c55 --- /dev/null +++ b/tests/src/tests/component_test_utils.go @@ -0,0 +1,228 @@ +package tests + +import ( + "errors" + "fmt" + "io/ioutil" + "strconv" + + schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + "github.com/google/go-cmp/cmp" + "sigs.k8s.io/yaml" +) + +func AddVolume(numVols int) []schema.VolumeMount { + commandVols := make([]schema.VolumeMount, numVols) + for i := 0; i < numVols; i++ { + commandVols[i].Name = "Name_" + GetRandomString(5, false) + commandVols[i].Path = "/Path_" + GetRandomString(5, false) + LogMessage(fmt.Sprintf(" ....... Add Volume: %s", commandVols[i])) + } + return commandVols +} + +func getSchemaComponent(components []schema.Component, name string) (*schema.Component, bool) { + found := false + var schemaComponent schema.Component + for _, component := range components { + if component.Name == name { + schemaComponent = component + found = true + break + } + } + return &schemaComponent, found +} + +func (devfile *TestDevfile) AddComponent(componentType schema.ComponentType) string { + + var components []schema.Component + index := 0 + if devfile.SchemaDevFile.Components != nil { + // Commands already exist so expand the current slice + currentSize := len(devfile.SchemaDevFile.Components) + components = make([]schema.Component, currentSize+1) + for _, component := range devfile.SchemaDevFile.Components { + components[index] = component + index++ + } + } else { + components = make([]schema.Component, 1) + } + + generateComponent(&components[index], componentType) + devfile.SchemaDevFile.Components = components + + return components[index].Name + +} + +func generateComponent(component *schema.Component, componentType schema.ComponentType) { + + component.Name = GetRandomUniqueString(8, true) + LogMessage(fmt.Sprintf(" ....... Name: %s", component.Name)) + + if componentType == schema.ContainerComponentType { + component.Container = createContainerComponent() + } else if componentType == schema.VolumeComponentType { + component.Volume = createVolumeComponent() + } +} + +func createContainerComponent() *schema.ContainerComponent { + + LogMessage("Create a container component :") + + containerComponent := schema.ContainerComponent{} + setContainerComponentValues(&containerComponent) + + return &containerComponent + +} + +func createVolumeComponent() *schema.VolumeComponent { + + LogMessage("Create a volume component :") + + volumeComponent := schema.VolumeComponent{} + setVolumeComponentValues(&volumeComponent) + + return &volumeComponent + +} + +func setContainerComponentValues(containerComponent *schema.ContainerComponent) { + + containerComponent.Image = GetRandomUniqueString(8+GetRandomNumber(10), false) + + if GetBinaryDecision() { + numCommands := GetRandomNumber(3) + containerComponent.Command = make([]string, numCommands) + for i := 0; i < numCommands; i++ { + containerComponent.Command[i] = GetRandomString(4+GetRandomNumber(10), false) + LogMessage(fmt.Sprintf(" ....... command %d of %d : %s", i, numCommands, containerComponent.Command[i])) + } + } + + if GetBinaryDecision() { + numArgs := GetRandomNumber(3) + containerComponent.Args = make([]string, numArgs) + for i := 0; i < numArgs; i++ { + containerComponent.Args[i] = GetRandomString(8+GetRandomNumber(10), false) + LogMessage(fmt.Sprintf(" ....... arg %d of %d : %s", i, numArgs, containerComponent.Args[i])) + } + } + + containerComponent.DedicatedPod = GetBinaryDecision() + LogMessage(fmt.Sprintf(" ....... DedicatedPod: %t", containerComponent.DedicatedPod)) + + if GetBinaryDecision() { + containerComponent.MemoryLimit = strconv.Itoa(4+GetRandomNumber(124)) + "M" + LogMessage(fmt.Sprintf(" ....... MemoryLimit: %s", containerComponent.MemoryLimit)) + } + + if GetBinaryDecision() { + setMountSources := GetBinaryDecision() + containerComponent.MountSources = &setMountSources + LogMessage(fmt.Sprintf(" ....... MountSources: %t", *containerComponent.MountSources)) + + if setMountSources { + containerComponent.SourceMapping = "/" + GetRandomString(8, false) + LogMessage(fmt.Sprintf(" ....... SourceMapping: %s", containerComponent.SourceMapping)) + } + } + + if GetBinaryDecision() { + containerComponent.Env = AddEnv(GetRandomNumber(4)) + } else { + containerComponent.Env = nil + } + + if GetBinaryDecision() { + containerComponent.VolumeMounts = AddVolume(GetRandomNumber(4)) + } else { + containerComponent.Env = nil + } + + if GetBinaryDecision() { + containerComponent.Endpoints = CreateEndpoints() + } + +} + +func setVolumeComponentValues(volumeComponent *schema.VolumeComponent) { + + if GetRandomDecision(5, 1) { + volumeComponent.Size = strconv.Itoa(4+GetRandomNumber(252)) + "G" + LogMessage(fmt.Sprintf(" ....... volumeComponent.Size: %s", volumeComponent.Size)) + } + +} + +func (devfile *TestDevfile) UpdateComponent(component *schema.Component) error { + + errorString := "" + testComponent, found := getSchemaComponent(devfile.SchemaDevFile.Components, component.Name) + if found { + LogMessage(fmt.Sprintf(" ....... Updating component name: %s", component.Name)) + if testComponent.ComponentType == schema.ContainerComponentType { + setContainerComponentValues(component.Container) + } else if testComponent.ComponentType == schema.VolumeComponentType { + setVolumeComponentValues(component.Volume) + } + } else { + errorString += LogMessage(fmt.Sprintf(" ....... Component not found in test : %s", component.Name)) + } + var err error + if errorString != "" { + err = errors.New(errorString) + } + return err +} + +func (devfile TestDevfile) VerifyComponents(parserComponents []schema.Component) error { + + LogMessage("Enter VerifyComponents") + errorString := "" + + // Compare entire array of commands + if !cmp.Equal(parserComponents, devfile.SchemaDevFile.Components) { + errorString += LogMessage(fmt.Sprintf(" --> ERROR: Component array compare failed.")) + for _, component := range parserComponents { + if testComponent, found := getSchemaComponent(devfile.SchemaDevFile.Components, component.Name); found { + if !cmp.Equal(component, *testComponent) { + parserFilename := AddSuffixToFileName(devfile.FileName, "_"+component.Name+"_Parser") + testFilename := AddSuffixToFileName(devfile.FileName, "_"+component.Name+"_Test") + LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", parserFilename)) + c, err := yaml.Marshal(component) + if err == nil { + err = ioutil.WriteFile(parserFilename, c, 0644) + } + LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", testFilename)) + c, err = yaml.Marshal(testComponent) + if err == nil { + err = ioutil.WriteFile(testFilename, c, 0644) + } + errorString += LogMessage(fmt.Sprintf(" --> ERROR: Component %s did not match, see files : %s and %s", component.Name, parserFilename, testFilename)) + } else { + LogMessage(fmt.Sprintf(" --> Component matched : %s", component.Name)) + } + } else { + errorString += LogMessage(fmt.Sprintf(" --> ERROR: Component from parser not known to test - id : %s ", component.Name)) + } + } + for _, component := range devfile.SchemaDevFile.Components { + if _, found := getSchemaComponent(parserComponents, component.Name); !found { + errorString += LogMessage(fmt.Sprintf(" --> ERROR: Component from test not returned by parser : %s ", component.Name)) + } + } + } else { + LogMessage(fmt.Sprintf(" --> Component structures matched")) + } + + var err error + if errorString != "" { + err = errors.New(errorString) + } + return err +} diff --git a/tests/src/tests/endpoint-test-utils.go b/tests/src/tests/endpoint-test-utils.go new file mode 100644 index 00000000..ad5f62a7 --- /dev/null +++ b/tests/src/tests/endpoint-test-utils.go @@ -0,0 +1,59 @@ +package tests + +import ( + "fmt" + + schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +var Exposures = [...]schema.EndpointExposure{schema.PublicEndpointExposure, schema.InternalEndpointExposure, schema.NoneEndpointExposure} + +func GetRandomExposure() schema.EndpointExposure { + return Exposures[GetRandomNumber(len(Exposures))-1] +} + +var Protocols = [...]schema.EndpointProtocol{schema.HTTPEndpointProtocol, schema.WSEndpointProtocol, schema.TCPEndpointProtocol, schema.UDPEndpointProtocol} + +func GetRandomProtocol() schema.EndpointProtocol { + return Protocols[GetRandomNumber(len(Protocols))-1] +} + +func CreateEndpoints() []schema.Endpoint { + + numEndpoints := GetRandomNumber(5) + endpoints := make([]schema.Endpoint, numEndpoints) + + for i := 0; i < numEndpoints; i++ { + + endpoint := schema.Endpoint{} + + endpoint.Name = GetRandomString(GetRandomNumber(15)+5, false) + LogMessage(fmt.Sprintf(" ....... add endpoint %d name : %s", i, endpoint.Name)) + + endpoint.TargetPort = GetRandomNumber(9999) + LogMessage(fmt.Sprintf(" ....... add endpoint %d targetPort: %d", i, endpoint.TargetPort)) + + if GetBinaryDecision() { + endpoint.Exposure = GetRandomExposure() + LogMessage(fmt.Sprintf(" ....... add endpoint %d exposure: %s", i, endpoint.Exposure)) + } + + if GetBinaryDecision() { + endpoint.Protocol = GetRandomProtocol() + LogMessage(fmt.Sprintf(" ....... add endpoint %d protocol: %s", i, endpoint.Protocol)) + } + + endpoint.Secure = GetBinaryDecision() + LogMessage(fmt.Sprintf(" ....... add endpoint %d secure: %t", i, endpoint.Secure)) + + if GetBinaryDecision() { + endpoint.Path = "/Path_" + GetRandomString(GetRandomNumber(10)+3, false) + LogMessage(fmt.Sprintf(" ....... add endpoint %d path: %s", i, endpoint.Path)) + } + + endpoints[i] = endpoint + + } + + return endpoints +} diff --git a/tests/src/tests/parser_v200_verify_test.go b/tests/src/tests/parser_v200_verify_test.go new file mode 100644 index 00000000..a0ccb18f --- /dev/null +++ b/tests/src/tests/parser_v200_verify_test.go @@ -0,0 +1,278 @@ +package tests + +import ( + "fmt" + "strconv" + "testing" + "time" + + schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +const numThreads = 5 // Number of threads used by multi-thread tests +const maxCommands = 10 // The maximum number of commands to include in a generated devfile +const maxComponents = 10 // The maximum number of components to include in a generated devfile + +type TestContent struct { + CommandTypes []schema.CommandType + ComponentTypes []schema.ComponentType + FileName string + CreateWithParser bool + EditContent bool +} + +func Test_ExecCommand(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType} + testContent.CreateWithParser = false + testContent.EditContent = false + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} +func Test_ExecCommandEdit(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType} + testContent.CreateWithParser = false + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_ExecCommandParserCreate(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType} + testContent.CreateWithParser = true + testContent.EditContent = false + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_ExecCommandEditParserCreate(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType} + testContent.CreateWithParser = true + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_CompositeCommand(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.CompositeCommandType} + testContent.CreateWithParser = false + testContent.EditContent = false + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} +func Test_CompositeCommandEdit(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.CompositeCommandType} + testContent.CreateWithParser = false + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_CompositeCommandParserCreate(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.CompositeCommandType} + testContent.CreateWithParser = true + testContent.EditContent = false + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_CompositeCommandEditParserCreate(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.CompositeCommandType} + testContent.CreateWithParser = true + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_MultiCommand(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType, schema.CompositeCommandType} + testContent.CreateWithParser = true + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_ContainerComponent(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType} + testContent.CreateWithParser = false + testContent.EditContent = false + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_ContainerComponentEdit(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType} + testContent.CreateWithParser = false + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_ContainerComponentCreateWithParser(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType} + testContent.CreateWithParser = true + testContent.EditContent = false + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_ContainerComponentEditCreateWithParser(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType} + testContent.CreateWithParser = true + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_VolumeComponent(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.VolumeComponentType} + testContent.CreateWithParser = false + testContent.EditContent = false + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_VolumeComponentEdit(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.VolumeComponentType} + testContent.CreateWithParser = false + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_VolumeComponentCreateWithParser(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.VolumeComponentType} + testContent.CreateWithParser = true + testContent.EditContent = false + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_VolumeComponentEditCreateWithParser(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.VolumeComponentType} + testContent.CreateWithParser = true + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_MultiComponent(t *testing.T) { + testContent := TestContent{} + testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType, schema.VolumeComponentType} + testContent.CreateWithParser = true + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func Test_Everything(t *testing.T) { + testContent := TestContent{} + testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType, schema.CompositeCommandType} + testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType, schema.VolumeComponentType} + testContent.CreateWithParser = true + testContent.EditContent = true + testContent.FileName = GetDevFileName() + runTest(testContent, t) + runMultiThreadTest(testContent, t) +} + +func runMultiThreadTest(testContent TestContent, t *testing.T) { + + LogMessage(fmt.Sprintf("Start Threaded test for %s", testContent.FileName)) + + devfileName := testContent.FileName + var i int + for i = 1; i < numThreads; i++ { + testContent.FileName = AddSuffixToFileName(devfileName, strconv.Itoa(i)) + go runTest(testContent, t) + } + testContent.FileName = AddSuffixToFileName(devfileName, strconv.Itoa(i)) + runTest(testContent, t) + + LogMessage(fmt.Sprintf("Sleep 2 seconds to allow all threads to complete : %s", devfileName)) + time.Sleep(2 * time.Second) + LogMessage(fmt.Sprintf("Sleep complete : %s", devfileName)) + +} + +func runTest(testContent TestContent, t *testing.T) { + + LogMessage(fmt.Sprintf("Start test for %s", testContent.FileName)) + testDevfile := GetDevfile(testContent.FileName) + + if len(testContent.CommandTypes) > 0 { + numCommands := GetRandomNumber(maxCommands) + for i := 0; i < numCommands; i++ { + commandIndex := GetRandomNumber(len(testContent.CommandTypes)) + testDevfile.addCommand(testContent.CommandTypes[commandIndex-1]) + } + } + + if len(testContent.ComponentTypes) > 0 { + numComponents := GetRandomNumber(maxComponents) + for i := 0; i < numComponents; i++ { + componentIndex := GetRandomNumber(len(testContent.ComponentTypes)) + testDevfile.AddComponent(testContent.ComponentTypes[componentIndex-1]) + } + } + + err := testDevfile.CreateDevfile(testContent.CreateWithParser) + if err != nil { + t.Fatalf(LogMessage(fmt.Sprintf("ERROR creating devfile : %s : %v", testContent.FileName, err))) + } + + if testContent.EditContent { + if len(testContent.CommandTypes) > 0 { + err = testDevfile.EditCommands() + if err != nil { + t.Fatalf(LogMessage(fmt.Sprintf("ERROR editing commands : %s : %v", testContent.FileName, err))) + } + } + if len(testContent.ComponentTypes) > 0 { + err = testDevfile.EditComponents() + if err != nil { + t.Fatalf(LogMessage(fmt.Sprintf("ERROR editing components : %s : %v", testContent.FileName, err))) + } + } + } + + err = testDevfile.Verify() + if err != nil { + t.Fatalf(LogMessage(fmt.Sprintf("ERROR verifying devfile content : %s : %v", testContent.FileName, err))) + } + +} diff --git a/tests/src/tests/project_test_utils.go b/tests/src/tests/project_test_utils.go new file mode 100644 index 00000000..34beca88 --- /dev/null +++ b/tests/src/tests/project_test_utils.go @@ -0,0 +1,10 @@ +package tests + +import ( + schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" +) + +type GenericProject struct { + Name string + Project *schema.Project +} diff --git a/tests/src/tests/test_utils.go b/tests/src/tests/test_utils.go new file mode 100644 index 00000000..67509ebd --- /dev/null +++ b/tests/src/tests/test_utils.go @@ -0,0 +1,324 @@ +package tests + +import ( + "fmt" + "io" + "io/ioutil" + "log" + "math/rand" + "os" + "path/filepath" + "runtime" + "strings" + "time" + + schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" + devfilepkg "github.com/devfile/library/pkg/devfile" + "github.com/devfile/library/pkg/devfile/parser" + devfileCtx "github.com/devfile/library/pkg/devfile/parser/context" + devfileData "github.com/devfile/library/pkg/devfile/parser/data" + "github.com/devfile/library/pkg/devfile/parser/data/v2/common" + "sigs.k8s.io/yaml" +) + +const tmpDir = "./tmp/" +const logErrorOnly = false +const logFileName = "test.log" +const logToFileOnly = true // If set to false the log output will also be output to the console + +var ( + testLogger *log.Logger +) + +func init() { + if _, err := os.Stat(tmpDir); !os.IsNotExist(err) { + os.RemoveAll(tmpDir) + } + os.Mkdir(tmpDir, 0755) + + f, err := os.OpenFile(filepath.Join(tmpDir, logFileName), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + fmt.Printf("Error creating Log file : %v", err) + } else { + if logToFileOnly { + testLogger = log.New(f, "", log.LstdFlags|log.Lmicroseconds) + } else { + writer := io.MultiWriter(f, os.Stdout) + testLogger = log.New(writer, "", log.LstdFlags|log.Lmicroseconds) + } + testLogger.Println("Test Starting:") + } +} + +func GetTempDir() string { + _, fn, _, ok := runtime.Caller(1) + if !ok { + return tmpDir + } + testFile := filepath.Base(fn) + testFileExtension := filepath.Ext(testFile) + subdir := testFile[0 : len(testFile)-len(testFileExtension)] + return CreateTempDir(subdir) +} + +func CreateTempDir(subdir string) string { + tempDir := tmpDir + subdir + "/" + if _, err := os.Stat(tempDir); os.IsNotExist(err) { + os.Mkdir(tempDir, 0755) + } + return tempDir +} + +func GetDevFileName() string { + pc, fn, _, ok := runtime.Caller(1) + if !ok { + return tmpDir + "DefaultDevfile" + } + + testFile := filepath.Base(fn) + testFileExtension := filepath.Ext(testFile) + subdir := testFile[0 : len(testFile)-len(testFileExtension)] + destDir := CreateTempDir(subdir) + callerName := runtime.FuncForPC(pc).Name() + + pos1 := strings.LastIndex(callerName, "/tests.") + len("/tests.") + devfileName := destDir + callerName[pos1:len(callerName)] + ".yaml" + + LogMessage(fmt.Sprintf("GetDevFileName : %s", devfileName)) + + return devfileName +} + +func AddSuffixToFileName(fileName string, suffix string) string { + pos1 := strings.LastIndex(fileName, ".yaml") + newFileName := fileName[0:pos1] + suffix + ".yaml" + LogMessage(fmt.Sprintf("Add suffix %s to fileName %s : %s", suffix, fileName, newFileName)) + return newFileName +} + +func LogMessage(message string) string { + testLogger.Println(message) + return message +} + +type TestDevfile struct { + SchemaDevFile schema.Devfile + FileName string + ParsedSchemaObj parser.DevfileObj + SchemaParsed bool +} + +var StringCount int = 0 + +var RndSeed int64 = time.Now().UnixNano() + +func GetRandomUniqueString(n int, lower bool) string { + StringCount++ + return fmt.Sprintf("%s%04d", GetRandomString(n, lower), StringCount) +} + +func setRandSeed() { + RndSeed++ + rand.Seed(RndSeed) +} + +const schemaBytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + +func GetRandomString(n int, lower bool) string { + setRandSeed() + b := make([]byte, n) + for i := range b { + b[i] = schemaBytes[rand.Intn(len(schemaBytes)-1)] + } + randomString := string(b) + if lower { + randomString = strings.ToLower(randomString) + } + return randomString +} + +func GetGroupKinds() []schema.CommandGroupKind { + setRandSeed() + return []schema.CommandGroupKind{schema.BuildCommandGroupKind, schema.RunCommandGroupKind, schema.TestCommandGroupKind, schema.DebugCommandGroupKind} +} + +func GetRandomGroupKind() schema.CommandGroupKind { + setRandSeed() + return GetGroupKinds()[rand.Intn(len(GetGroupKinds()))] +} + +func GetBinaryDecision() bool { + return GetRandomDecision(1, 1) +} + +func GetRandomDecision(success int, failure int) bool { + setRandSeed() + return rand.Intn(success+failure) > failure-1 +} + +func GetRandomNumber(max int) int { + setRandSeed() + return rand.Intn(max) + 1 +} + +func GetDevfile(fileName string) TestDevfile { + testDevfile := TestDevfile{} + testDevfile.SchemaDevFile = schema.Devfile{} + testDevfile.FileName = fileName + testDevfile.SchemaDevFile.SchemaVersion = "2.0.0" + testDevfile.SchemaParsed = false + return testDevfile +} + +func (devfile *TestDevfile) CreateDevfile(useParser bool) error { + var err error + + fileName := devfile.FileName + if !strings.HasSuffix(fileName, ".yaml") { + fileName += ".yaml" + } + + if useParser { + LogMessage(fmt.Sprintf(" .......use Parser to write devfile %s", fileName)) + newDevfile, err := devfileData.NewDevfileData(devfile.SchemaDevFile.SchemaVersion) + if err != nil { + LogMessage(fmt.Sprintf(" ..... ERROR: creating new devfile : %v", err)) + } else { + newDevfile.SetSchemaVersion(devfile.SchemaDevFile.SchemaVersion) + + // add the commands to new devfile + for _, command := range devfile.SchemaDevFile.Commands { + newDevfile.AddCommands(command) + } + // add components to the new devfile + newDevfile.AddComponents(devfile.SchemaDevFile.Components) + + ctx := devfileCtx.NewDevfileCtx(fileName) + + err = ctx.SetAbsPath() + if err != nil { + LogMessage(fmt.Sprintf(" ..... ERROR: setting devfile path : %v", err)) + } else { + devObj := parser.DevfileObj{ + Ctx: ctx, + Data: newDevfile, + } + err = devObj.WriteYamlDevfile() + if err != nil { + LogMessage(fmt.Sprintf(" ..... ERROR: wriring devfile : %v", err)) + } + } + + } + } else { + LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", devfile.FileName)) + c, err := yaml.Marshal(&(devfile.SchemaDevFile)) + + if err == nil { + err = ioutil.WriteFile(fileName, c, 0644) + } + } + if err == nil { + devfile.SchemaParsed = false + } + return err +} + +func (devfile *TestDevfile) ParseSchema() error { + + var err error + if !devfile.SchemaParsed { + LogMessage(fmt.Sprintf(" -> Parse and Validate %s : ", devfile.FileName)) + devfile.ParsedSchemaObj, err = devfilepkg.ParseAndValidate(devfile.FileName) + if err != nil { + LogMessage(fmt.Sprintf(" ......ERROR from ParseAndValidate %v : ", err)) + } + devfile.SchemaParsed = true + } + return err +} + +func (devfile TestDevfile) Verify() error { + + LogMessage(fmt.Sprintf("Verify %s : ", devfile.FileName)) + + err := devfile.ParseSchema() + + if err == nil { + LogMessage(fmt.Sprintf(" -> Get commands %s : ", devfile.FileName)) + commands, _ := devfile.ParsedSchemaObj.Data.GetCommands(common.DevfileOptions{}) + if commands != nil && len(commands) > 0 { + err = devfile.VerifyCommands(commands) + } else { + LogMessage(fmt.Sprintf(" No command found in %s : ", devfile.FileName)) + } + } + + if err == nil { + LogMessage(fmt.Sprintf(" -> Get components %s : ", devfile.FileName)) + components, _ := devfile.ParsedSchemaObj.Data.GetComponents(common.DevfileOptions{}) + if components != nil && len(components) > 0 { + err = devfile.VerifyComponents(components) + } else { + LogMessage(fmt.Sprintf(" No components found in %s : ", devfile.FileName)) + } + } + + return err + +} + +func (devfile TestDevfile) EditCommands() error { + + LogMessage(fmt.Sprintf("Edit %s : ", devfile.FileName)) + + err := devfile.ParseSchema() + if err == nil { + LogMessage(fmt.Sprintf(" -> Get commands %s : ", devfile.FileName)) + commands, _ := devfile.ParsedSchemaObj.Data.GetCommands(common.DevfileOptions{}) + for _, command := range commands { + err = devfile.UpdateCommand(&command) + if err != nil { + LogMessage(fmt.Sprintf(" ..... ERROR: updating command : %v", err)) + } else { + LogMessage(fmt.Sprintf(" ..... Update command in Parser : %s", command.Id)) + devfile.ParsedSchemaObj.Data.UpdateCommand(command) + } + } + LogMessage(fmt.Sprintf(" ..... Write updated file to yaml : %s", devfile.FileName)) + devfile.ParsedSchemaObj.WriteYamlDevfile() + devfile.SchemaParsed = false + + } else { + LogMessage(fmt.Sprintf(" ..... ERROR: from parser : %v", err)) + } + return err + +} + +func (devfile TestDevfile) EditComponents() error { + + LogMessage(fmt.Sprintf("Edit %s : ", devfile.FileName)) + + err := devfile.ParseSchema() + if err == nil { + LogMessage(fmt.Sprintf(" -> Get commands %s : ", devfile.FileName)) + components, _ := devfile.ParsedSchemaObj.Data.GetComponents(common.DevfileOptions{}) + for _, component := range components { + err = devfile.UpdateComponent(&component) + if err != nil { + LogMessage(fmt.Sprintf(" ..... ERROR: updating component : %v", err)) + } else { + LogMessage(fmt.Sprintf(" ..... Update component in Parser : %s", component.Name)) + devfile.ParsedSchemaObj.Data.UpdateComponent(component) + } + } + LogMessage(fmt.Sprintf(" ..... Write updated file to yaml : %s", devfile.FileName)) + devfile.ParsedSchemaObj.WriteYamlDevfile() + devfile.SchemaParsed = false + } else { + LogMessage(fmt.Sprintf(" ..... ERROR: from parser : %v", err)) + } + return err + +} From 6e3def7a88ec6be4222f3a425d736537b58e0d3d Mon Sep 17 00:00:00 2001 From: Martin Mulholland Date: Mon, 14 Dec 2020 15:31:49 -0500 Subject: [PATCH 2/8] go.sum update --- go.sum | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/go.sum b/go.sum index 7993348d..b494c01a 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devfile/api v0.0.0-20201211221100-a68230324c7e h1:Jy3C3ul05YvL4bJpAVhFwPZD8neOJUBZy7GuCcjc8nc= -github.com/devfile/api v0.0.0-20201211221100-a68230324c7e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY= +github.com/devfile/api v0.0.0-20201126204309-ec222215253e h1:NO6mS8ktVFjkVIKZKF2JjfL3ZxXw4VAtKIZWyp9e2kQ= +github.com/devfile/api v0.0.0-20201126204309-ec222215253e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= @@ -158,7 +158,6 @@ github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMyw github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.4 h1:L8R9j+yAqZuZjsqh/z+F1NCffTKKLShY6zXTItVIZ8M= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= From 84990029eaae42a692053edd4cdb640f62d28a5b Mon Sep 17 00:00:00 2001 From: Martin Mulholland Date: Wed, 16 Dec 2020 16:14:19 -0500 Subject: [PATCH 3/8] output gofmt error --- .github/workflows/go.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index f1e9664d..aeb3f189 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -41,6 +41,6 @@ jobs: make gofmt if [[ ! -z $(git status -s) ]] then - echo "not well formatted sources are found" + echo "not well formatted sources are found : $(git status -s)" exit 1 fi From 04669ad48775fbce6117a31e6477f7c0004b797e Mon Sep 17 00:00:00 2001 From: Martin Mulholland Date: Wed, 16 Dec 2020 16:17:43 -0500 Subject: [PATCH 4/8] output gofmt error --- .github/workflows/go.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index aeb3f189..fac2bcfe 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -33,9 +33,6 @@ jobs: - name: Build Binary run: make bin - - name: Run Go Tests - run: make test - - name: Check format run: | make gofmt @@ -44,3 +41,6 @@ jobs: echo "not well formatted sources are found : $(git status -s)" exit 1 fi + + - name: Run Go Tests + run: make test From c9ea73ab941ec1378b9fa0009f1444a815e923d2 Mon Sep 17 00:00:00 2001 From: Martin Mulholland Date: Mon, 4 Jan 2021 13:22:14 -0500 Subject: [PATCH 5/8] Address pull request comments --- .gitignore | 3 +++ go.sum | 4 ++-- tests/src/tests/README.md | 46 +++++++++++++++++++++------------------ 3 files changed, 30 insertions(+), 23 deletions(-) diff --git a/.gitignore b/.gitignore index 83bf67aa..1bd4b352 100644 --- a/.gitignore +++ b/.gitignore @@ -18,4 +18,7 @@ main # Files used for debugging .vscode/ +# File created running tests +tests/src/tests/tmp/ + .DS_Store diff --git a/go.sum b/go.sum index b494c01a..68bd42ff 100644 --- a/go.sum +++ b/go.sum @@ -44,8 +44,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/devfile/api v0.0.0-20201126204309-ec222215253e h1:NO6mS8ktVFjkVIKZKF2JjfL3ZxXw4VAtKIZWyp9e2kQ= -github.com/devfile/api v0.0.0-20201126204309-ec222215253e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY= +github.com/devfile/api v0.0.0-20201211221100-a68230324c7e h1:Jy3C3ul05YvL4bJpAVhFwPZD8neOJUBZy7GuCcjc8nc= +github.com/devfile/api v0.0.0-20201211221100-a68230324c7e/go.mod h1:/aDiwWjDEW/fY1/Ig8umVtmneAXKZImnLvWqzMlcfrY= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/docker/docker v0.7.3-0.20190327010347-be7ac8be2ae0/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= diff --git a/tests/src/tests/README.md b/tests/src/tests/README.md index 3c665b91..58f4e399 100644 --- a/tests/src/tests/README.md +++ b/tests/src/tests/README.md @@ -10,7 +10,7 @@ The tests use the go language and are intended to test every apsect of the parse * Parser functions covered: * Read an existing devfile. * Write a new devfile. - * Modify Content of a devfile. + * Modify content of a devfile. * Multi-threaded access to the parser. * The tests use the devfile schema to create a structure containing expected content for a devfile. These structures are compared with those returned by the parser. * sigs.k8s.io/yaml is used to write out devfiles. @@ -87,6 +87,10 @@ There are also some constants which control execution of the tests: * Each devfile is created in a schema structure. * Which attributes are set and the values used are randomized. + * For example, the number of commands included in a devfile is randomly generated. + * For example, attribute values are set to randomized strings, numbers or binary. + * For example, a particular optional attribute has a 50% chance of being uncluded in a devfiles. + * Repeated tests give more variety and wider coverage. * Once the schema structure is complete it is written in one of two ways. * using the sigs.k8s.io/yaml. * using the parser. @@ -124,10 +128,10 @@ For example add support for apply command to existing command support: 1. In ```command-test-utils.go``` * add functions: - * ```func createApplyCommand() *schema.ApplyCommand``` - * creates the apply command object and calls setApplyCommandValues to add attribute values * ```func setApplyCommandValues(applyCommand *schema.ApplyCommand)``` * randomly set attribute values in the provided apply command object + * ```func createApplyCommand() *schema.ApplyCommand``` + * creates the apply command object and calls setApplyCommandValues to add attribute values * follow the implementation of other similar functions. * modify: * ```func generateCommand(command *schema.Command, genericCommand *GenericCommand)``` @@ -164,33 +168,33 @@ Using existing support for commands as an illustration, any new property support * sets random attributes into the provided object * for example see: ```func setExecCommandValues(execCommand *schema.ExecCommand)``` * Functions general to all commands + * ```func generateCommand(command *schema.Command, genericCommand *GenericCommand)``` + * includes logic to call the ```createCommand``` function for the command-Type of the supplied command object. * ```func (devfile *TestDevfile) addCommand(commandType schema.CommandType) string``` * main entry point for a test to add a command * maintains the array of commands in the schema structure * calls generateCommand() - * ```func generateCommand(command *schema.Command, genericCommand *GenericCommand)``` - * includes logic to call the ```createCommand``` function for the command-Type of the supplied command object. * ```func (devfile *TestDevfile) UpdateCommand(command *schema.Command) error``` * includes logic to call setCommandValues for each commandType. * ```func (devfile TestDevfile) VerifyCommands(parserCommands []schema.Command) error``` - * Includes logic to compare the array of commands obtained from the parser with those created by the test. if the compare fails: + * includes logic to compare the array of commands obtained from the parser with those created by the test. if the compare fails: * each individual command is compared. * if a command compare fails, the parser version and test version of the command are oputput as yaml files to the tmp directory * a check is made to determine if the parser returned a command not known to the test or the pasrer omitted a command expected by the test. 1. ```test-utils.go``` * ```func (devfile TestDevfile) Verify()``` - * Includes code to get object from the paser and verify their content. - * For commands code is required to: + * includes code to get object from the paser and verify their content. + * for commands code is required to: 1. Retrieve each command from the parser - 1. Use command id to obtain the GenericCommand object which matches - 1. compare the command structure returned by the parser with the command structure saved in the GenericCommand object. + 1. Use command Id to obtain the GenericCommand object which matches + 1. Compare the command structure returned by the parser with the command structure saved in the GenericCommand object. * ```func (devfile TestDevfile) EditCommands() error``` - * Specific to command objects. + * specific to command objects. 1. Ensure devfile is written to disk - 1. use parser to read devfile and get all command object - 1. for each command call: + 1. Use parser to read devfile and get all command object + 1. For each command call: * ```func (devfile *TestDevfile) UpdateCommand(command *schema.Command) error``` - 1. when all commands have been updated, use parser to write the updated devfile to disk + 1. When all commands have been updated, use parser to write the updated devfile to disk 1. ```parser-v200-test.go``` * ```type TestContent struct``` * includes an array of command types: ```CommandTypes []schema.CommandType``` @@ -200,12 +204,12 @@ Using existing support for commands as an illustration, any new property support 1. Calls runTest for a single thread test 1. Calls runMultiThreadTest for a multi-thread test. * See also - *```func Test_ExecCommand(t *testing.T)``` - *```func Test_MultiCommand(t *testing.T)``` - *```func Test_Everything(t *testing.T)``` - * add logic to ```func runTest(testContent TestContent, t *testing.T)``` includes logic - 1. Add commands to the test - 2. Starts edits of commands if required. + * ```func Test_ExecCommand(t *testing.T)``` + * ```func Test_MultiCommand(t *testing.T)``` + * ```func Test_Everything(t *testing.T)``` + * Add logic to ```func runTest(testContent TestContent, t *testing.T)``` + 1. Add commands to the test. + 2. Start edits of commands if required. #### Code flow @@ -215,7 +219,7 @@ Create, modify and verify an exec command: 1. parser-v200-test.runTest 1. command-test-utils.AddCommand 1. command-test-utils.GenerateCommand - 1. command-test-utils.createExecCommand + 1. command-test-utils.createExecCommand 1. command-test-utils.setExecCommandValues 1. test-utils.CreateDevfile 1. test-utils.EditCommands From ad9fecd2b41f07d54913b88dfd62a3eca1bbc593 Mon Sep 17 00:00:00 2001 From: Martin Mulholland Date: Tue, 5 Jan 2021 17:17:30 -0500 Subject: [PATCH 6/8] Address 2nd set of code review comments --- tests/src/tests/command_test_utils.go | 128 +++++++++-------- tests/src/tests/component_test_utils.go | 111 +++++++------- tests/src/tests/endpoint-test-utils.go | 16 ++- tests/src/tests/parser_v200_verify_test.go | 8 +- tests/src/tests/test_utils.go | 160 +++++++++++++++------ 5 files changed, 252 insertions(+), 171 deletions(-) diff --git a/tests/src/tests/command_test_utils.go b/tests/src/tests/command_test_utils.go index fd468674..60817883 100644 --- a/tests/src/tests/command_test_utils.go +++ b/tests/src/tests/command_test_utils.go @@ -11,78 +11,67 @@ import ( schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) +// Return a specifed number of env attributes in a schema structure func AddEnv(numEnv int) []schema.EnvVar { commandEnvs := make([]schema.EnvVar, numEnv) for i := 0; i < numEnv; i++ { commandEnvs[i].Name = "Name_" + GetRandomString(5, false) commandEnvs[i].Value = "Value_" + GetRandomString(5, false) - LogMessage(fmt.Sprintf(" ....... Add Env: %s", commandEnvs[i])) + LogInfoMessage(fmt.Sprintf("Add Env: %s", commandEnvs[i])) } return commandEnvs } +// Return a specifed number of attributes in a schema structure func AddAttributes(numAtrributes int) map[string]string { attributes := make(map[string]string) for i := 0; i < numAtrributes; i++ { AttributeName := "Name_" + GetRandomString(6, false) attributes[AttributeName] = "Value_" + GetRandomString(6, false) - LogMessage(fmt.Sprintf(" ....... Add attribute : %s = %s", AttributeName, attributes[AttributeName])) + LogInfoMessage(fmt.Sprintf("Add attribute : %s = %s", AttributeName, attributes[AttributeName])) } return attributes } +// Create and return a group in a schema structure func addGroup() *schema.CommandGroup { commandGroup := schema.CommandGroup{} - commandGroup.Kind = GetRandomGroupKind() - LogMessage(fmt.Sprintf(" ....... group Kind: %s", commandGroup.Kind)) + LogInfoMessage(fmt.Sprintf("group Kind: %s", commandGroup.Kind)) commandGroup.IsDefault = GetBinaryDecision() - LogMessage(fmt.Sprintf(" ....... group isDefault: %t", commandGroup.IsDefault)) - + LogInfoMessage(fmt.Sprintf("group isDefault: %t", commandGroup.IsDefault)) return &commandGroup } +// Add a command of the specified type to the schema func (devfile *TestDevfile) addCommand(commandType schema.CommandType) string { - - var commands []schema.Command - index := 0 - if devfile.SchemaDevFile.Commands != nil { - // Commands already exist so expand the current slice - currentSize := len(devfile.SchemaDevFile.Commands) - commands = make([]schema.Command, currentSize+1) - for _, command := range devfile.SchemaDevFile.Commands { - commands[index] = command - index++ - } - } else { - commands = make([]schema.Command, 1) - } - - generateCommand(&commands[index], commandType) - devfile.SchemaDevFile.Commands = commands - - return commands[index].Id - + command := generateCommand(commandType) + devfile.SchemaDevFile.Commands = append(devfile.SchemaDevFile.Commands, command) + return command.Id } -func generateCommand(command *schema.Command, commandType schema.CommandType) { +// Create a command of a specified type in a schema structure +func generateCommand(commandType schema.CommandType) schema.Command { + command := schema.Command{} command.Id = GetRandomUniqueString(8, true) - LogMessage(fmt.Sprintf(" ....... id: %s", command.Id)) + LogInfoMessage(fmt.Sprintf("command Id: %s", command.Id)) if commandType == schema.ExecCommandType { command.Exec = createExecCommand() } else if commandType == schema.CompositeCommandType { command.Composite = createCompositeCommand() } + return command } +// Update the values of a specified command func (devfile *TestDevfile) UpdateCommand(parserCommand *schema.Command) error { - errorString := "" + var errorString []string testCommand, found := getSchemaCommand(devfile.SchemaDevFile.Commands, parserCommand.Id) if found { - LogMessage(fmt.Sprintf(" ....... Updating command id: %s", parserCommand.Id)) + LogInfoMessage(fmt.Sprintf("Updating command id: %s", parserCommand.Id)) if testCommand.Exec != nil { setExecCommandValues(parserCommand.Exec) } else if testCommand.Composite != nil { @@ -90,35 +79,34 @@ func (devfile *TestDevfile) UpdateCommand(parserCommand *schema.Command) error { } devfile.replaceSchemaCommand(*parserCommand) } else { - errorString += LogMessage(fmt.Sprintf(" ....... Command not found in test : %s", parserCommand.Id)) + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Command not found in test : %s", parserCommand.Id))) } - var err error - if errorString != "" { - err = errors.New(errorString) + var returnError error + if len(errorString) > 0 { + returnError = errors.New(fmt.Sprint(errorString)) } - return err + return returnError } +// Create and return an exec command in a schema structure func createExecCommand() *schema.ExecCommand { - LogMessage("Create an exec command :") - + LogInfoMessage("Create an exec command :") execCommand := schema.ExecCommand{} - setExecCommandValues(&execCommand) - return &execCommand } +// Set the attribute values of an exec command func setExecCommandValues(execCommand *schema.ExecCommand) { execCommand.Component = GetRandomString(8, false) - LogMessage(fmt.Sprintf(" ....... component: %s", execCommand.Component)) + LogInfoMessage(fmt.Sprintf("....... component: %s", execCommand.Component)) execCommand.CommandLine = GetRandomString(4, false) + " " + GetRandomString(4, false) - LogMessage(fmt.Sprintf(" ....... commandLine: %s", execCommand.CommandLine)) + LogInfoMessage(fmt.Sprintf("....... commandLine: %s", execCommand.CommandLine)) if GetRandomDecision(2, 1) { execCommand.Group = addGroup() @@ -128,20 +116,20 @@ func setExecCommandValues(execCommand *schema.ExecCommand) { if GetBinaryDecision() { execCommand.Label = GetRandomString(12, false) - LogMessage(fmt.Sprintf(" ....... label: %s", execCommand.Label)) + LogInfoMessage(fmt.Sprintf("....... label: %s", execCommand.Label)) } else { execCommand.Label = "" } if GetBinaryDecision() { execCommand.WorkingDir = "./tmp" - LogMessage(fmt.Sprintf(" ....... WorkingDir: %s", execCommand.WorkingDir)) + LogInfoMessage(fmt.Sprintf("....... WorkingDir: %s", execCommand.WorkingDir)) } else { execCommand.WorkingDir = "" } execCommand.HotReloadCapable = GetBinaryDecision() - LogMessage(fmt.Sprintf(" ....... HotReloadCapable: %t", execCommand.HotReloadCapable)) + LogInfoMessage(fmt.Sprintf("....... HotReloadCapable: %t", execCommand.HotReloadCapable)) if GetBinaryDecision() { execCommand.Env = AddEnv(GetRandomNumber(4)) @@ -151,6 +139,7 @@ func setExecCommandValues(execCommand *schema.ExecCommand) { } +// Use the specified command to replace the command in the schema structure with the same Id. func (devfile TestDevfile) replaceSchemaCommand(command schema.Command) { for i := 0; i < len(devfile.SchemaDevFile.Commands); i++ { if devfile.SchemaDevFile.Commands[i].Id == command.Id { @@ -160,6 +149,7 @@ func (devfile TestDevfile) replaceSchemaCommand(command schema.Command) { } } +// Get a command from the schema structure func getSchemaCommand(commands []schema.Command, id string) (*schema.Command, bool) { found := false var schemaCommand schema.Command @@ -173,22 +163,23 @@ func getSchemaCommand(commands []schema.Command, id string) (*schema.Command, bo return &schemaCommand, found } +// Create a composite command in a schema structure func createCompositeCommand() *schema.CompositeCommand { + LogInfoMessage("Create a composite command :") compositeCommand := schema.CompositeCommand{} - setCompositeCommandValues(&compositeCommand) - return &compositeCommand } +// Set the attribute values for a composite command func setCompositeCommandValues(compositeCommand *schema.CompositeCommand) { numCommands := GetRandomNumber(3) compositeCommand.Commands = make([]string, numCommands) for i := 0; i < numCommands; i++ { compositeCommand.Commands[i] = GetRandomUniqueString(8, false) - LogMessage(fmt.Sprintf(" ....... command %d of %d : %s", i, numCommands, compositeCommand.Commands[i])) + LogInfoMessage(fmt.Sprintf("....... command %d of %d : %s", i, numCommands, compositeCommand.Commands[i])) } if GetRandomDecision(2, 1) { @@ -197,60 +188,71 @@ func setCompositeCommandValues(compositeCommand *schema.CompositeCommand) { if GetBinaryDecision() { compositeCommand.Label = GetRandomString(12, false) - LogMessage(fmt.Sprintf(" ....... label: %s", compositeCommand.Label)) + LogInfoMessage(fmt.Sprintf("....... label: %s", compositeCommand.Label)) } if GetBinaryDecision() { compositeCommand.Parallel = true - LogMessage(fmt.Sprintf(" ....... Parallel: %t", compositeCommand.Parallel)) + LogInfoMessage(fmt.Sprintf("....... Parallel: %t", compositeCommand.Parallel)) } } +// Verify commands returned by the parser match with those saved in the schema func (devfile TestDevfile) VerifyCommands(parserCommands []schema.Command) error { - LogMessage("Enter VerifyCommands") - errorString := "" + LogInfoMessage("Enter VerifyCommands") + var errorString []string // Compare entire array of commands if !cmp.Equal(parserCommands, devfile.SchemaDevFile.Commands) { - errorString += LogMessage(fmt.Sprintf(" --> ERROR: Command array compare failed.")) + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Command array compare failed."))) // Array compare failed. Narrow down by comparing indivdual commands for _, command := range parserCommands { if testCommand, found := getSchemaCommand(devfile.SchemaDevFile.Commands, command.Id); found { if !cmp.Equal(command, *testCommand) { parserFilename := AddSuffixToFileName(devfile.FileName, "_"+command.Id+"_Parser") testFilename := AddSuffixToFileName(devfile.FileName, "_"+command.Id+"_Test") - LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", devfile.FileName)) + LogInfoMessage(fmt.Sprintf(".......marshall and write devfile %s", devfile.FileName)) c, err := yaml.Marshal(command) - if err == nil { + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf(".......marshall devfile %s", parserFilename))) + } else { err = ioutil.WriteFile(parserFilename, c, 0644) + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf(".......write devfile %s", parserFilename))) + } } - LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", devfile.FileName)) + LogInfoMessage(fmt.Sprintf(".......marshall and write devfile %s", testFilename)) c, err = yaml.Marshal(testCommand) - if err == nil { + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf(".......marshall devfile %s", testFilename))) + } else { err = ioutil.WriteFile(testFilename, c, 0644) + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf(".......write devfile %s", testFilename))) + } } - errorString += LogMessage(fmt.Sprintf(" --> ERROR: Command %s did not match, see files : %s and %s", command.Id, parserFilename, testFilename)) + errorString = append(errorString, LogInfoMessage(fmt.Sprintf("Command %s did not match, see files : %s and %s", command.Id, parserFilename, testFilename))) } else { - LogMessage(fmt.Sprintf(" --> Command matched : %s", command.Id)) + LogInfoMessage(fmt.Sprintf(" --> Command matched : %s", command.Id)) } } else { - errorString += LogMessage(fmt.Sprintf(" --> ERROR: Command from parser not known to test - id : %s ", command.Id)) + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Command from parser not known to test - id : %s ", command.Id))) } } for _, command := range devfile.SchemaDevFile.Commands { if _, found := getSchemaCommand(parserCommands, command.Id); !found { - errorString += LogMessage(fmt.Sprintf(" --> ERROR: Command from test not returned by parser : %s ", command.Id)) + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Command from test not returned by parser : %s ", command.Id))) } } } else { - LogMessage(fmt.Sprintf(" --> Command structures matched")) + LogInfoMessage(fmt.Sprintf(" --> Command structures matched")) } var err error - if errorString != "" { - err = errors.New(errorString) + if len(errorString) > 0 { + err = errors.New(fmt.Sprint(errorString)) } return err } diff --git a/tests/src/tests/component_test_utils.go b/tests/src/tests/component_test_utils.go index d7262c55..9280e10e 100644 --- a/tests/src/tests/component_test_utils.go +++ b/tests/src/tests/component_test_utils.go @@ -11,16 +11,18 @@ import ( "sigs.k8s.io/yaml" ) +// Return volumeMounts in a schema structure based on a specified number of volumes func AddVolume(numVols int) []schema.VolumeMount { commandVols := make([]schema.VolumeMount, numVols) for i := 0; i < numVols; i++ { commandVols[i].Name = "Name_" + GetRandomString(5, false) commandVols[i].Path = "/Path_" + GetRandomString(5, false) - LogMessage(fmt.Sprintf(" ....... Add Volume: %s", commandVols[i])) + LogInfoMessage(fmt.Sprintf("....... Add Volume: %s", commandVols[i])) } return commandVols } +// Get a named components from an array of components func getSchemaComponent(components []schema.Component, name string) (*schema.Component, bool) { found := false var schemaComponent schema.Component @@ -34,44 +36,32 @@ func getSchemaComponent(components []schema.Component, name string) (*schema.Com return &schemaComponent, found } +// Add a component of the specified type func (devfile *TestDevfile) AddComponent(componentType schema.ComponentType) string { - - var components []schema.Component - index := 0 - if devfile.SchemaDevFile.Components != nil { - // Commands already exist so expand the current slice - currentSize := len(devfile.SchemaDevFile.Components) - components = make([]schema.Component, currentSize+1) - for _, component := range devfile.SchemaDevFile.Components { - components[index] = component - index++ - } - } else { - components = make([]schema.Component, 1) - } - - generateComponent(&components[index], componentType) - devfile.SchemaDevFile.Components = components - - return components[index].Name - + component := generateComponent(componentType) + devfile.SchemaDevFile.Components = append(devfile.SchemaDevFile.Components, component) + return component.Name } -func generateComponent(component *schema.Component, componentType schema.ComponentType) { +// Generate a component in a schema structure of the specified type +func generateComponent(componentType schema.ComponentType) schema.Component { + component := schema.Component{} component.Name = GetRandomUniqueString(8, true) - LogMessage(fmt.Sprintf(" ....... Name: %s", component.Name)) + LogInfoMessage(fmt.Sprintf("....... Name: %s", component.Name)) if componentType == schema.ContainerComponentType { component.Container = createContainerComponent() } else if componentType == schema.VolumeComponentType { component.Volume = createVolumeComponent() } + return component } +// Create a container component and set its attribute values func createContainerComponent() *schema.ContainerComponent { - LogMessage("Create a container component :") + LogInfoMessage("Create a container component :") containerComponent := schema.ContainerComponent{} setContainerComponentValues(&containerComponent) @@ -80,9 +70,10 @@ func createContainerComponent() *schema.ContainerComponent { } +// Create a volume component and set its attribute values func createVolumeComponent() *schema.VolumeComponent { - LogMessage("Create a volume component :") + LogInfoMessage("Create a volume component :") volumeComponent := schema.VolumeComponent{} setVolumeComponentValues(&volumeComponent) @@ -91,6 +82,7 @@ func createVolumeComponent() *schema.VolumeComponent { } +// Set container component attribute values func setContainerComponentValues(containerComponent *schema.ContainerComponent) { containerComponent.Image = GetRandomUniqueString(8+GetRandomNumber(10), false) @@ -100,7 +92,7 @@ func setContainerComponentValues(containerComponent *schema.ContainerComponent) containerComponent.Command = make([]string, numCommands) for i := 0; i < numCommands; i++ { containerComponent.Command[i] = GetRandomString(4+GetRandomNumber(10), false) - LogMessage(fmt.Sprintf(" ....... command %d of %d : %s", i, numCommands, containerComponent.Command[i])) + LogInfoMessage(fmt.Sprintf("....... command %d of %d : %s", i, numCommands, containerComponent.Command[i])) } } @@ -109,26 +101,26 @@ func setContainerComponentValues(containerComponent *schema.ContainerComponent) containerComponent.Args = make([]string, numArgs) for i := 0; i < numArgs; i++ { containerComponent.Args[i] = GetRandomString(8+GetRandomNumber(10), false) - LogMessage(fmt.Sprintf(" ....... arg %d of %d : %s", i, numArgs, containerComponent.Args[i])) + LogInfoMessage(fmt.Sprintf("....... arg %d of %d : %s", i, numArgs, containerComponent.Args[i])) } } containerComponent.DedicatedPod = GetBinaryDecision() - LogMessage(fmt.Sprintf(" ....... DedicatedPod: %t", containerComponent.DedicatedPod)) + LogInfoMessage(fmt.Sprintf("....... DedicatedPod: %t", containerComponent.DedicatedPod)) if GetBinaryDecision() { containerComponent.MemoryLimit = strconv.Itoa(4+GetRandomNumber(124)) + "M" - LogMessage(fmt.Sprintf(" ....... MemoryLimit: %s", containerComponent.MemoryLimit)) + LogInfoMessage(fmt.Sprintf("....... MemoryLimit: %s", containerComponent.MemoryLimit)) } if GetBinaryDecision() { setMountSources := GetBinaryDecision() containerComponent.MountSources = &setMountSources - LogMessage(fmt.Sprintf(" ....... MountSources: %t", *containerComponent.MountSources)) + LogInfoMessage(fmt.Sprintf("....... MountSources: %t", *containerComponent.MountSources)) if setMountSources { containerComponent.SourceMapping = "/" + GetRandomString(8, false) - LogMessage(fmt.Sprintf(" ....... SourceMapping: %s", containerComponent.SourceMapping)) + LogInfoMessage(fmt.Sprintf("....... SourceMapping: %s", containerComponent.SourceMapping)) } } @@ -141,7 +133,7 @@ func setContainerComponentValues(containerComponent *schema.ContainerComponent) if GetBinaryDecision() { containerComponent.VolumeMounts = AddVolume(GetRandomNumber(4)) } else { - containerComponent.Env = nil + containerComponent.VolumeMounts = nil } if GetBinaryDecision() { @@ -150,79 +142,92 @@ func setContainerComponentValues(containerComponent *schema.ContainerComponent) } +// Set volume component attribute values func setVolumeComponentValues(volumeComponent *schema.VolumeComponent) { if GetRandomDecision(5, 1) { volumeComponent.Size = strconv.Itoa(4+GetRandomNumber(252)) + "G" - LogMessage(fmt.Sprintf(" ....... volumeComponent.Size: %s", volumeComponent.Size)) + LogInfoMessage(fmt.Sprintf("....... volumeComponent.Size: %s", volumeComponent.Size)) } } +// Update the attribute values of a specified component func (devfile *TestDevfile) UpdateComponent(component *schema.Component) error { - errorString := "" + var errorString []string testComponent, found := getSchemaComponent(devfile.SchemaDevFile.Components, component.Name) if found { - LogMessage(fmt.Sprintf(" ....... Updating component name: %s", component.Name)) + LogInfoMessage(fmt.Sprintf("....... Updating component name: %s", component.Name)) if testComponent.ComponentType == schema.ContainerComponentType { setContainerComponentValues(component.Container) } else if testComponent.ComponentType == schema.VolumeComponentType { setVolumeComponentValues(component.Volume) } } else { - errorString += LogMessage(fmt.Sprintf(" ....... Component not found in test : %s", component.Name)) + errorString = append(errorString, LogInfoMessage(fmt.Sprintf("....... Component not found in test : %s", component.Name))) } var err error - if errorString != "" { - err = errors.New(errorString) + if len(errorString) > 0 { + err = errors.New(fmt.Sprint(errorString)) } return err } +// Verify components returned by the parser match with those saved in the schema func (devfile TestDevfile) VerifyComponents(parserComponents []schema.Component) error { - LogMessage("Enter VerifyComponents") - errorString := "" + LogInfoMessage("Enter VerifyComponents") + var errorString []string - // Compare entire array of commands + // Compare entire array of components if !cmp.Equal(parserComponents, devfile.SchemaDevFile.Components) { - errorString += LogMessage(fmt.Sprintf(" --> ERROR: Component array compare failed.")) + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Component array compare failed."))) for _, component := range parserComponents { if testComponent, found := getSchemaComponent(devfile.SchemaDevFile.Components, component.Name); found { if !cmp.Equal(component, *testComponent) { parserFilename := AddSuffixToFileName(devfile.FileName, "_"+component.Name+"_Parser") testFilename := AddSuffixToFileName(devfile.FileName, "_"+component.Name+"_Test") - LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", parserFilename)) + LogInfoMessage(fmt.Sprintf(".......marshall and write devfile %s", parserFilename)) c, err := yaml.Marshal(component) - if err == nil { + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf(".......marshall devfile %s", parserFilename))) + } else { err = ioutil.WriteFile(parserFilename, c, 0644) + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf(".......write devfile %s", parserFilename))) + } } - LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", testFilename)) + LogInfoMessage(fmt.Sprintf(".......marshall and write devfile %s", testFilename)) c, err = yaml.Marshal(testComponent) - if err == nil { + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf(".......marshall devfile %s", testFilename))) + } else { err = ioutil.WriteFile(testFilename, c, 0644) + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf(".......write devfile %s", testFilename))) + } } - errorString += LogMessage(fmt.Sprintf(" --> ERROR: Component %s did not match, see files : %s and %s", component.Name, parserFilename, testFilename)) + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Component %s did not match, see files : %s and %s", component.Name, parserFilename, testFilename))) } else { - LogMessage(fmt.Sprintf(" --> Component matched : %s", component.Name)) + LogInfoMessage(fmt.Sprintf(" --> Component matched : %s", component.Name)) } } else { - errorString += LogMessage(fmt.Sprintf(" --> ERROR: Component from parser not known to test - id : %s ", component.Name)) + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Component from parser not known to test - id : %s ", component.Name))) } } for _, component := range devfile.SchemaDevFile.Components { if _, found := getSchemaComponent(parserComponents, component.Name); !found { - errorString += LogMessage(fmt.Sprintf(" --> ERROR: Component from test not returned by parser : %s ", component.Name)) + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Component from test not returned by parser : %s ", component.Name))) } } } else { - LogMessage(fmt.Sprintf(" --> Component structures matched")) + LogInfoMessage(fmt.Sprintf("Component structures matched")) } var err error - if errorString != "" { - err = errors.New(errorString) + if len(errorString) > 0 { + err = errors.New(fmt.Sprint(errorString)) } return err } diff --git a/tests/src/tests/endpoint-test-utils.go b/tests/src/tests/endpoint-test-utils.go index ad5f62a7..bcfe1264 100644 --- a/tests/src/tests/endpoint-test-utils.go +++ b/tests/src/tests/endpoint-test-utils.go @@ -8,16 +8,20 @@ import ( var Exposures = [...]schema.EndpointExposure{schema.PublicEndpointExposure, schema.InternalEndpointExposure, schema.NoneEndpointExposure} +// Get a random exposure value func GetRandomExposure() schema.EndpointExposure { return Exposures[GetRandomNumber(len(Exposures))-1] } +//var Protocols = [...]schema.EndpointProtocol{schema.HTTPEndpointProtocol, schema.HTTPSEndpointProtocol, schema.WSEndpointProtocol, schema.WSSEndpointProtocol, schema.TCPEndpointProtocol, schema.UDPEndpointProtocol} var Protocols = [...]schema.EndpointProtocol{schema.HTTPEndpointProtocol, schema.WSEndpointProtocol, schema.TCPEndpointProtocol, schema.UDPEndpointProtocol} +// Get a random protocol value func GetRandomProtocol() schema.EndpointProtocol { return Protocols[GetRandomNumber(len(Protocols))-1] } +// Create one or more endpoints in a schema structure func CreateEndpoints() []schema.Endpoint { numEndpoints := GetRandomNumber(5) @@ -28,27 +32,27 @@ func CreateEndpoints() []schema.Endpoint { endpoint := schema.Endpoint{} endpoint.Name = GetRandomString(GetRandomNumber(15)+5, false) - LogMessage(fmt.Sprintf(" ....... add endpoint %d name : %s", i, endpoint.Name)) + LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d name : %s", i, endpoint.Name)) endpoint.TargetPort = GetRandomNumber(9999) - LogMessage(fmt.Sprintf(" ....... add endpoint %d targetPort: %d", i, endpoint.TargetPort)) + LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d targetPort: %d", i, endpoint.TargetPort)) if GetBinaryDecision() { endpoint.Exposure = GetRandomExposure() - LogMessage(fmt.Sprintf(" ....... add endpoint %d exposure: %s", i, endpoint.Exposure)) + LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d exposure: %s", i, endpoint.Exposure)) } if GetBinaryDecision() { endpoint.Protocol = GetRandomProtocol() - LogMessage(fmt.Sprintf(" ....... add endpoint %d protocol: %s", i, endpoint.Protocol)) + LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d protocol: %s", i, endpoint.Protocol)) } endpoint.Secure = GetBinaryDecision() - LogMessage(fmt.Sprintf(" ....... add endpoint %d secure: %t", i, endpoint.Secure)) + LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d secure: %t", i, endpoint.Secure)) if GetBinaryDecision() { endpoint.Path = "/Path_" + GetRandomString(GetRandomNumber(10)+3, false) - LogMessage(fmt.Sprintf(" ....... add endpoint %d path: %s", i, endpoint.Path)) + LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d path: %s", i, endpoint.Path)) } endpoints[i] = endpoint diff --git a/tests/src/tests/parser_v200_verify_test.go b/tests/src/tests/parser_v200_verify_test.go index a0ccb18f..73422531 100644 --- a/tests/src/tests/parser_v200_verify_test.go +++ b/tests/src/tests/parser_v200_verify_test.go @@ -252,27 +252,27 @@ func runTest(testContent TestContent, t *testing.T) { err := testDevfile.CreateDevfile(testContent.CreateWithParser) if err != nil { - t.Fatalf(LogMessage(fmt.Sprintf("ERROR creating devfile : %s : %v", testContent.FileName, err))) + t.Fatalf(LogErrorMessage(fmt.Sprintf("ERROR creating devfile : %s : %v", testContent.FileName, err))) } if testContent.EditContent { if len(testContent.CommandTypes) > 0 { err = testDevfile.EditCommands() if err != nil { - t.Fatalf(LogMessage(fmt.Sprintf("ERROR editing commands : %s : %v", testContent.FileName, err))) + t.Fatalf(LogErrorMessage(fmt.Sprintf("ERROR editing commands : %s : %v", testContent.FileName, err))) } } if len(testContent.ComponentTypes) > 0 { err = testDevfile.EditComponents() if err != nil { - t.Fatalf(LogMessage(fmt.Sprintf("ERROR editing components : %s : %v", testContent.FileName, err))) + t.Fatalf(LogErrorMessage(fmt.Sprintf("ERROR editing components : %s : %v", testContent.FileName, err))) } } } err = testDevfile.Verify() if err != nil { - t.Fatalf(LogMessage(fmt.Sprintf("ERROR verifying devfile content : %s : %v", testContent.FileName, err))) + t.Fatalf(LogErrorMessage(fmt.Sprintf("ERROR verifying devfile content : %s : %v", testContent.FileName, err))) } } diff --git a/tests/src/tests/test_utils.go b/tests/src/tests/test_utils.go index 67509ebd..b309d207 100644 --- a/tests/src/tests/test_utils.go +++ b/tests/src/tests/test_utils.go @@ -1,6 +1,7 @@ package tests import ( + "errors" "fmt" "io" "io/ioutil" @@ -30,6 +31,9 @@ var ( testLogger *log.Logger ) +// Creates: +// - the temporary directory used by the test to store logs and generated devfiles. +// - the log file func init() { if _, err := os.Stat(tmpDir); !os.IsNotExist(err) { os.RemoveAll(tmpDir) @@ -50,6 +54,10 @@ func init() { } } +// Called from a test program. +// - determines the test program name +// - creates a temproray directory for the test program +// returns the name of the directory created. func GetTempDir() string { _, fn, _, ok := runtime.Caller(1) if !ok { @@ -61,6 +69,8 @@ func GetTempDir() string { return CreateTempDir(subdir) } +// Creates a specified sub directory under the temp directory if it does not exists +// Returns the name of the temp directory. func CreateTempDir(subdir string) string { tempDir := tmpDir + subdir + "/" if _, err := os.Stat(tempDir); os.IsNotExist(err) { @@ -69,6 +79,10 @@ func CreateTempDir(subdir string) string { return tempDir } +// Called from a test program. +// - ensure the temp directory for the test program exists +// - generates a devfile name badsed in the calling function name +// Returns the devfile name func GetDevFileName() string { pc, fn, _, ok := runtime.Caller(1) if !ok { @@ -84,23 +98,47 @@ func GetDevFileName() string { pos1 := strings.LastIndex(callerName, "/tests.") + len("/tests.") devfileName := destDir + callerName[pos1:len(callerName)] + ".yaml" - LogMessage(fmt.Sprintf("GetDevFileName : %s", devfileName)) + LogInfoMessage(fmt.Sprintf("GetDevFileName : %s", devfileName)) return devfileName } +// Adds a specified suffix to the name of a specified file. +// For example if the file is devfile.yaml and the suffix 1 the result is devfile1.yaml func AddSuffixToFileName(fileName string, suffix string) string { pos1 := strings.LastIndex(fileName, ".yaml") newFileName := fileName[0:pos1] + suffix + ".yaml" - LogMessage(fmt.Sprintf("Add suffix %s to fileName %s : %s", suffix, fileName, newFileName)) + LogInfoMessage(fmt.Sprintf("Add suffix %s to fileName %s : %s", suffix, fileName, newFileName)) return newFileName } +// Log the specified message +// Return the message logged func LogMessage(message string) string { testLogger.Println(message) return message } +// Log the specified message as an Error +// Return the message logged +var errorPrefix = "..... ERROR : " + +func LogErrorMessage(message string) string { + var errMessage []string + errMessage = append(errMessage, errorPrefix, message) + return LogMessage(fmt.Sprint(errMessage)) +} + +// Log the specified message as Info +// Return the message logged +var infoPrefix = "INFO :" + +func LogInfoMessage(message string) string { + var infoMessage []string + infoMessage = append(infoMessage, infoPrefix, message) + return LogMessage(fmt.Sprint(infoMessage)) +} + type TestDevfile struct { SchemaDevFile schema.Devfile FileName string @@ -112,11 +150,15 @@ var StringCount int = 0 var RndSeed int64 = time.Now().UnixNano() +// Return a unique random string which is n characters long. +// An integer is appended to the name to ensure uniqueness +// If lower is set to true a lower case string is returned. func GetRandomUniqueString(n int, lower bool) string { StringCount++ return fmt.Sprintf("%s%04d", GetRandomString(n, lower), StringCount) } +// Creates a unique seed for the randon generation. func setRandSeed() { RndSeed++ rand.Seed(RndSeed) @@ -124,6 +166,8 @@ func setRandSeed() { const schemaBytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" +// Return a random string which is n characters long. +// If lower is set to true a lower case string is returned. func GetRandomString(n int, lower bool) string { setRandSeed() b := make([]byte, n) @@ -137,30 +181,32 @@ func GetRandomString(n int, lower bool) string { return randomString } -func GetGroupKinds() []schema.CommandGroupKind { - setRandSeed() - return []schema.CommandGroupKind{schema.BuildCommandGroupKind, schema.RunCommandGroupKind, schema.TestCommandGroupKind, schema.DebugCommandGroupKind} -} +var GroupKinds = [...]schema.CommandGroupKind{schema.BuildCommandGroupKind, schema.RunCommandGroupKind, schema.TestCommandGroupKind, schema.DebugCommandGroupKind} +// Return random group kind. One of "build", "run", "test" or "debug" func GetRandomGroupKind() schema.CommandGroupKind { - setRandSeed() - return GetGroupKinds()[rand.Intn(len(GetGroupKinds()))] + return GroupKinds[GetRandomNumber(len(GroupKinds))-1] } +// Randomly returns true or false func GetBinaryDecision() bool { return GetRandomDecision(1, 1) } +// Randomly returns true or false, but weighted to one or the other. +// For example if success is set to 2 and failure to 1, true is twice as likely to be returned. func GetRandomDecision(success int, failure int) bool { setRandSeed() return rand.Intn(success+failure) > failure-1 } +// Randomly returns an integer between 1 and the number specified. func GetRandomNumber(max int) int { setRandSeed() return rand.Intn(max) + 1 } +// Return a structure used to represent a specific devfile in the tests func GetDevfile(fileName string) TestDevfile { testDevfile := TestDevfile{} testDevfile.SchemaDevFile = schema.Devfile{} @@ -170,6 +216,9 @@ func GetDevfile(fileName string) TestDevfile { return testDevfile } +// Create a devifle on disk for use in the tests. +// If useParser is true the parser is used to generate the file, otherwise "sigs.k8s.io/yaml" is used. +// The TestDevfile structure specified contains the name of the devfile and its required content. func (devfile *TestDevfile) CreateDevfile(useParser bool) error { var err error @@ -179,10 +228,10 @@ func (devfile *TestDevfile) CreateDevfile(useParser bool) error { } if useParser { - LogMessage(fmt.Sprintf(" .......use Parser to write devfile %s", fileName)) + LogInfoMessage(fmt.Sprintf("Use Parser to write devfile %s", fileName)) newDevfile, err := devfileData.NewDevfileData(devfile.SchemaDevFile.SchemaVersion) if err != nil { - LogMessage(fmt.Sprintf(" ..... ERROR: creating new devfile : %v", err)) + LogErrorMessage(fmt.Sprintf("Creating new devfile : %v", err)) } else { newDevfile.SetSchemaVersion(devfile.SchemaDevFile.SchemaVersion) @@ -197,7 +246,7 @@ func (devfile *TestDevfile) CreateDevfile(useParser bool) error { err = ctx.SetAbsPath() if err != nil { - LogMessage(fmt.Sprintf(" ..... ERROR: setting devfile path : %v", err)) + LogErrorMessage(fmt.Sprintf("Setting devfile path : %v", err)) } else { devObj := parser.DevfileObj{ Ctx: ctx, @@ -205,120 +254,141 @@ func (devfile *TestDevfile) CreateDevfile(useParser bool) error { } err = devObj.WriteYamlDevfile() if err != nil { - LogMessage(fmt.Sprintf(" ..... ERROR: wriring devfile : %v", err)) + LogErrorMessage(fmt.Sprintf("Writing devfile : %v", err)) + } else { + devfile.SchemaParsed = false } } } } else { - LogMessage(fmt.Sprintf(" .......marshall and write devfile %s", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("Marshall and write devfile %s", devfile.FileName)) c, err := yaml.Marshal(&(devfile.SchemaDevFile)) - if err == nil { + if err != nil { + LogErrorMessage(fmt.Sprintf("Marshall devfile %s : %v", devfile.FileName, err)) + } else { err = ioutil.WriteFile(fileName, c, 0644) + if err != nil { + LogErrorMessage(fmt.Sprintf("Write devfile %s : %v", devfile.FileName, err)) + } else { + devfile.SchemaParsed = false + } } } - if err == nil { - devfile.SchemaParsed = false - } return err } +// Use the parser to parse a devfile on disk func (devfile *TestDevfile) ParseSchema() error { var err error if !devfile.SchemaParsed { - LogMessage(fmt.Sprintf(" -> Parse and Validate %s : ", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("Parse and Validate %s : ", devfile.FileName)) devfile.ParsedSchemaObj, err = devfilepkg.ParseAndValidate(devfile.FileName) if err != nil { - LogMessage(fmt.Sprintf(" ......ERROR from ParseAndValidate %v : ", err)) + LogErrorMessage(fmt.Sprintf("From ParseAndValidate %v : ", err)) } devfile.SchemaParsed = true } return err } +// Verify the contents of the specified devfile match the expected content func (devfile TestDevfile) Verify() error { - LogMessage(fmt.Sprintf("Verify %s : ", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("Verify %s : ", devfile.FileName)) + + var errorString []string err := devfile.ParseSchema() - if err == nil { - LogMessage(fmt.Sprintf(" -> Get commands %s : ", devfile.FileName)) + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("parsing schema %s : %v", devfile.FileName, err))) + } else { + LogInfoMessage(fmt.Sprintf("Get commands %s : ", devfile.FileName)) commands, _ := devfile.ParsedSchemaObj.Data.GetCommands(common.DevfileOptions{}) if commands != nil && len(commands) > 0 { err = devfile.VerifyCommands(commands) + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Verfify Commands %s : %v", devfile.FileName, err))) + } } else { - LogMessage(fmt.Sprintf(" No command found in %s : ", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("No command found in %s : ", devfile.FileName)) } } if err == nil { - LogMessage(fmt.Sprintf(" -> Get components %s : ", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("Get components %s : ", devfile.FileName)) components, _ := devfile.ParsedSchemaObj.Data.GetComponents(common.DevfileOptions{}) if components != nil && len(components) > 0 { err = devfile.VerifyComponents(components) + if err != nil { + errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Verfify Commands %s : %v", devfile.FileName, err))) + } } else { - LogMessage(fmt.Sprintf(" No components found in %s : ", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("No components found in %s : ", devfile.FileName)) } } - return err + var returnError error + if len(errorString) > 0 { + returnError = errors.New(fmt.Sprint(errorString)) + } + return returnError } +// Edit the commands in the specified devfile. func (devfile TestDevfile) EditCommands() error { - LogMessage(fmt.Sprintf("Edit %s : ", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("Edit %s : ", devfile.FileName)) err := devfile.ParseSchema() - if err == nil { - LogMessage(fmt.Sprintf(" -> Get commands %s : ", devfile.FileName)) + if err != nil { + LogErrorMessage(fmt.Sprintf("From parser : %v", err)) + } else { + LogInfoMessage(fmt.Sprintf(" -> Get commands %s : ", devfile.FileName)) commands, _ := devfile.ParsedSchemaObj.Data.GetCommands(common.DevfileOptions{}) for _, command := range commands { err = devfile.UpdateCommand(&command) if err != nil { - LogMessage(fmt.Sprintf(" ..... ERROR: updating command : %v", err)) + LogErrorMessage(fmt.Sprintf("Updating command : %v", err)) } else { - LogMessage(fmt.Sprintf(" ..... Update command in Parser : %s", command.Id)) + LogInfoMessage(fmt.Sprintf("Update command in Parser : %s", command.Id)) devfile.ParsedSchemaObj.Data.UpdateCommand(command) } } - LogMessage(fmt.Sprintf(" ..... Write updated file to yaml : %s", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("Write updated file to yaml : %s", devfile.FileName)) devfile.ParsedSchemaObj.WriteYamlDevfile() devfile.SchemaParsed = false - - } else { - LogMessage(fmt.Sprintf(" ..... ERROR: from parser : %v", err)) } return err - } +// Edit the components in the specified devfile. func (devfile TestDevfile) EditComponents() error { - LogMessage(fmt.Sprintf("Edit %s : ", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("Edit %s : ", devfile.FileName)) err := devfile.ParseSchema() - if err == nil { - LogMessage(fmt.Sprintf(" -> Get commands %s : ", devfile.FileName)) + if err != nil { + LogErrorMessage(fmt.Sprintf("From parser : %v", err)) + } else { + LogInfoMessage(fmt.Sprintf(" -> Get commands %s : ", devfile.FileName)) components, _ := devfile.ParsedSchemaObj.Data.GetComponents(common.DevfileOptions{}) for _, component := range components { err = devfile.UpdateComponent(&component) if err != nil { - LogMessage(fmt.Sprintf(" ..... ERROR: updating component : %v", err)) + LogErrorMessage(fmt.Sprintf("Updating component : %v", err)) } else { - LogMessage(fmt.Sprintf(" ..... Update component in Parser : %s", component.Name)) + LogInfoMessage(fmt.Sprintf("Update component in Parser : %s", component.Name)) devfile.ParsedSchemaObj.Data.UpdateComponent(component) } } - LogMessage(fmt.Sprintf(" ..... Write updated file to yaml : %s", devfile.FileName)) + LogInfoMessage(fmt.Sprintf("Write updated file to yaml : %s", devfile.FileName)) devfile.ParsedSchemaObj.WriteYamlDevfile() devfile.SchemaParsed = false - } else { - LogMessage(fmt.Sprintf(" ..... ERROR: from parser : %v", err)) } return err - } From 0010b5ff36d636348e4a97f8eb92331fb7e82faf Mon Sep 17 00:00:00 2001 From: Martin Mulholland Date: Thu, 7 Jan 2021 09:29:44 -0500 Subject: [PATCH 7/8] Address Maysun comments --- .gitignore | 2 +- tests/{src/tests => }/README.md | 4 +- .../tests => api}/parser_v200_verify_test.go | 88 +++++---- .../tests => utils}/command_test_utils.go | 41 ++--- .../tests => utils}/component_test_utils.go | 22 +-- .../tests => utils}/endpoint-test-utils.go | 8 +- .../tests => utils}/project_test_utils.go | 2 +- tests/{src/tests => utils}/test_utils.go | 167 +++++++++++------- 8 files changed, 189 insertions(+), 145 deletions(-) rename tests/{src/tests => }/README.md (98%) rename tests/{src/tests => api}/parser_v200_verify_test.go (71%) rename tests/{src/tests => utils}/command_test_utils.go (85%) rename tests/{src/tests => utils}/component_test_utils.go (89%) rename tests/{src/tests => utils}/endpoint-test-utils.go (90%) rename tests/{src/tests => utils}/project_test_utils.go (91%) rename tests/{src/tests => utils}/test_utils.go (68%) diff --git a/.gitignore b/.gitignore index 1bd4b352..2e12ef21 100644 --- a/.gitignore +++ b/.gitignore @@ -19,6 +19,6 @@ main .vscode/ # File created running tests -tests/src/tests/tmp/ +tests/tmp/ .DS_Store diff --git a/tests/src/tests/README.md b/tests/README.md similarity index 98% rename from tests/src/tests/README.md rename to tests/README.md index 58f4e399..9f51e59f 100644 --- a/tests/src/tests/README.md +++ b/tests/README.md @@ -4,7 +4,7 @@ The tests use the go language and are intended to test every apsect of the parser for every schema attribute. Some basic aspects of the tests: -* A first test (parser_v200_schema_test.go) feeds pre-created devfiles to the parser to ensure the parser can parse all attribues and return an approproate error when the devfile contains an error. +* A first test (parser_v200_schema_test.go) feeds pre-created devfiles to the parser to ensure the parser can parse all attribues and return an appropriate error when the devfile contains an error. This test is not currently available. * A second set of tests (parser_v200_verify_test.go) create devfile content at runtime: * Devfile content is randomly generated and as a result the tests are designed to run multiple times. * Parser functions covered: @@ -18,7 +18,7 @@ The tests use the go language and are intended to test every apsect of the parse ## Current tests: -The tests using pre-created devfiles are complete (but update in progress due to schema changes) +The tests using pre-created devfiles are not currently available (update in progress due to schema changes) The tests which generate devfiles with random content at run time currently cover the following properties and items. diff --git a/tests/src/tests/parser_v200_verify_test.go b/tests/api/parser_v200_verify_test.go similarity index 71% rename from tests/src/tests/parser_v200_verify_test.go rename to tests/api/parser_v200_verify_test.go index 73422531..9275642f 100644 --- a/tests/src/tests/parser_v200_verify_test.go +++ b/tests/api/parser_v200_verify_test.go @@ -1,4 +1,4 @@ -package tests +package api import ( "fmt" @@ -6,13 +6,21 @@ import ( "testing" "time" + "github.com/devfile/library/tests/utils" + schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) -const numThreads = 5 // Number of threads used by multi-thread tests -const maxCommands = 10 // The maximum number of commands to include in a generated devfile -const maxComponents = 10 // The maximum number of components to include in a generated devfile +const ( + // numThreads : Number of threads used by multi-thread tests + numThreads = 5 + // maxCommands : The maximum number of commands to include in a generated devfile + maxCommands = 10 + // maxComponents : The maximum number of components to include in a generated devfile + maxComponents = 10 +) +// TestContent - structure used by a test to configure the tests to run type TestContent struct { CommandTypes []schema.CommandType ComponentTypes []schema.ComponentType @@ -26,7 +34,7 @@ func Test_ExecCommand(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType} testContent.CreateWithParser = false testContent.EditContent = false - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -35,7 +43,7 @@ func Test_ExecCommandEdit(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType} testContent.CreateWithParser = false testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -45,7 +53,7 @@ func Test_ExecCommandParserCreate(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType} testContent.CreateWithParser = true testContent.EditContent = false - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -55,7 +63,7 @@ func Test_ExecCommandEditParserCreate(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType} testContent.CreateWithParser = true testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -65,7 +73,7 @@ func Test_CompositeCommand(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.CompositeCommandType} testContent.CreateWithParser = false testContent.EditContent = false - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -74,7 +82,7 @@ func Test_CompositeCommandEdit(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.CompositeCommandType} testContent.CreateWithParser = false testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -84,7 +92,7 @@ func Test_CompositeCommandParserCreate(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.CompositeCommandType} testContent.CreateWithParser = true testContent.EditContent = false - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -94,7 +102,7 @@ func Test_CompositeCommandEditParserCreate(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.CompositeCommandType} testContent.CreateWithParser = true testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -104,7 +112,7 @@ func Test_MultiCommand(t *testing.T) { testContent.CommandTypes = []schema.CommandType{schema.ExecCommandType, schema.CompositeCommandType} testContent.CreateWithParser = true testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -114,7 +122,7 @@ func Test_ContainerComponent(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType} testContent.CreateWithParser = false testContent.EditContent = false - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -124,7 +132,7 @@ func Test_ContainerComponentEdit(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType} testContent.CreateWithParser = false testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -134,7 +142,7 @@ func Test_ContainerComponentCreateWithParser(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType} testContent.CreateWithParser = true testContent.EditContent = false - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -144,7 +152,7 @@ func Test_ContainerComponentEditCreateWithParser(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType} testContent.CreateWithParser = true testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -154,7 +162,7 @@ func Test_VolumeComponent(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.VolumeComponentType} testContent.CreateWithParser = false testContent.EditContent = false - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -164,7 +172,7 @@ func Test_VolumeComponentEdit(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.VolumeComponentType} testContent.CreateWithParser = false testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -174,7 +182,7 @@ func Test_VolumeComponentCreateWithParser(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.VolumeComponentType} testContent.CreateWithParser = true testContent.EditContent = false - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -184,7 +192,7 @@ func Test_VolumeComponentEditCreateWithParser(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.VolumeComponentType} testContent.CreateWithParser = true testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -194,7 +202,7 @@ func Test_MultiComponent(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType, schema.VolumeComponentType} testContent.CreateWithParser = true testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } @@ -205,74 +213,76 @@ func Test_Everything(t *testing.T) { testContent.ComponentTypes = []schema.ComponentType{schema.ContainerComponentType, schema.VolumeComponentType} testContent.CreateWithParser = true testContent.EditContent = true - testContent.FileName = GetDevFileName() + testContent.FileName = utils.GetDevFileName() runTest(testContent, t) runMultiThreadTest(testContent, t) } +// runMultiThreadTest : Runs the same test on multiple threads, the test is based on the content of the specified TestContent func runMultiThreadTest(testContent TestContent, t *testing.T) { - LogMessage(fmt.Sprintf("Start Threaded test for %s", testContent.FileName)) + utils.LogMessage(fmt.Sprintf("Start Threaded test for %s", testContent.FileName)) devfileName := testContent.FileName var i int for i = 1; i < numThreads; i++ { - testContent.FileName = AddSuffixToFileName(devfileName, strconv.Itoa(i)) + testContent.FileName = utils.AddSuffixToFileName(devfileName, strconv.Itoa(i)) go runTest(testContent, t) } - testContent.FileName = AddSuffixToFileName(devfileName, strconv.Itoa(i)) + testContent.FileName = utils.AddSuffixToFileName(devfileName, strconv.Itoa(i)) runTest(testContent, t) - LogMessage(fmt.Sprintf("Sleep 2 seconds to allow all threads to complete : %s", devfileName)) + utils.LogMessage(fmt.Sprintf("Sleep 2 seconds to allow all threads to complete : %s", devfileName)) time.Sleep(2 * time.Second) - LogMessage(fmt.Sprintf("Sleep complete : %s", devfileName)) + utils.LogMessage(fmt.Sprintf("Sleep complete : %s", devfileName)) } +// runTest : Runs a test beased on the content of the specified TestContent func runTest(testContent TestContent, t *testing.T) { - LogMessage(fmt.Sprintf("Start test for %s", testContent.FileName)) - testDevfile := GetDevfile(testContent.FileName) + utils.LogMessage(fmt.Sprintf("Start test for %s", testContent.FileName)) + testDevfile := utils.GetDevfile(testContent.FileName) if len(testContent.CommandTypes) > 0 { - numCommands := GetRandomNumber(maxCommands) + numCommands := utils.GetRandomNumber(maxCommands) for i := 0; i < numCommands; i++ { - commandIndex := GetRandomNumber(len(testContent.CommandTypes)) - testDevfile.addCommand(testContent.CommandTypes[commandIndex-1]) + commandIndex := utils.GetRandomNumber(len(testContent.CommandTypes)) + testDevfile.AddCommand(testContent.CommandTypes[commandIndex-1]) } } if len(testContent.ComponentTypes) > 0 { - numComponents := GetRandomNumber(maxComponents) + numComponents := utils.GetRandomNumber(maxComponents) for i := 0; i < numComponents; i++ { - componentIndex := GetRandomNumber(len(testContent.ComponentTypes)) + componentIndex := utils.GetRandomNumber(len(testContent.ComponentTypes)) testDevfile.AddComponent(testContent.ComponentTypes[componentIndex-1]) } } err := testDevfile.CreateDevfile(testContent.CreateWithParser) if err != nil { - t.Fatalf(LogErrorMessage(fmt.Sprintf("ERROR creating devfile : %s : %v", testContent.FileName, err))) + t.Fatalf(utils.LogErrorMessage(fmt.Sprintf("ERROR creating devfile : %s : %v", testContent.FileName, err))) } if testContent.EditContent { if len(testContent.CommandTypes) > 0 { err = testDevfile.EditCommands() if err != nil { - t.Fatalf(LogErrorMessage(fmt.Sprintf("ERROR editing commands : %s : %v", testContent.FileName, err))) + t.Fatalf(utils.LogErrorMessage(fmt.Sprintf("ERROR editing commands : %s : %v", testContent.FileName, err))) } } if len(testContent.ComponentTypes) > 0 { err = testDevfile.EditComponents() if err != nil { - t.Fatalf(LogErrorMessage(fmt.Sprintf("ERROR editing components : %s : %v", testContent.FileName, err))) + t.Fatalf(utils.LogErrorMessage(fmt.Sprintf("ERROR editing components : %s : %v", testContent.FileName, err))) } } } err = testDevfile.Verify() if err != nil { - t.Fatalf(LogErrorMessage(fmt.Sprintf("ERROR verifying devfile content : %s : %v", testContent.FileName, err))) + t.Fatalf(utils.LogErrorMessage(fmt.Sprintf("ERROR verifying devfile content : %s : %v", testContent.FileName, err))) } } diff --git a/tests/src/tests/command_test_utils.go b/tests/utils/command_test_utils.go similarity index 85% rename from tests/src/tests/command_test_utils.go rename to tests/utils/command_test_utils.go index 60817883..be0c693f 100644 --- a/tests/src/tests/command_test_utils.go +++ b/tests/utils/command_test_utils.go @@ -1,4 +1,4 @@ -package tests +package utils import ( "errors" @@ -11,7 +11,7 @@ import ( schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) -// Return a specifed number of env attributes in a schema structure +// AddEnv creates and returns a specifed number of env attributes in a schema structure func AddEnv(numEnv int) []schema.EnvVar { commandEnvs := make([]schema.EnvVar, numEnv) for i := 0; i < numEnv; i++ { @@ -22,7 +22,7 @@ func AddEnv(numEnv int) []schema.EnvVar { return commandEnvs } -// Return a specifed number of attributes in a schema structure +// AddAttributes creates returns a specifed number of attributes in a schema structure func AddAttributes(numAtrributes int) map[string]string { attributes := make(map[string]string) for i := 0; i < numAtrributes; i++ { @@ -33,7 +33,7 @@ func AddAttributes(numAtrributes int) map[string]string { return attributes } -// Create and return a group in a schema structure +// addGroup creates and returns a group in a schema structure func addGroup() *schema.CommandGroup { commandGroup := schema.CommandGroup{} @@ -44,14 +44,14 @@ func addGroup() *schema.CommandGroup { return &commandGroup } -// Add a command of the specified type to the schema -func (devfile *TestDevfile) addCommand(commandType schema.CommandType) string { +// AddCommand adds a command of the specified type, with random attributes, to the devfile schema +func (devfile *TestDevfile) AddCommand(commandType schema.CommandType) string { command := generateCommand(commandType) devfile.SchemaDevFile.Commands = append(devfile.SchemaDevFile.Commands, command) return command.Id } -// Create a command of a specified type in a schema structure +// generateCommand creates a command of a specified type in a schema structure func generateCommand(commandType schema.CommandType) schema.Command { command := schema.Command{} command.Id = GetRandomUniqueString(8, true) @@ -65,10 +65,10 @@ func generateCommand(commandType schema.CommandType) schema.Command { return command } -// Update the values of a specified command +// UpdateCommand randomly updates attribute values of a specified command in the devfile schema func (devfile *TestDevfile) UpdateCommand(parserCommand *schema.Command) error { - var errorString []string + var err error testCommand, found := getSchemaCommand(devfile.SchemaDevFile.Commands, parserCommand.Id) if found { LogInfoMessage(fmt.Sprintf("Updating command id: %s", parserCommand.Id)) @@ -79,17 +79,12 @@ func (devfile *TestDevfile) UpdateCommand(parserCommand *schema.Command) error { } devfile.replaceSchemaCommand(*parserCommand) } else { - errorString = append(errorString, LogErrorMessage(fmt.Sprintf("Command not found in test : %s", parserCommand.Id))) - } - - var returnError error - if len(errorString) > 0 { - returnError = errors.New(fmt.Sprint(errorString)) + err = errors.New(LogErrorMessage(fmt.Sprintf("Command not found in test : %s", parserCommand.Id))) } - return returnError + return err } -// Create and return an exec command in a schema structure +// createExecCommand creates and returns an exec command in a schema structure func createExecCommand() *schema.ExecCommand { LogInfoMessage("Create an exec command :") @@ -99,7 +94,7 @@ func createExecCommand() *schema.ExecCommand { } -// Set the attribute values of an exec command +// setExecCommandValues randomly sets exec command attribute to random values func setExecCommandValues(execCommand *schema.ExecCommand) { execCommand.Component = GetRandomString(8, false) @@ -139,7 +134,7 @@ func setExecCommandValues(execCommand *schema.ExecCommand) { } -// Use the specified command to replace the command in the schema structure with the same Id. +// replaceSchemaCommand uses the specified command to replace the command in the schema structure with the same Id. func (devfile TestDevfile) replaceSchemaCommand(command schema.Command) { for i := 0; i < len(devfile.SchemaDevFile.Commands); i++ { if devfile.SchemaDevFile.Commands[i].Id == command.Id { @@ -149,7 +144,7 @@ func (devfile TestDevfile) replaceSchemaCommand(command schema.Command) { } } -// Get a command from the schema structure +// getSchemaCommand get a command from the devfile schema structure func getSchemaCommand(commands []schema.Command, id string) (*schema.Command, bool) { found := false var schemaCommand schema.Command @@ -163,7 +158,7 @@ func getSchemaCommand(commands []schema.Command, id string) (*schema.Command, bo return &schemaCommand, found } -// Create a composite command in a schema structure +// createCompositeCommand creates a composite command in a schema structure func createCompositeCommand() *schema.CompositeCommand { LogInfoMessage("Create a composite command :") @@ -172,7 +167,7 @@ func createCompositeCommand() *schema.CompositeCommand { return &compositeCommand } -// Set the attribute values for a composite command +// setCompositeCommandValues randomly sets composite command attribute to random values func setCompositeCommandValues(compositeCommand *schema.CompositeCommand) { numCommands := GetRandomNumber(3) @@ -197,7 +192,7 @@ func setCompositeCommandValues(compositeCommand *schema.CompositeCommand) { } } -// Verify commands returned by the parser match with those saved in the schema +// VerifyCommands verifies commands returned by the parser are the same as those saved in the devfile schema func (devfile TestDevfile) VerifyCommands(parserCommands []schema.Command) error { LogInfoMessage("Enter VerifyCommands") diff --git a/tests/src/tests/component_test_utils.go b/tests/utils/component_test_utils.go similarity index 89% rename from tests/src/tests/component_test_utils.go rename to tests/utils/component_test_utils.go index 9280e10e..3775751a 100644 --- a/tests/src/tests/component_test_utils.go +++ b/tests/utils/component_test_utils.go @@ -1,4 +1,4 @@ -package tests +package utils import ( "errors" @@ -11,7 +11,7 @@ import ( "sigs.k8s.io/yaml" ) -// Return volumeMounts in a schema structure based on a specified number of volumes +// AddVolume returns volumeMounts in a schema structure based on a specified number of volumes func AddVolume(numVols int) []schema.VolumeMount { commandVols := make([]schema.VolumeMount, numVols) for i := 0; i < numVols; i++ { @@ -22,7 +22,7 @@ func AddVolume(numVols int) []schema.VolumeMount { return commandVols } -// Get a named components from an array of components +// getSchemaComponent returns a named component from an array of components func getSchemaComponent(components []schema.Component, name string) (*schema.Component, bool) { found := false var schemaComponent schema.Component @@ -36,14 +36,14 @@ func getSchemaComponent(components []schema.Component, name string) (*schema.Com return &schemaComponent, found } -// Add a component of the specified type +// AddComponent adds a component of the specified type, with random attributes, to the devfile schema func (devfile *TestDevfile) AddComponent(componentType schema.ComponentType) string { component := generateComponent(componentType) devfile.SchemaDevFile.Components = append(devfile.SchemaDevFile.Components, component) return component.Name } -// Generate a component in a schema structure of the specified type +// generateComponent generates a component in a schema structure of the specified type func generateComponent(componentType schema.ComponentType) schema.Component { component := schema.Component{} @@ -58,7 +58,7 @@ func generateComponent(componentType schema.ComponentType) schema.Component { return component } -// Create a container component and set its attribute values +// createContainerComponent creates a container component and set its attribute values func createContainerComponent() *schema.ContainerComponent { LogInfoMessage("Create a container component :") @@ -70,7 +70,7 @@ func createContainerComponent() *schema.ContainerComponent { } -// Create a volume component and set its attribute values +// createVolumeComponent creates a volume component and set its attribute values func createVolumeComponent() *schema.VolumeComponent { LogInfoMessage("Create a volume component :") @@ -82,7 +82,7 @@ func createVolumeComponent() *schema.VolumeComponent { } -// Set container component attribute values +// setContainerComponentValues randomly sets container component attributes to random values func setContainerComponentValues(containerComponent *schema.ContainerComponent) { containerComponent.Image = GetRandomUniqueString(8+GetRandomNumber(10), false) @@ -142,7 +142,7 @@ func setContainerComponentValues(containerComponent *schema.ContainerComponent) } -// Set volume component attribute values +// setVolumeComponentValues randomly sets volume component attributes to random values func setVolumeComponentValues(volumeComponent *schema.VolumeComponent) { if GetRandomDecision(5, 1) { @@ -152,7 +152,7 @@ func setVolumeComponentValues(volumeComponent *schema.VolumeComponent) { } -// Update the attribute values of a specified component +// UpdateComponent randomly updates the attribute values of a specified component func (devfile *TestDevfile) UpdateComponent(component *schema.Component) error { var errorString []string @@ -174,7 +174,7 @@ func (devfile *TestDevfile) UpdateComponent(component *schema.Component) error { return err } -// Verify components returned by the parser match with those saved in the schema +// VerifyComponents verifies components returned by the parser are the same as those saved in the devfile schema func (devfile TestDevfile) VerifyComponents(parserComponents []schema.Component) error { LogInfoMessage("Enter VerifyComponents") diff --git a/tests/src/tests/endpoint-test-utils.go b/tests/utils/endpoint-test-utils.go similarity index 90% rename from tests/src/tests/endpoint-test-utils.go rename to tests/utils/endpoint-test-utils.go index bcfe1264..52d67d34 100644 --- a/tests/src/tests/endpoint-test-utils.go +++ b/tests/utils/endpoint-test-utils.go @@ -1,4 +1,4 @@ -package tests +package utils import ( "fmt" @@ -8,7 +8,7 @@ import ( var Exposures = [...]schema.EndpointExposure{schema.PublicEndpointExposure, schema.InternalEndpointExposure, schema.NoneEndpointExposure} -// Get a random exposure value +// GetRandomExposure returns a random exposure value func GetRandomExposure() schema.EndpointExposure { return Exposures[GetRandomNumber(len(Exposures))-1] } @@ -16,12 +16,12 @@ func GetRandomExposure() schema.EndpointExposure { //var Protocols = [...]schema.EndpointProtocol{schema.HTTPEndpointProtocol, schema.HTTPSEndpointProtocol, schema.WSEndpointProtocol, schema.WSSEndpointProtocol, schema.TCPEndpointProtocol, schema.UDPEndpointProtocol} var Protocols = [...]schema.EndpointProtocol{schema.HTTPEndpointProtocol, schema.WSEndpointProtocol, schema.TCPEndpointProtocol, schema.UDPEndpointProtocol} -// Get a random protocol value +// GetRandomProtocol returns a random protocol value func GetRandomProtocol() schema.EndpointProtocol { return Protocols[GetRandomNumber(len(Protocols))-1] } -// Create one or more endpoints in a schema structure +// CreateEndpoints createa and returns a randon numebr of endpoints in a schema structure func CreateEndpoints() []schema.Endpoint { numEndpoints := GetRandomNumber(5) diff --git a/tests/src/tests/project_test_utils.go b/tests/utils/project_test_utils.go similarity index 91% rename from tests/src/tests/project_test_utils.go rename to tests/utils/project_test_utils.go index 34beca88..1d7ee70b 100644 --- a/tests/src/tests/project_test_utils.go +++ b/tests/utils/project_test_utils.go @@ -1,4 +1,4 @@ -package tests +package utils import ( schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" diff --git a/tests/src/tests/test_utils.go b/tests/utils/test_utils.go similarity index 68% rename from tests/src/tests/test_utils.go rename to tests/utils/test_utils.go index b309d207..749f5734 100644 --- a/tests/src/tests/test_utils.go +++ b/tests/utils/test_utils.go @@ -1,4 +1,4 @@ -package tests +package utils import ( "errors" @@ -22,16 +22,19 @@ import ( "sigs.k8s.io/yaml" ) -const tmpDir = "./tmp/" -const logErrorOnly = false -const logFileName = "test.log" -const logToFileOnly = true // If set to false the log output will also be output to the console +const ( + tmpDir = "../tmp/" + logErrorOnly = false + logFileName = "test.log" + // logToFileOnly - If set to false the log output will also be output to the console + logToFileOnly = true // If set to false the log output will also be output to the console +) var ( testLogger *log.Logger ) -// Creates: +// init creates: // - the temporary directory used by the test to store logs and generated devfiles. // - the log file func init() { @@ -52,26 +55,14 @@ func init() { } testLogger.Println("Test Starting:") } -} -// Called from a test program. -// - determines the test program name -// - creates a temproray directory for the test program -// returns the name of the directory created. -func GetTempDir() string { - _, fn, _, ok := runtime.Caller(1) - if !ok { - return tmpDir - } - testFile := filepath.Base(fn) - testFileExtension := filepath.Ext(testFile) - subdir := testFile[0 : len(testFile)-len(testFileExtension)] - return CreateTempDir(subdir) + testError(true) + testError1(true) } -// Creates a specified sub directory under the temp directory if it does not exists -// Returns the name of the temp directory. -func CreateTempDir(subdir string) string { +// createTempDir creates a specified sub directory under the temp directory if it does not exist. +// Returns the name of the created directory. +func createTempDir(subdir string) string { tempDir := tmpDir + subdir + "/" if _, err := os.Stat(tempDir); os.IsNotExist(err) { os.Mkdir(tempDir, 0755) @@ -79,10 +70,8 @@ func CreateTempDir(subdir string) string { return tempDir } -// Called from a test program. -// - ensure the temp directory for the test program exists -// - generates a devfile name badsed in the calling function name -// Returns the devfile name +// GetDevFileName returns a qualified name of a devfile for use in a test. +// The devfile will be in a temporary directory and is named using the calling function's name. func GetDevFileName() string { pc, fn, _, ok := runtime.Caller(1) if !ok { @@ -92,10 +81,9 @@ func GetDevFileName() string { testFile := filepath.Base(fn) testFileExtension := filepath.Ext(testFile) subdir := testFile[0 : len(testFile)-len(testFileExtension)] - destDir := CreateTempDir(subdir) + destDir := createTempDir(subdir) callerName := runtime.FuncForPC(pc).Name() - - pos1 := strings.LastIndex(callerName, "/tests.") + len("/tests.") + pos1 := strings.LastIndex(callerName, "/tests/api.") + len("/tests/api.") devfileName := destDir + callerName[pos1:len(callerName)] + ".yaml" LogInfoMessage(fmt.Sprintf("GetDevFileName : %s", devfileName)) @@ -103,8 +91,8 @@ func GetDevFileName() string { return devfileName } -// Adds a specified suffix to the name of a specified file. -// For example if the file is devfile.yaml and the suffix 1 the result is devfile1.yaml +// AddSuffixToFileName adds a specified suffix to the name of a specified file. +// For example if the file is devfile.yaml and the suffix is 1, the result is devfile1.yaml func AddSuffixToFileName(fileName string, suffix string) string { pos1 := strings.LastIndex(fileName, ".yaml") newFileName := fileName[0:pos1] + suffix + ".yaml" @@ -112,33 +100,30 @@ func AddSuffixToFileName(fileName string, suffix string) string { return newFileName } -// Log the specified message -// Return the message logged +// LogMessage logs the specified message and returns the message logged func LogMessage(message string) string { testLogger.Println(message) return message } -// Log the specified message as an Error -// Return the message logged var errorPrefix = "..... ERROR : " +var infoPrefix = "INFO :" +// LogErrorMessage logs the specified message as an error message and returns the message logged func LogErrorMessage(message string) string { var errMessage []string errMessage = append(errMessage, errorPrefix, message) return LogMessage(fmt.Sprint(errMessage)) } -// Log the specified message as Info -// Return the message logged -var infoPrefix = "INFO :" - +// LogInfoMessage logs the specified message as an info message and returns the message logged func LogInfoMessage(message string) string { var infoMessage []string infoMessage = append(infoMessage, infoPrefix, message) return LogMessage(fmt.Sprint(infoMessage)) } +// TestDevfile is a structure used to track a test devfile and its contents type TestDevfile struct { SchemaDevFile schema.Devfile FileName string @@ -150,8 +135,7 @@ var StringCount int = 0 var RndSeed int64 = time.Now().UnixNano() -// Return a unique random string which is n characters long. -// An integer is appended to the name to ensure uniqueness +// GetRandomUniqueString returns a unique random string which is n characters long plus an integer to ensure uniqueness // If lower is set to true a lower case string is returned. func GetRandomUniqueString(n int, lower bool) string { StringCount++ @@ -166,7 +150,7 @@ func setRandSeed() { const schemaBytes = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" -// Return a random string which is n characters long. +// GetRandomString returns a random string which is n characters long. // If lower is set to true a lower case string is returned. func GetRandomString(n int, lower bool) string { setRandSeed() @@ -183,30 +167,30 @@ func GetRandomString(n int, lower bool) string { var GroupKinds = [...]schema.CommandGroupKind{schema.BuildCommandGroupKind, schema.RunCommandGroupKind, schema.TestCommandGroupKind, schema.DebugCommandGroupKind} -// Return random group kind. One of "build", "run", "test" or "debug" +// GetRandomGroupKind return random group kind. One of "build", "run", "test" or "debug" func GetRandomGroupKind() schema.CommandGroupKind { return GroupKinds[GetRandomNumber(len(GroupKinds))-1] } -// Randomly returns true or false +// GetBinaryDecision randomly returns true or false func GetBinaryDecision() bool { return GetRandomDecision(1, 1) } -// Randomly returns true or false, but weighted to one or the other. +// GetRandomDecision randomly returns true or false, but weighted to one or the other. // For example if success is set to 2 and failure to 1, true is twice as likely to be returned. func GetRandomDecision(success int, failure int) bool { setRandSeed() return rand.Intn(success+failure) > failure-1 } -// Randomly returns an integer between 1 and the number specified. +// GetRandomNumber randomly returns an integer between 1 and the number specified. func GetRandomNumber(max int) int { setRandSeed() return rand.Intn(max) + 1 } -// Return a structure used to represent a specific devfile in the tests +// GetDevfile returns a structure used to represent a specific devfile in a test func GetDevfile(fileName string) TestDevfile { testDevfile := TestDevfile{} testDevfile.SchemaDevFile = schema.Devfile{} @@ -216,9 +200,8 @@ func GetDevfile(fileName string) TestDevfile { return testDevfile } -// Create a devifle on disk for use in the tests. -// If useParser is true the parser is used to generate the file, otherwise "sigs.k8s.io/yaml" is used. -// The TestDevfile structure specified contains the name of the devfile and its required content. +// CreateDevfile create a devifle on disk for use in a test. +// If useParser is true the parser library is used to generate the file, otherwise "sigs.k8s.io/yaml" is used. func (devfile *TestDevfile) CreateDevfile(useParser bool) error { var err error @@ -229,9 +212,9 @@ func (devfile *TestDevfile) CreateDevfile(useParser bool) error { if useParser { LogInfoMessage(fmt.Sprintf("Use Parser to write devfile %s", fileName)) - newDevfile, err := devfileData.NewDevfileData(devfile.SchemaDevFile.SchemaVersion) - if err != nil { - LogErrorMessage(fmt.Sprintf("Creating new devfile : %v", err)) + newDevfile, createErr := devfileData.NewDevfileData(devfile.SchemaDevFile.SchemaVersion) + if createErr != nil { + err = errors.New(LogErrorMessage(fmt.Sprintf("Creating new devfile : %v", createErr))) } else { newDevfile.SetSchemaVersion(devfile.SchemaDevFile.SchemaVersion) @@ -263,10 +246,10 @@ func (devfile *TestDevfile) CreateDevfile(useParser bool) error { } } else { LogInfoMessage(fmt.Sprintf("Marshall and write devfile %s", devfile.FileName)) - c, err := yaml.Marshal(&(devfile.SchemaDevFile)) + c, marshallErr := yaml.Marshal(&(devfile.SchemaDevFile)) - if err != nil { - LogErrorMessage(fmt.Sprintf("Marshall devfile %s : %v", devfile.FileName, err)) + if marshallErr != nil { + err = errors.New(LogErrorMessage(fmt.Sprintf("Marshall devfile %s : %v", devfile.FileName, marshallErr))) } else { err = ioutil.WriteFile(fileName, c, 0644) if err != nil { @@ -280,7 +263,7 @@ func (devfile *TestDevfile) CreateDevfile(useParser bool) error { } // Use the parser to parse a devfile on disk -func (devfile *TestDevfile) ParseSchema() error { +func (devfile *TestDevfile) parseSchema() error { var err error if !devfile.SchemaParsed { @@ -294,14 +277,14 @@ func (devfile *TestDevfile) ParseSchema() error { return err } -// Verify the contents of the specified devfile match the expected content +// Verify verifies the contents of the specified devfile with the expected content func (devfile TestDevfile) Verify() error { LogInfoMessage(fmt.Sprintf("Verify %s : ", devfile.FileName)) var errorString []string - err := devfile.ParseSchema() + err := devfile.parseSchema() if err != nil { errorString = append(errorString, LogErrorMessage(fmt.Sprintf("parsing schema %s : %v", devfile.FileName, err))) @@ -339,12 +322,12 @@ func (devfile TestDevfile) Verify() error { } -// Edit the commands in the specified devfile. +// EditCommands modifies random attributes for each of the commands in the devfile. func (devfile TestDevfile) EditCommands() error { LogInfoMessage(fmt.Sprintf("Edit %s : ", devfile.FileName)) - err := devfile.ParseSchema() + err := devfile.parseSchema() if err != nil { LogErrorMessage(fmt.Sprintf("From parser : %v", err)) } else { @@ -366,12 +349,12 @@ func (devfile TestDevfile) EditCommands() error { return err } -// Edit the components in the specified devfile. +// EditComponents modifies random attributes for each of the components in the devfile. func (devfile TestDevfile) EditComponents() error { LogInfoMessage(fmt.Sprintf("Edit %s : ", devfile.FileName)) - err := devfile.ParseSchema() + err := devfile.parseSchema() if err != nil { LogErrorMessage(fmt.Sprintf("From parser : %v", err)) } else { @@ -392,3 +375,59 @@ func (devfile TestDevfile) EditComponents() error { } return err } + +func getError(message string) (string, error) { + return message, errors.New(message) +} + +func testError(doit bool) { + + var err error + + message1, err := getError("Error21") + LogInfoMessage(fmt.Sprintf("Message1 : %s", message1)) + LogInfoMessage(fmt.Sprintf("Error : %v", err)) + + if doit { + if err != nil { + message2, err := getError("Error22") + LogInfoMessage(fmt.Sprintf("Message2 : %s", message2)) + LogInfoMessage(fmt.Sprintf("Error : %v", err)) + if err != nil { + message3, err := getError("Error23") + LogInfoMessage(fmt.Sprintf("Message3 : %s", message3)) + LogInfoMessage(fmt.Sprintf("Error : %v", err)) + } + } + } + + LogInfoMessage(fmt.Sprintf("At the end")) + LogInfoMessage(fmt.Sprintf("Error : %v", err)) + +} +func testError1(doit bool) { + + var err error + var message string + + message, err = getError("Message Var Error1") + LogInfoMessage(fmt.Sprintf("Message1 : %s", message)) + LogInfoMessage(fmt.Sprintf("Error : %v", err)) + + if doit { + if err != nil { + message, err = getError("Message Var Error2") + LogInfoMessage(fmt.Sprintf("Message2 : %s", message)) + LogInfoMessage(fmt.Sprintf("Error : %v", err)) + if err != nil { + message, err = getError("Message Var Error3") + LogInfoMessage(fmt.Sprintf("Message1 : %s", message)) + LogInfoMessage(fmt.Sprintf("Error : %v", err)) + } + } + } + + LogInfoMessage(fmt.Sprintf("At the end")) + LogInfoMessage(fmt.Sprintf("Error : %v", err)) + +} From d2d24b323c9b4a586cf511671eaaab5be20eeec0 Mon Sep 17 00:00:00 2001 From: Martin Mulholland Date: Mon, 11 Jan 2021 11:04:56 -0500 Subject: [PATCH 8/8] Address more comments --- tests/utils/command_test_utils.go | 10 ++--- tests/utils/component_test_utils.go | 8 ++-- tests/utils/endpoint-test-utils.go | 12 +++--- tests/utils/project_test_utils.go | 10 ----- tests/utils/test_utils.go | 58 ----------------------------- 5 files changed, 15 insertions(+), 83 deletions(-) delete mode 100644 tests/utils/project_test_utils.go diff --git a/tests/utils/command_test_utils.go b/tests/utils/command_test_utils.go index be0c693f..23d6400a 100644 --- a/tests/utils/command_test_utils.go +++ b/tests/utils/command_test_utils.go @@ -11,8 +11,8 @@ import ( schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" ) -// AddEnv creates and returns a specifed number of env attributes in a schema structure -func AddEnv(numEnv int) []schema.EnvVar { +// addEnv creates and returns a specifed number of env attributes in a schema structure +func addEnv(numEnv int) []schema.EnvVar { commandEnvs := make([]schema.EnvVar, numEnv) for i := 0; i < numEnv; i++ { commandEnvs[i].Name = "Name_" + GetRandomString(5, false) @@ -22,8 +22,8 @@ func AddEnv(numEnv int) []schema.EnvVar { return commandEnvs } -// AddAttributes creates returns a specifed number of attributes in a schema structure -func AddAttributes(numAtrributes int) map[string]string { +// addAttributes creates returns a specifed number of attributes in a schema structure +func addAttributes(numAtrributes int) map[string]string { attributes := make(map[string]string) for i := 0; i < numAtrributes; i++ { AttributeName := "Name_" + GetRandomString(6, false) @@ -127,7 +127,7 @@ func setExecCommandValues(execCommand *schema.ExecCommand) { LogInfoMessage(fmt.Sprintf("....... HotReloadCapable: %t", execCommand.HotReloadCapable)) if GetBinaryDecision() { - execCommand.Env = AddEnv(GetRandomNumber(4)) + execCommand.Env = addEnv(GetRandomNumber(4)) } else { execCommand.Env = nil } diff --git a/tests/utils/component_test_utils.go b/tests/utils/component_test_utils.go index 3775751a..43440f13 100644 --- a/tests/utils/component_test_utils.go +++ b/tests/utils/component_test_utils.go @@ -11,8 +11,8 @@ import ( "sigs.k8s.io/yaml" ) -// AddVolume returns volumeMounts in a schema structure based on a specified number of volumes -func AddVolume(numVols int) []schema.VolumeMount { +// addVolume returns volumeMounts in a schema structure based on a specified number of volumes +func addVolume(numVols int) []schema.VolumeMount { commandVols := make([]schema.VolumeMount, numVols) for i := 0; i < numVols; i++ { commandVols[i].Name = "Name_" + GetRandomString(5, false) @@ -125,13 +125,13 @@ func setContainerComponentValues(containerComponent *schema.ContainerComponent) } if GetBinaryDecision() { - containerComponent.Env = AddEnv(GetRandomNumber(4)) + containerComponent.Env = addEnv(GetRandomNumber(4)) } else { containerComponent.Env = nil } if GetBinaryDecision() { - containerComponent.VolumeMounts = AddVolume(GetRandomNumber(4)) + containerComponent.VolumeMounts = addVolume(GetRandomNumber(4)) } else { containerComponent.VolumeMounts = nil } diff --git a/tests/utils/endpoint-test-utils.go b/tests/utils/endpoint-test-utils.go index 52d67d34..b8ca55a9 100644 --- a/tests/utils/endpoint-test-utils.go +++ b/tests/utils/endpoint-test-utils.go @@ -8,16 +8,16 @@ import ( var Exposures = [...]schema.EndpointExposure{schema.PublicEndpointExposure, schema.InternalEndpointExposure, schema.NoneEndpointExposure} -// GetRandomExposure returns a random exposure value -func GetRandomExposure() schema.EndpointExposure { +// getRandomExposure returns a random exposure value +func getRandomExposure() schema.EndpointExposure { return Exposures[GetRandomNumber(len(Exposures))-1] } //var Protocols = [...]schema.EndpointProtocol{schema.HTTPEndpointProtocol, schema.HTTPSEndpointProtocol, schema.WSEndpointProtocol, schema.WSSEndpointProtocol, schema.TCPEndpointProtocol, schema.UDPEndpointProtocol} var Protocols = [...]schema.EndpointProtocol{schema.HTTPEndpointProtocol, schema.WSEndpointProtocol, schema.TCPEndpointProtocol, schema.UDPEndpointProtocol} -// GetRandomProtocol returns a random protocol value -func GetRandomProtocol() schema.EndpointProtocol { +// getRandomProtocol returns a random protocol value +func getRandomProtocol() schema.EndpointProtocol { return Protocols[GetRandomNumber(len(Protocols))-1] } @@ -38,12 +38,12 @@ func CreateEndpoints() []schema.Endpoint { LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d targetPort: %d", i, endpoint.TargetPort)) if GetBinaryDecision() { - endpoint.Exposure = GetRandomExposure() + endpoint.Exposure = getRandomExposure() LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d exposure: %s", i, endpoint.Exposure)) } if GetBinaryDecision() { - endpoint.Protocol = GetRandomProtocol() + endpoint.Protocol = getRandomProtocol() LogInfoMessage(fmt.Sprintf(" ....... add endpoint %d protocol: %s", i, endpoint.Protocol)) } diff --git a/tests/utils/project_test_utils.go b/tests/utils/project_test_utils.go deleted file mode 100644 index 1d7ee70b..00000000 --- a/tests/utils/project_test_utils.go +++ /dev/null @@ -1,10 +0,0 @@ -package utils - -import ( - schema "github.com/devfile/api/pkg/apis/workspaces/v1alpha2" -) - -type GenericProject struct { - Name string - Project *schema.Project -} diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 749f5734..c99098f9 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -55,9 +55,6 @@ func init() { } testLogger.Println("Test Starting:") } - - testError(true) - testError1(true) } // createTempDir creates a specified sub directory under the temp directory if it does not exist. @@ -299,9 +296,7 @@ func (devfile TestDevfile) Verify() error { } else { LogInfoMessage(fmt.Sprintf("No command found in %s : ", devfile.FileName)) } - } - if err == nil { LogInfoMessage(fmt.Sprintf("Get components %s : ", devfile.FileName)) components, _ := devfile.ParsedSchemaObj.Data.GetComponents(common.DevfileOptions{}) if components != nil && len(components) > 0 { @@ -313,7 +308,6 @@ func (devfile TestDevfile) Verify() error { LogInfoMessage(fmt.Sprintf("No components found in %s : ", devfile.FileName)) } } - var returnError error if len(errorString) > 0 { returnError = errors.New(fmt.Sprint(errorString)) @@ -379,55 +373,3 @@ func (devfile TestDevfile) EditComponents() error { func getError(message string) (string, error) { return message, errors.New(message) } - -func testError(doit bool) { - - var err error - - message1, err := getError("Error21") - LogInfoMessage(fmt.Sprintf("Message1 : %s", message1)) - LogInfoMessage(fmt.Sprintf("Error : %v", err)) - - if doit { - if err != nil { - message2, err := getError("Error22") - LogInfoMessage(fmt.Sprintf("Message2 : %s", message2)) - LogInfoMessage(fmt.Sprintf("Error : %v", err)) - if err != nil { - message3, err := getError("Error23") - LogInfoMessage(fmt.Sprintf("Message3 : %s", message3)) - LogInfoMessage(fmt.Sprintf("Error : %v", err)) - } - } - } - - LogInfoMessage(fmt.Sprintf("At the end")) - LogInfoMessage(fmt.Sprintf("Error : %v", err)) - -} -func testError1(doit bool) { - - var err error - var message string - - message, err = getError("Message Var Error1") - LogInfoMessage(fmt.Sprintf("Message1 : %s", message)) - LogInfoMessage(fmt.Sprintf("Error : %v", err)) - - if doit { - if err != nil { - message, err = getError("Message Var Error2") - LogInfoMessage(fmt.Sprintf("Message2 : %s", message)) - LogInfoMessage(fmt.Sprintf("Error : %v", err)) - if err != nil { - message, err = getError("Message Var Error3") - LogInfoMessage(fmt.Sprintf("Message1 : %s", message)) - LogInfoMessage(fmt.Sprintf("Error : %v", err)) - } - } - } - - LogInfoMessage(fmt.Sprintf("At the end")) - LogInfoMessage(fmt.Sprintf("Error : %v", err)) - -}