Updates to the affinity router test framework as
well as bug fixes to the affinity router found by
the test framework.

Change-Id: I90e6baa9e9ee11bd8034498b8651e9e14512e528
diff --git a/tests/afrouter/templates/stats.go b/tests/afrouter/templates/stats.go
new file mode 100644
index 0000000..958bea7
--- /dev/null
+++ b/tests/afrouter/templates/stats.go
@@ -0,0 +1,126 @@
+/*
+ * 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"
+	"fmt"
+	//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:"passed"`
+	Info []string `json:"info"`
+}
+
+type TestSuite struct {
+	Name string `json:"name"`
+	Info []string `json:"info"`
+	TestCases []TestCase `json:"testCases"`
+}
+
+type TestRun struct {
+	TestSuites []TestSuite
+}
+
+func (tr * TestRun) testLog(format string, a ...interface{}) {
+
+	tridx := len(tr.TestSuites) - 1
+	tcidx := len(tr.TestSuites[tridx].TestCases) - 1
+
+	tr.TestSuites[tridx].TestCases[tcidx].Info =
+			append(tr.TestSuites[tridx].TestCases[tcidx].Info, fmt.Sprintf(format, a...))
+
+}
+
+func (tr * TestRun) suiteLog(format string, a ...interface{}) {
+
+	tridx := len(tr.TestSuites) - 1
+
+	tr.TestSuites[tridx].Info =
+			append(tr.TestSuites[tridx].Info, fmt.Sprintf(format, a...))
+
+}
+
+func readStats(statFn string) (*TestRun, error) {
+	// Check if the  stats file exists
+	if _,err := os.Stat(statFn); err != nil {
+		// Nothing to do, just return
+		return &TestRun{}, nil
+	}
+	rtrn := &TestRun{}
+	// The file is there, read it an unmarshal it into the stats struct
+	if statBytes, err := ioutil.ReadFile(statFn); err != nil {
+		log.Error(err)
+		return nil, err
+	} else if err := json.Unmarshal(statBytes, rtrn); err != nil {
+		log.Error(err)
+		return nil, err
+	}
+	return rtrn, nil
+}
+
+func writeStats(statFn string, stats * TestRun) error {
+	// 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 err
+	} else if err := ioutil.WriteFile(statFn+".new", statBytes, 0644); err != nil {
+		log.Error(err)
+		return err
+	}
+	if err := os.Rename(statFn, statFn+"~"); err != nil {
+		log.Error(err)
+		return err
+	}
+	if err := os.Rename(statFn+".new", statFn); err != nil {
+		log.Error(err)
+		return err
+	}
+	return nil
+}
+
+func (tr * TestRun) appendNew() {
+	tr.TestSuites = append(tr.TestSuites, TestSuite{})
+}
+
+func initStats(statFn string) error {
+	s := &TestRun{}
+
+	if statBytes, err := json.MarshalIndent(s, "","    "); err != nil {
+		log.Error(err)
+		return err
+	} else if err := ioutil.WriteFile(statFn, statBytes, 0644); err != nil {
+		log.Error(err)
+		return err
+	}
+
+	return nil
+}
+
+
+var statFn string
+var stats *TestRun