Changes to the test framework to support templating of
the json test files to enable the creation of very large
stress test suites. Still a work in progress.
Change-Id: I1a35e4143a2feb577c9ad6048a0339c7b9dc0f89
diff --git a/tests/afrouter/templates/main.go b/tests/afrouter/templates/main.go
index f539a02..c2fddb9 100644
--- a/tests/afrouter/templates/main.go
+++ b/tests/afrouter/templates/main.go
@@ -26,9 +26,28 @@
"os/exec"
"strings"
"context"
+ slog "log"
+ "io/ioutil"
+ "encoding/json"
+ "google.golang.org/grpc/grpclog"
"github.com/opencord/voltha-go/common/log"
)
+type TestCase struct {
+ Title string `json:"title"`
+ Result bool `json:"result"`
+ Info []string `json:"info"`
+}
+
+type TestSuite struct {
+ Name string `json:"name"`
+ TestCases []TestCase `json:"testCases"`
+}
+
+type TestRun struct {
+ TestSuites []TestSuite
+}
+
var resFile *tstLog
type tstLog struct {
fp * os.File
@@ -95,6 +114,37 @@
//time.Sleep(1 * time.Second)
}
+func readStats(stats * TestRun) () {
+ // Check if the stats file exists
+ if _,err := os.Stat("stats.json"); err != nil {
+ // Nothing to do, just return
+ return
+ }
+ // The file is there, read it an unmarshal it into the stats struct
+ if statBytes, err := ioutil.ReadFile("stats.json"); err != nil {
+ log.Error(err)
+ return
+ } else if err := json.Unmarshal(statBytes, stats); err != nil {
+ log.Error(err)
+ return
+ }
+}
+
+func writeStats(stats * TestRun) () {
+ // Check if the stats file exists
+ // The file is there, read it an unmarshal it into the stats struct
+ if statBytes, err := json.MarshalIndent(stats, ""," "); err != nil {
+ log.Error(err)
+ return
+ } else if err := ioutil.WriteFile("stats.json.new", statBytes, 0644); err != nil {
+ log.Error(err)
+ return
+ }
+ os.Rename("stats.json", "stats.json~")
+ os.Rename("stats.json.new", "stats.json")
+}
+var stats TestRun
+
func main() {
var err error
@@ -102,9 +152,13 @@
if _, err = log.SetDefaultLogger(log.JSON, 0, nil); err != nil {
log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
}
-
defer log.CleanUp()
+ readStats(&stats)
+
+
+ grpclog.SetLogger(slog.New(os.Stderr, "grpc: ", slog.LstdFlags))
+
resFile = &tstLog{fn:os.Args[1]}
defer resFile.close()
@@ -133,5 +187,6 @@
// Run all the test cases now
log.Infof("Executing tests")
runTests()
+ writeStats(&stats)
}
diff --git a/tests/afrouter/templates/runAll.go b/tests/afrouter/templates/runAll.go
index b4079d1..03cdab1 100644
--- a/tests/afrouter/templates/runAll.go
+++ b/tests/afrouter/templates/runAll.go
@@ -83,7 +83,7 @@
}
tl := &tstLog{fn:"results.txt"}
{{range .}}
- cmdStr = "./"+"{{.}}"[:len("{{.}}")-5]
+ cmdStr = "./"+"{{.}}"+".e"
tl.testLogOnce("Running test suite '%s'\n", cmdStr[2:])
log.Infof("Running test suite %s",cmdStr)
diff --git a/tests/afrouter/templates/runTests.go b/tests/afrouter/templates/runTests.go
index 2c65f09..61ba5eb 100644
--- a/tests/afrouter/templates/runTests.go
+++ b/tests/afrouter/templates/runTests.go
@@ -18,9 +18,12 @@
package main
import (
+ "fmt"
+ "time"
"errors"
+ "context"
"encoding/json"
- "golang.org/x/net/context"
+ //"golang.org/x/net/context"
"google.golang.org/grpc/metadata"
"github.com/opencord/voltha-go/common/log"
{{range .Imports}}
@@ -31,6 +34,8 @@
{{end}}
)
+var glCtx context.Context
+
func resetChannels() {
// Drain all channels of data
for _,v := range servers {
@@ -56,15 +61,19 @@
} else {
resFile.testLog("\tTest Failed\n")
}
- resetChannels()
+ //resetChannels()
{{end}}
}
{{range $k,$v := .Tests}}
func test{{$k}}() error {
var rtrn error = nil
+ var cancel context.CancelFunc
+
+ glCtx, cancel = context.WithTimeout(context.Background(), 900*time.Millisecond)
+ defer cancel()
// Announce the test being run
- resFile.testLog("******************** Running test case: {{$v.Name}}\n")
+ resFile.testLog("******************** Running test case ({{$k}}): {{$v.Name}}\n")
// Acquire the client used to run the test
cl := clients["{{$v.Send.Client}}"]
// Create the server's reply data structure
@@ -76,13 +85,18 @@
log.Error(err)
return err
}
- select {
- case servers["{{$s.Name}}"].replyData <- repl:
- default:
- err := errors.New("Could not provide server {{$s.Name}} with reply data")
- log.Error(err)
- return err
- }
+ // Start a go routine to send the the reply data to the
+ // server. The go routine blocks until the server picks
+ // up the data or the timeout is exceeded.
+ go func (ctx context.Context) {
+ select {
+ case servers["{{$s.Name}}"].replyData <- repl:
+ case <-ctx.Done():
+ rtrn := errors.New("Could not provide server {{$s.Name}} with reply data")
+ log.Error(rtrn)
+ resFile.testLog("%s\n", rtrn.Error())
+ }
+ }(glCtx)
{{end}}
// Now call the RPC with the data provided
@@ -118,25 +132,27 @@
}
{{range $s := .Srvr}}
s = servers["{{$s.Name}}"]
+ // Oddly sometimes the data isn't in the channel yet when we come to read it.
select {
case i = <-s.incmg:
if i.payload != payload {
- log.Errorf("Mismatched payload for test {{$v.Name}}, %s:%s", i.payload, payload)
- resFile.testLog("Mismatched payload expected '%s', got '%s'\n", payload, i.payload)
- rtrn = errors.New("Failed")
+ rtrn = errors.New(fmt.Sprintf("Mismatched payload expected '%s', got '%s'", payload, i.payload))
+ log.Error(rtrn.Error())
+ resFile.testLog("%s\n", rtrn.Error())
}
{{range $m := $s.Meta}}
if mv,ok := i.meta["{{$m.Key}}"]; ok == true {
if "{{$m.Val}}" != mv[0] {
- log.Errorf("Mismatched metadata for test {{$v.Name}}, %s:%s", mv[0], "{{$m.Val}}")
- resFile.testLog("Mismatched metadata on server '%s' expected '%s', got '%s'\n", "{{$s.Name}}", "{{$m.Val}}", mv[0])
- rtrn = errors.New("Failed")
+ rtrn=errors.New(fmt.Sprintf("Mismatched metadata on server '%s' expected '%s', got '%s'", "{{$s.Name}}", "{{$m.Val}}", mv[0]))
+ log.Error(rtrn.Error())
+ resFile.testLog("%s\n", rtrn.Error())
}
}
{{end}}
- default:
- err := errors.New("No response data available for server {{$s.Name}}")
- log.Error(err)
+ case <-glCtx.Done():
+ rtrn = errors.New("Timeout: no response data available for server {{$s.Name}}")
+ resFile.testLog("%s\n", rtrn.Error())
+ log.Error(rtrn)
}
{{end}}
diff --git a/tests/afrouter/templates/server.go b/tests/afrouter/templates/server.go
index 85c3b93..ffea3d5 100644
--- a/tests/afrouter/templates/server.go
+++ b/tests/afrouter/templates/server.go
@@ -76,7 +76,7 @@
func {{.Name}}ListenAndServe() error {
var s {{.Name}}TestServer
- s.control = &serverCtl{replyData:make(chan *reply,1), incmg:make(chan *incoming,1)}
+ s.control = &serverCtl{replyData:make(chan *reply), incmg:make(chan *incoming)}
servers["{{.Name}}"] = s.control
log.Debugf("Starting server %s on port %d", "{{.Name}}", {{.Port}})
@@ -112,15 +112,18 @@
{{range .Methods}}
{{if .Ss}}
func (ts {{$.Name}}TestServer) {{.Name}}(in *{{.Param}}, srvr {{.Pkg}}.{{.Svc}}_{{.Name}}Server) error {
+ log.Debug("Serving server streaming {{$.Name}}")
return nil
}
{{else if .Cs}}
func (ts {{$.Name}}TestServer) {{.Name}}({{.Pkg}}.{{.Svc}}_{{.Name}}Server) error {
+ log.Debug("Serving client streaming {{$.Name}}")
return nil
}
{{else}}
func (ts {{$.Name}}TestServer) {{.Name}}(ctx context.Context, in *{{.Param}}) (*{{.Rtrn}}, error) {
var r * incoming = &incoming{}
+ log.Debug("Serving {{$.Name}}")
// Read the metadata
if md,ok := metadata.FromIncomingContext(ctx); ok == false {
log.Error("Getting matadata during call to {{.Name}}")
@@ -134,7 +137,15 @@
r.payload = string(parm)
}
// Send the server information back to the test framework
- ts.control.incmg <- r
+ go func(ctx context.Context) {
+ select {
+ case ts.control.incmg <- r:
+ return
+ case <-ctx.Done():
+ return
+
+ }
+ }(glCtx)
// Read the value that needs to be returned from the channel
select {
case d := <-ts.control.replyData:
@@ -144,8 +155,8 @@
default:
return nil, errors.New("Mismatched type in call to {{.Name}}")
}
- default:
- return nil, errors.New("Nothing in the reply data channel in call to {{.Name}}, sending nil")
+ case <-glCtx.Done():
+ return nil, errors.New("Timeout: nothing in the reply data channel in call to {{.Name}}, sending nil")
}
return &{{.Rtrn}}{},nil
}