Initial commit for the affinity router test framework
added license junk.

Change-Id: I6faad2ca93b0a7bb5108a1ffe42ff82f30451ae9
diff --git a/tests/afrouter/templates/client.go b/tests/afrouter/templates/client.go
new file mode 100644
index 0000000..d384baf
--- /dev/null
+++ b/tests/afrouter/templates/client.go
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+import (
+	"fmt"
+	"errors"
+	"encoding/json"
+	"google.golang.org/grpc"
+	"golang.org/x/net/context"
+	"github.com/opencord/voltha-go/common/log"
+	// Values generated by the go template
+	{{range .Imports}}
+	"{{.}}"
+	{{end}}
+	{{range .ProtoImports}}
+	{{.Short}} "{{.Package}}"
+	{{end}}
+	// End go template values
+)
+
+{{if .Ct}}{{else}}
+type clientCtl struct {
+	send func(string, interface{}, string) error
+	cncl  context.CancelFunc
+	ctx context.Context
+}
+{{end}}
+
+type {{.Name}}ClientConn struct {
+	conn * grpc.ClientConn
+	control * clientCtl
+}
+
+
+var {{.Name}}Client *{{.Name}}ClientConn
+
+
+func {{.Name}}Connect() (*{{.Name}}ClientConn, error)  {
+	log.Infof("Connecting client {{.Name}} to addr:127.0.0.1, port:{{.Port}}")
+	// Dial doesn't block, it just returns and continues connecting in the background.
+	// Check back later to confirm and increase the connection count.
+	cl := &{{.Name}}ClientConn{control:&clientCtl{}}
+	ctx, cnclFnc := context.WithCancel(context.Background())
+	cl.control.cncl = cnclFnc
+	cl.control.ctx = ctx
+	if conn, err := grpc.Dial("127.0.0.1:{{.Port}}", grpc.WithInsecure()); err != nil {
+		log.Errorf("Dialng connection :%v",err)
+		return nil, err
+	} else {
+		cl.conn = conn
+	}
+	{{.Name}}Client = cl
+	cl.control.send = {{.Name}}Send
+	clients["{{.Name}}"] = cl.control
+	return cl, nil
+}
+
+// This function will make the requested RPC with the supplied
+// parameter and validate that the response matches the expected
+// value provided. It will return nil if successful or an error
+// if not.
+func {{.Name}}Send(mthd string, param interface{}, expect string) error {
+	switch mthd {
+	{{range .Methods}}
+		case "{{.Name}}":
+		switch t := param.(type) {
+			case *{{.Param}}:
+	{{if .Ss}}
+			_=t
+	{{else if .Cs}}
+			_=t
+	{{else}}
+			client := {{.Pkg}}.New{{.Svc}}Client({{$.Name}}Client.conn)
+			res, err := client.{{.Name}}(context.Background(), t)
+			if err != nil {
+				return errors.New("Error sending method {{.Name}}")
+			}
+			// Marshal the result and compare it to the expected
+			// value.
+			if resS,err := json.Marshal(res); err == nil {
+				if string(resS) != expect {
+					return errors.New("Unexpected result on method {{.Name}}")
+				}
+			} else {
+				return errors.New("Error Marshaling the reply for method {{.Name}}")
+			}
+			default:
+					return errors.New("Invalid parameter type for method {{.Name}}")
+	{{end}}
+		}
+	{{end}}
+		default:
+			return errors.New(fmt.Sprintf("Unexpected method %s in send", mthd))
+	}
+	return nil
+}
+
diff --git a/tests/afrouter/templates/clientInit.go b/tests/afrouter/templates/clientInit.go
new file mode 100644
index 0000000..e8f4836
--- /dev/null
+++ b/tests/afrouter/templates/clientInit.go
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+var clients map[string]*clientCtl
+
+func clientInit() error {
+	clients = make(map[string]*clientCtl)
+	{{range .}}
+	if _,err := {{.Name}}Connect(); err != nil {
+		return err
+	}
+	{{end}}
+	return nil
+}
+
+
diff --git a/tests/afrouter/templates/main.go b/tests/afrouter/templates/main.go
new file mode 100644
index 0000000..5c094d9
--- /dev/null
+++ b/tests/afrouter/templates/main.go
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// The template for the tester.
+// This template is filled in by the
+// test driver based on the configuration.
+
+package main
+
+import (
+	"os"
+	"time"
+	"os/exec"
+	"strings"
+	"context"
+	"github.com/opencord/voltha-go/common/log"
+)
+
+var resFile *os.File
+
+func startSut(cmdStr string) (context.CancelFunc, error) {
+	var err error = nil
+
+	cmdAry := strings.Fields(cmdStr)
+	log.Infof("Running the affinity router: %s",cmdStr)
+	//ctx, cncl := context.WithCancel(context.Background())
+	ctx, cncl := context.WithCancel(context.Background())
+	cmd := exec.CommandContext(ctx, cmdAry[0], cmdAry[1:]...)
+	cmd.Stdin = os.Stdin
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	if err = cmd.Start(); err != nil {
+		log.Errorf("Failed to run the affinity router: %s %v", cmdStr,err)
+	}
+	time.Sleep(1 * time.Second) // Give the command time to get started
+	return cncl, err
+}
+
+func cleanUp(cncl context.CancelFunc) {
+	cncl()
+	// Give the child processes time to terminate
+	time.Sleep(1 * time.Second)
+}
+
+func main() {
+	var err error
+
+	// Setup logging
+	if _, err = log.SetDefaultLogger(log.JSON, 0, nil); err != nil {
+		log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
+	}
+
+	defer log.CleanUp()
+
+	// Open the results file to write the results to
+	if resFile, err = os.OpenFile(os.Args[1], os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644); err != nil {
+		log.Errorf("Could not append to the results file")
+	}
+
+	defer resFile.Close()
+
+	// Initialize the servers
+	if err := serverInit(); err != nil {
+		log.Errorf("Error initializing server: %v", err)
+		return
+	}
+
+	// Start the sofware under test
+	cnclFunc, err := startSut("./{{.Command}}");
+	defer cleanUp(cnclFunc)
+	if  err != nil {
+		return
+	}
+
+	// Initialize the clients
+	if err := clientInit(); err != nil {
+		log.Errorf("Error initializing client: %v", err)
+		return
+	}
+
+	log.Infof("The servers are: %v",servers)
+
+	// Run all the test cases now
+	log.Infof("Executing tests")
+	resFile.Write([]byte("Executing tests\n"))
+	runTests()
+
+}
diff --git a/tests/afrouter/templates/runAll.go b/tests/afrouter/templates/runAll.go
new file mode 100644
index 0000000..b85e4c7
--- /dev/null
+++ b/tests/afrouter/templates/runAll.go
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// The template for the tester.
+// This template is filled in by the
+// test driver based on the configuration.
+
+package main
+
+import (
+	"os"
+	//"time"
+	"fmt"
+	"os/exec"
+	"io/ioutil"
+	"github.com/opencord/voltha-go/common/log"
+)
+
+func main() {
+	var cmd *exec.Cmd
+	var cmdStr string
+	// Setup logging
+	if _, err := log.SetDefaultLogger(log.JSON, 0, nil); err != nil {
+		log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
+	}
+
+	defer log.CleanUp()
+
+	log.Info("Running tests")
+	{{range .}}
+	if err:= os.Chdir(os.Args[1]); err != nil {
+		log.Error("Could not change directory to %s: %v", os.Args[1], err)
+	}
+	cmdStr =  "./"+"{{.}}"[:len("{{.}}")-5]
+	log.Infof("Running test %s",cmdStr)
+	cmd = exec.Command(cmdStr, "results.txt")
+	cmd.Stdin = os.Stdin
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+	if err := cmd.Run(); err != nil {
+		log.Errorf("Test '%s' failed", cmdStr)
+	}
+	{{end}}
+	// Open the results file and output it.
+	if resFile, err := ioutil.ReadFile("results.txt"); err == nil {
+		fmt.Println(string(resFile))
+	} else {
+		log.Error("Could not load the results file 'results.txt'")
+	}
+	log.Info("Tests complete")
+}
diff --git a/tests/afrouter/templates/runTests.go b/tests/afrouter/templates/runTests.go
new file mode 100644
index 0000000..3b0f6d4
--- /dev/null
+++ b/tests/afrouter/templates/runTests.go
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package main
+
+import (
+	"fmt"
+	"time"
+	"errors"
+	"encoding/json"
+	"github.com/opencord/voltha-go/common/log"
+	{{range .Imports}}
+	_ "{{.}}"
+	{{end}}
+	{{range .ProtoImports}}
+	{{.Short}} "{{.Package}}"
+	{{end}}
+)
+
+func runTests() {
+	{{range $k,$v := .Tests}}
+	if err := test{{$k}}(); err == nil {
+		resFile.Write([]byte("\tTest Successful\n"))
+	} else {
+		resFile.Write([]byte("\tTest Failed\n"))
+	}
+	{{end}}
+	time.Sleep(5 * time.Second)
+}
+
+{{range $k,$v := .Tests}}
+func test{{$k}}() error {
+	var rtrn error = nil
+	// Announce the test being run
+	resFile.Write([]byte("******************** Running test case: {{$v.Name}}\n"))
+	// Acquire the client used to run the test
+	cl := clients["{{$v.Send.Client}}"]
+	// Create the server's reply data structure
+	repl := &reply{repl:&{{$v.Send.ExpectType}}{{$v.Send.Expect}}}
+	// Send the reply data structure to each of the servers
+	{{range $s := .Srvr}}
+	if servers["{{$s.Name}}"] == nil {
+		log.Error("Server '{{$s.Name}}' is nil")
+		return errors.New("GAAK")
+	}
+	servers["{{$s.Name}}"].replyData <- repl
+	{{end}}
+
+	// Now call the RPC with the data provided
+	if expct,err := json.Marshal(repl.repl); err != nil {
+		log.Errorf("Marshaling the reply for test {{$v.Name}}: %v",err)
+	} else {
+		if err := cl.send("{{$v.Send.Method}}",
+							&{{$v.Send.ParamType}}{{$v.Send.Param}},
+							string(expct)); err != nil {
+			log.Errorf("Test case {{$v.Name}} failed!: %v", err)
+
+		}
+	}
+
+	// Now read the servers' information to validate it
+	var s *serverCtl
+	var payload string
+	var i *incoming
+	if pld, err := json.Marshal(&{{$v.Send.ParamType}}{{$v.Send.Param}}); err != nil {
+		log.Errorf("Marshaling paramter for test {{$v.Name}}: %v", err)
+	} else {
+		payload = string(pld)
+	}
+	{{range $s := .Srvr}}
+	s = servers["{{$s.Name}}"]
+	i = <-s.incmg
+	if i.payload != payload {
+		log.Errorf("Mismatched payload for test {{$v.Name}}, %s:%s", i.payload, payload)
+		resFile.Write([]byte(fmt.Sprintf("Mismatched payload expected %s, got %s\n", payload, i.payload)))
+		rtrn = errors.New("Failed")
+	}
+	{{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.Write([]byte(fmt.Sprintf("Mismatched metadata on server %s expected %s, got %s\n", "{{$s.Name}}", "{{$m.Val}}", mv[0])))
+			rtrn = errors.New("Failed")
+		}
+	}
+	{{end}}
+	{{end}}
+
+	return rtrn
+}
+{{end}}
+
+
diff --git a/tests/afrouter/templates/server.go b/tests/afrouter/templates/server.go
new file mode 100644
index 0000000..8461d38
--- /dev/null
+++ b/tests/afrouter/templates/server.go
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// The template for the tester.
+// This template is filled in by the
+// test driver based on the configuration.
+
+package main
+
+import (
+	"fmt"
+	"net"
+	"errors"
+	"encoding/json"
+	"google.golang.org/grpc"
+	"golang.org/x/net/context"
+	"google.golang.org/grpc/metadata"
+	"github.com/opencord/voltha-go/common/log"
+	// Values generated by the go template
+	{{range .Imports}}
+	"{{.}}"
+	{{end}}
+	{{range .ProtoImports}}
+	{{.Short}} "{{.Package}}"
+	{{end}}
+	// End go template values
+)
+
+// The channels to get fed the expected results by the test driver.
+//var {{.Name}}Meta <-chan string
+////var {{.Name}}Payload <-chan string
+
+{{if .Ct}}{{else}}
+type reply struct {
+	repl interface{}
+}
+type incoming struct {
+	meta metadata.MD
+	payload string
+}
+type  serverCtl struct {
+	replyData chan * reply
+	incmg chan * incoming
+}
+{{end}}
+
+type {{.Name}}TestServer struct {
+	control *serverCtl
+	srv *grpc.Server
+}
+
+/*
+func init() {
+	{{if .Ct}}{{else}}
+	if _, err := log.SetDefaultLogger(log.JSON, 0, nil); err != nil {
+		log.With(log.Fields{"error": err}).Fatal("Cannot setup logging")
+	}
+	{{end}}
+	{{.Name}}ListenAndServe()
+}
+*/
+
+
+func {{.Name}}ListenAndServe() error {
+	var s {{.Name}}TestServer
+
+	s.control = &serverCtl{replyData:make(chan *reply,1), incmg:make(chan *incoming,1)}
+	servers["{{.Name}}"] = s.control
+
+	log.Debugf("Starting server %s on port %d", "{{.Name}}", {{.Port}})
+	// THe test head always uses localhost 127.0.0.1
+	addr := fmt.Sprintf("127.0.0.1:%d", {{.Port}})
+
+	// Create the gRPC server
+	s.srv = grpc.NewServer()
+
+{{range .ProtoImports}}
+	// Register the handler object
+	{{.Short}}.Register{{.Service}}Server(s.srv, s)
+{{end}}
+
+	// Create the channel to listen on
+	lis, err := net.Listen("tcp", addr)
+	if err != nil {
+		log.Errorf("could not listen on %s: %s", addr, err)
+		return err
+	}
+
+	// Serve and Listen
+	go func() {
+		if err = s.srv.Serve(lis); err != nil {
+			log.Errorf("grpc serve error: %s", err)
+			return
+		}
+	}()
+
+	return err
+}
+
+{{range .Methods}}
+{{if .Ss}}
+func (ts {{$.Name}}TestServer) {{.Name}}(in *{{.Param}}, srvr {{.Pkg}}.{{.Svc}}_{{.Name}}Server) error {
+	return nil
+}
+{{else if .Cs}}
+func (ts {{$.Name}}TestServer) {{.Name}}({{.Pkg}}.{{.Svc}}_{{.Name}}Server) error {
+	return nil
+}
+{{else}}
+func  (ts {{$.Name}}TestServer) {{.Name}}(ctx context.Context, in *{{.Param}}) (*{{.Rtrn}}, error) {
+	var r * incoming = &incoming{}
+	// Read the metadata
+	if md,ok := metadata.FromIncomingContext(ctx); ok == false {
+		log.Error("Getting matadata during call to {{.Name}}")
+	} else {
+		r.meta = md.Copy()
+	}
+	// Read the data sent to the function
+	if parm,err := json.Marshal(in); err != nil {
+		log.Error("Marshalling the {{.Param}} for {{.Name}}")
+	} else {
+		r.payload = string(parm)
+	}
+	// Send the server information back to the test framework
+	ts.control.incmg <- r
+	// Read the value that needs to be returned from the channel
+	d := <-ts.control.replyData
+	switch r := d.repl.(type) {
+		case *{{.Rtrn}}:
+			return r, nil
+		default:
+			return nil, errors.New("Mismatched type in call to {{.Name}}")
+	}
+	return &{{.Rtrn}}{},nil
+}
+{{end}}
+{{end}}
+
diff --git a/tests/afrouter/templates/serverInit.go b/tests/afrouter/templates/serverInit.go
new file mode 100644
index 0000000..e97e6ff
--- /dev/null
+++ b/tests/afrouter/templates/serverInit.go
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018-present Open Networking Foundation
+
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+
+ * http://www.apache.org/licenses/LICENSE-2.0
+
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package main
+
+var servers map[string]*serverCtl
+
+func serverInit() error {
+	servers = make(map[string]*serverCtl)
+	{{range .}}
+	if err := {{.Name}}ListenAndServe(); err != nil {
+		return err
+	}
+	{{end}}
+	return nil
+}
+
+