Skip to content
This repository was archived by the owner on Aug 26, 2022. It is now read-only.

Commit b22ad8f

Browse files
authored
Merge pull request #21 from redhat-nfvpe/operator-test
Adding operator testing for check for CSV
2 parents 06a17cb + 5ec45a1 commit b22ad8f

File tree

12 files changed

+462
-0
lines changed

12 files changed

+462
-0
lines changed

Makefile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,23 @@ generic-cnf-tests: build build-cnf-tests run-generic-cnf-tests
3232

3333
cnf-tests: build build-cnf-tests run-cnf-tests
3434

35+
operator-cnf-tests: build build-cnf-operator-tests run-operator-tests
36+
3537
build-cnf-tests:
3638
PATH=${PATH}:${GOBIN} ginkgo build ./test-network-function
3739

40+
build-cnf-operator-tests:
41+
PATH=${PATH}:${GOBIN} ginkgo build ./test-network-function/operator-test --tags operator_suite
42+
3843
run-generic-cnf-tests:
3944
cd ./test-network-function && ./test-network-function.test -ginkgo.focus="generic" ${COMMON_GINKGO_ARGS}
4045

4146
run-cnf-tests:
4247
cd ./test-network-function && ./test-network-function.test $COMMON_GINKGO_ARGS
4348

49+
run-operator-tests:
50+
cd ./test-network-function/operator-test && ./operator-test.test $COMMON_GINKGO_ARGS
51+
4452
deps-update:
4553
go mod tidy && \
4654
go mod vendor
@@ -61,6 +69,8 @@ clean:
6169
go clean
6270
rm -f ./test-network-function/test-network-function.test
6371
rm -f ./test-network-function/cnf-certification-tests_junit.xml
72+
rm -f ./test-network-function/operator-test/operator-test.test
73+
rm -f ./test-network-function/operator-test/cnf-operator-certification-tests_junit.xml
6474

6575
dependencies:
6676
go get github.com/onsi/ginkgo/ginkgo

