misc: add test framework for host stack
Type: feature
Signed-off-by: Filip Tehlar <ftehlar@cisco.com>
Change-Id: I5a64a2c095cae3a4d5f8fdc73e624b010339ec8e
diff --git a/extras/hs-test/main.go b/extras/hs-test/main.go
new file mode 100755
index 0000000..1014917
--- /dev/null
+++ b/extras/hs-test/main.go
@@ -0,0 +1,155 @@
+package main
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "os"
+ "os/exec"
+ "os/signal"
+
+ "git.fd.io/govpp.git/api"
+)
+
+type CfgTable map[string]func([]string) *ActionResult
+
+var cfgTable CfgTable
+
+type ConfFn func(context.Context, api.Connection) error
+
+func newVppContext() (context.Context, context.CancelFunc) {
+ ctx, cancel := signal.NotifyContext(
+ context.Background(),
+ os.Interrupt,
+ )
+ return ctx, cancel
+}
+
+func Vppcli(runDir, command string) (string, error) {
+ cmd := exec.Command("vppctl", "-s", fmt.Sprintf("%s/var/run/vpp/cli.sock", runDir), command)
+ o, err := cmd.CombinedOutput()
+ if err != nil {
+ fmt.Printf("failed to execute command: '%v'.\n", err)
+ }
+ fmt.Printf("Command output %s", string(o))
+ return string(o), err
+}
+
+func exitOnErrCh(ctx context.Context, cancel context.CancelFunc, errCh <-chan error) {
+ // If we already have an error, log it and exit
+ select {
+ case err := <-errCh:
+ fmt.Printf("%v", err)
+ default:
+ }
+ go func(ctx context.Context, errCh <-chan error) {
+ <-errCh
+ cancel()
+ }(ctx, errCh)
+}
+
+func writeSyncFile(res *ActionResult) error {
+ syncFile := "/tmp/sync/rc"
+
+ var jsonRes JsonResult
+
+ jsonRes.ErrOutput = res.ErrOutput
+ jsonRes.StdOutput = res.StdOutput
+ if res.Err != nil {
+ jsonRes.Code = 1
+ jsonRes.Desc = fmt.Sprintf("%s :%v", res.Desc, res.Err)
+ } else {
+ jsonRes.Code = 0
+ }
+
+ str, err := json.Marshal(jsonRes)
+ if err != nil {
+ return fmt.Errorf("error marshaling json result data! %v", err)
+ }
+
+ _, err = os.Open(syncFile)
+ if err != nil {
+ // expecting the file does not exist
+ f, e := os.Create(syncFile)
+ if e != nil {
+ return fmt.Errorf("failed to open sync file")
+ }
+ defer f.Close()
+ f.Write([]byte(str))
+ } else {
+ return fmt.Errorf("sync file exists, delete the file frst")
+ }
+ return nil
+}
+
+func NewActionResult(err error, opts ...ActionResultOptionFn) *ActionResult {
+ res := &ActionResult{
+ Err: err,
+ }
+ for _, o := range opts {
+ o(res)
+ }
+ return res
+}
+
+type ActionResultOptionFn func(res *ActionResult)
+
+func ActionResultWithDesc(s string) ActionResultOptionFn {
+ return func(res *ActionResult) {
+ res.Desc = s
+ }
+}
+
+func ActionResultWithStderr(s string) ActionResultOptionFn {
+ return func(res *ActionResult) {
+ res.ErrOutput = s
+ }
+}
+
+func ActionResultWithStdout(s string) ActionResultOptionFn {
+ return func(res *ActionResult) {
+ res.ErrOutput = s
+ }
+}
+
+func OkResult() *ActionResult {
+ return NewActionResult(nil)
+}
+
+func reg(key string, fn func([]string) *ActionResult) {
+ cfgTable[key] = fn
+}
+
+func processArgs() *ActionResult {
+ fn := cfgTable[os.Args[1]]
+ if fn == nil {
+ return NewActionResult(fmt.Errorf("internal: no config found for %s", os.Args[1]))
+ }
+ return fn(os.Args)
+}
+
+func main() {
+ if len(os.Args) == 0 {
+ fmt.Println("args required")
+ return
+ }
+
+ if os.Args[1] == "rm" {
+ topology, err := LoadTopology(TopologyDir, os.Args[2])
+ if err != nil {
+ fmt.Printf("falied to load topologies: %v\n", err)
+ os.Exit(1)
+ }
+ topology.Unconfigure()
+ os.Exit(0)
+ }
+
+ RegisterActions()
+
+ var err error
+ res := processArgs()
+ err = writeSyncFile(res)
+ if err != nil {
+ fmt.Printf("failed to write to sync file: %v\n", err)
+ }
+}