README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,3 +274,33 @@ cd ./test-network-function && ./test-network-function.test -ginkgo.v -ginkgo.foc
274274
```
275275
276276
A JUnit report containing results is created at `test-network-function/cnf-certification-tests_junit.xml`.
277+
278+
### Run an Operator Test Suite
279+
280+
In order to run an operator test suite, `operator-test` for example, issue the following command:
281+
282+
```shell script
283+
make build build-cnf-operator-tests
284+
cd ./test-network-function/operator-test && ./operator-test.test -ginkgo.v -ginkgo.focus="operatr_test" -junit . -report .
285+
```
286+
287+
Test Configuration
288+
289+
You can either edit the provided config at `test-network-function/operator-test/config/config.yml`
290+
or you can pass config with `-config` flag to the test suite
291+
292+
Sample config.yml
293+
294+
---
295+
csv:
296+
name: "etcdoperator.v0.9.4"
297+
namespace: "my-etcd"
298+
status: "Succeeded"
299+
300+
```
301+
cd ./test-network-function/operator-test && ./operator-test.test -config=config.yml -ginkgo.v -ginkgo.focus="operatr_test" -junit . -report .
302+
```
303+
304+
305+
A JUnit report containing results is created at `test-network-function/operator-test/cnf-operator-certification-tests_junit.xml`.
306+
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package config
2+
3+
import (
4+
"flag"
5+
"fmt"
6+
"gopkg.in/yaml.v2"
7+
"os"
8+
)
9+
10+
//String that contains the configured configuration path
11+
var configPath = flag.String("config", "./config/config.yml", "path to config file")
12+
13+
//Config struct for configuring operator test
14+
type Config struct {
15+
//Csv is a clusterServiceVersion which contains the packaging details of the operator
16+
Csv struct {
17+
//Name of csv operator package with version name
18+
Name string `yaml:"name" json:"name"`
19+
//Namespace where the operator will be running
20+
Namespace string `yaml:"namespace" json:"namespace"`
21+
//Expected status of the Csv
22+
Status string `yaml:"status" json:"status"`
23+
} `yaml:"csv" json:"csv"`
24+
}
25+
26+
//NewConfig returns a new decoded Config struct
27+
func NewConfig(configPath string) (*Config, error) {
28+
var file *os.File
29+
var err error
30+
// Create config structure
31+
config := &Config{}
32+
// Open config file
33+
if file, err = os.Open(configPath); err != nil {
34+
return nil, err
35+
}
36+
defer file.Close()
37+
// Init new YAML decode
38+
d := yaml.NewDecoder(file)
39+
// Start YAML decoding from file
40+
if err := d.Decode(&config); err != nil {
41+
return nil, err
42+
}
43+
return config, nil
44+
}
45+
46+
// ValidateConfigPath just makes sure, that the path provided is a file,
47+
// that can be read
48+
func validateConfigPath(path string) error {
49+
s, err := os.Stat(path)
50+
if err != nil {
51+
return err
52+
}
53+
if s.IsDir() {
54+
return fmt.Errorf("'%s' is a directory, not a normal file", path)
55+
}
56+
return nil
57+
}
58+
59+
// parseFlags will create and parse the CLI flags
60+
// and return the path to be used elsewhere
61+
func parseFlags() (string, error) {
62+
var err error
63+
flag.Parse()
64+
// Validate the path first
65+
if err = validateConfigPath(*configPath); err != nil {
66+
return "", err
67+
}
68+
// Return the configuration path
69+
return *configPath, nil
70+
}
71+
72+
// GetConfig returns the Operator TestConfig configuration.
73+
func GetConfig() (*Config, error) {
74+
// Generate our config based on the config supplied
75+
// by the user in the flags
76+
cfgPath, err := parseFlags()
77+
if err != nil {
78+
return nil, err
79+
}
80+
cfg, err := NewConfig(cfgPath)
81+
return cfg, err
82+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
csv:
3+
name: "etcdoperator.v0.9.4"
4+
namespace: "my-etcd"
5+
status: "Succeeded"
6+
7+
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package config
2+
3+
import (
4+
"fmt"
5+
"github.com/stretchr/testify/assert"
6+
"io/ioutil"
7+
"os"
8+
"strings"
9+
"testing"
10+
)
11+
12+
func TestNewConfig(t *testing.T) {
13+
file, err := ioutil.TempFile("", "testconfig.yml")
14+
defer os.Remove(file.Name())
15+
if err != nil {
16+
fmt.Println(err)
17+
assert.Fail(t, "failed to parse valid test file")
18+
}
19+
cfg, err := NewConfig(file.Name())
20+
assert.Nil(t, cfg)
21+
assert.NotNil(t, err)
22+
cfg, err = NewConfig(file.Name() + "bad_file")
23+
assert.Nil(t, cfg)
24+
assert.NotNil(t, err)
25+
26+
cfg, err = NewConfig("config.yml")
27+
assert.NotNil(t, cfg)
28+
assert.Nil(t, err)
29+
}
30+
31+
func TestValidateConfigPath(t *testing.T) {
32+
var tests = []struct {
33+
path string
34+
error error
35+
}{
36+
{".", fmt.Errorf("'.' is a directory, not a normal file")},
37+
{"./config", fmt.Errorf("./config is a directory, not a normal file")},
38+
{"./config.yml", nil},
39+
}
40+
for _, tt := range tests {
41+
t.Run(tt.path, func(t *testing.T) {
42+
err := validateConfigPath(tt.path)
43+
if err == nil && tt.error != nil {
44+
assert.Fail(t, err.Error())
45+
}
46+
47+
})
48+
}
49+
}
50+
51+
//TestConfigLoadFunction ... Test if config is read correctly
52+
func TestConfigLoadFunction(t *testing.T) {
53+
var test Config
54+
test.Csv.Name = "etcdoperator.v0.9.4"
55+
test.Csv.Namespace = "my-etcd"
56+
test.Csv.Status = "Succeeded"
57+
path, _ := os.Getwd()
58+
59+
var tests = []struct {
60+
args []string
61+
conf Config
62+
error string
63+
}{
64+
{[]string{"./operator-test"}, test, "no such file or directory"},
65+
{[]string{"./operator-test", "-config", "config_not_exists"}, test, "no such file or directory"},
66+
{[]string{"./operator-test", "-config", path}, test, "is a directory, not a normal file"},
67+
{[]string{"./operator-test", "-config", "config.yml"}, test, ""},
68+
{[]string{"./operator-test", "-config", path + "/config.yml"}, test, ""},
69+
}
70+
for _, tt := range tests {
71+
t.Run(strings.Join(tt.args, " "), func(t *testing.T) {
72+
os.Args = tt.args
73+
if len(tt.args) > 2 {
74+
configPath = &tt.args[2]
75+
}
76+
testConfig, err := GetConfig()
77+
if err == nil {
78+
assert.Nil(t, err)
79+
assert.NotNil(t, testConfig)
80+
assert.Equal(t, *testConfig, tt.conf)
81+
} else {
82+
assert.NotNil(t, err)
83+
assert.Contains(t, err.Error(), tt.error)
84+
}
85+
})
86+
}
87+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package config

pkg/tnf/handlers/operator/csv.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package operator
2+
3+
import (
4+
"fmt"
5+
"github.com/redhat-nfvpe/test-network-function/internal/reel"
6+
"github.com/redhat-nfvpe/test-network-function/pkg/tnf"
7+
"regexp"
8+
"strings"
9+
"time"
10+
)
11+
12+
const (
13+
// CheckCSVCommand is the OC command for checking for CSV.
14+
CheckCSVCommand = "oc get csv %s -n %s -o json | jq -r '.status.phase'"
15+
)
16+
17+
//Csv Cluster service version , manifests of the operator.
18+
type Csv struct {
19+
result int
20+
timeout time.Duration
21+
args []string
22+
Name string
23+
Status string
24+
Namespace string
25+
ExpectStatus string
26+
}
27+
28+
// Args returns the command line args for the test.
29+
func (c *Csv) Args() []string {
30+
return c.args
31+
}
32+
33+
// Timeout return the timeout for the test.
34+
func (c *Csv) Timeout() time.Duration {
35+
return c.timeout
36+
}
37+
38+
// Result returns the test result.
39+
func (c *Csv) Result() int {
40+
return c.result
41+
}
42+
43+
// ReelFirst returns a step which expects an csv status for the given csv.
44+
func (c *Csv) ReelFirst() *reel.Step {
45+
return &reel.Step{
46+
Expect: []string{c.ExpectStatus},
47+
Timeout: c.timeout,
48+
}
49+
}
50+
51+
// ReelMatch parses the csv status output and set the test result on match.
52+
// Returns no step; the test is complete.
53+
func (c *Csv) ReelMatch(_ string, _ string, match string) *reel.Step {
54+
re := regexp.MustCompile(c.ExpectStatus)
55+
matched := re.MatchString(match)
56+
if matched {
57+
c.result = tnf.SUCCESS
58+
}
59+
return nil
60+
}
61+
62+
// ReelTimeout does nothing;
63+
func (c *Csv) ReelTimeout() *reel.Step {
64+
return nil
65+
}
66+
67+
// ReelEOF does nothing.
68+
func (c *Csv) ReelEOF() {
69+
}
70+
71+
// NewCsv creates a `Operator Csv` test which determines the "csv" status.
72+
func NewCsv(name, namespace string, expectedStatus string, timeout time.Duration) *Csv {
73+
args := strings.Split(fmt.Sprintf(CheckCSVCommand, name, namespace), " ")
74+
return &Csv{
75+
Name: name,
76+
Namespace: namespace,
77+
ExpectStatus: expectedStatus,
78+
result: tnf.ERROR,
79+
timeout: timeout,
80+
args: args,
81+
}
82+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
package operator_test
2+
3+
import (
4+
"fmt"
5+
"github.com/redhat-nfvpe/test-network-function/pkg/tnf"
6+
"github.com/redhat-nfvpe/test-network-function/pkg/tnf/handlers/operator"
7+
"github.com/stretchr/testify/assert"
8+
"strings"
9+
"testing"
10+
"time"
11+
)
12+
13+
const (
14+
testTimeoutDuration = time.Second * 2
15+
csvName = "csv-test-v1.0"
16+
namespace = "test"
17+
expectedStatus = "Succeeded"
18+
)
19+
20+
func TestCsv_Args(t *testing.T) {
21+
c := operator.NewCsv(csvName, namespace, expectedStatus, testTimeoutDuration)
22+
args := strings.Split(fmt.Sprintf(operator.CheckCSVCommand, c.Name, c.Namespace), " ")
23+
fmt.Println(args)
24+
assert.Equal(t, args, c.Args())
25+
}
26+
func TestCsv_ReelFirst(t *testing.T) {
27+
c := operator.NewCsv(csvName, namespace, expectedStatus, testTimeoutDuration)
28+
step := c.ReelFirst()
29+
assert.Equal(t, "", step.Execute)
30+
fmt.Println(c.ExpectStatus)
31+
assert.Equal(t, []string{c.ExpectStatus}, step.Expect)
32+
assert.Equal(t, testTimeoutDuration, step.Timeout)
33+
}
34+
35+
func TestCsv_ReelEof(t *testing.T) {
36+
c := operator.NewCsv(csvName, namespace, expectedStatus, testTimeoutDuration)
37+
// just ensures lack of panic
38+
c.ReelEOF()
39+
}
40+
41+
func TestCsv_ReelTimeout(t *testing.T) {
42+
c := operator.NewCsv(csvName, namespace, expectedStatus, testTimeoutDuration)
43+
step := c.ReelTimeout()
44+
assert.Nil(t, step)
45+
}
46+
func TestCsv_ReelMatch(t *testing.T) {
47+
c := operator.NewCsv(csvName, namespace, expectedStatus, testTimeoutDuration)
48+
step := c.ReelMatch("", "", "Succeeded")
49+
assert.Nil(t, step)
50+
assert.Equal(t, tnf.SUCCESS, c.Result())
51+
}
52+
func TestNewCsv(t *testing.T) {
53+
c := operator.NewCsv(csvName, namespace, expectedStatus, testTimeoutDuration)
54+
assert.Equal(t, tnf.ERROR, c.Result())
55+
assert.Equal(t, testTimeoutDuration, c.Timeout())
56+
}

pkg/tnf/handlers/operator/doc.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
package operator
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
csv:
3+
name: "etcdoperator.v0.9.4"
4+
namespace: "my-etcd"
5+
status: "Succeeded"

0 commit comments

Comments
 (0)