Fixed/improved tests startup and exit
[src/xds/xds-server.git] / test / main_test.go
index ced75a6..1c577a9 100644 (file)
@@ -17,6 +17,7 @@
 package xdsservertest
 
 import (
+       "encoding/json"
        "fmt"
        "io"
        "log"
@@ -27,6 +28,7 @@ import (
        "time"
 
        common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git/golib"
+       "gerrit.automotivelinux.org/gerrit/src/xds/xds-server/lib/xdsconfig"
        "gerrit.automotivelinux.org/gerrit/src/xds/xds-server/lib/xsapiv1"
        socketio_client "github.com/sebd71/go-socket.io-client"
 )
@@ -46,6 +48,7 @@ type IOSockClient struct {
 var HTTPCli *common.HTTPClient
 var logDir string
 var sCli *IOSockClient
+var prefixURL string
 
 // Debug function used to print debug logs
 func Debug(t *testing.T, args ...interface{}) {
@@ -82,10 +85,39 @@ func Copy(src, dst string) error {
        return out.Close()
 }
 
+// init function will run once before execution of test functions begins.
+func init() {
+       // Check dependency
+       err := checkTestDep()
+       if err != nil {
+               log.Fatal(err)
+       }
+}
+
+// isCommandAvailable verify if a command/utility is available
+func isCommandAvailable(name string) bool {
+       cmd := exec.Command("/bin/sh", "-c", "command -v "+name)
+       if err := cmd.Run(); err != nil {
+               return false
+       }
+       return true
+}
+
+// checkTestDep checks if all dependency tools are available to be able to run tests
+func checkTestDep() error {
+       for _, cmd := range dependency_tools {
+               if !isCommandAvailable(cmd) {
+                       return fmt.Errorf(cmd + " is not installed and is mandatory to run tests")
+               }
+       }
+       return nil
+}
+
+// initEnv
 func initEnv(launchProcess bool) {
        if launchProcess {
                /*kill xds-server if needed*/
-               cmd := exec.Command("killall", "-9", "xds-server")
+               cmd := exec.Command("pkill", "-9", "xds-server")
                if err := cmd.Start(); err != nil {
                        log.Fatal(err)
                }
@@ -123,6 +155,11 @@ func launchXdsServer(proc **os.Process) *os.File {
        if err != nil {
                log.Fatal(err)
        }
+       var argsProcess = []string{"../bin/xds-server",
+               "-l", "debug",
+               "-c", testConfigFile,
+       }
+
        tmpProc, err := os.StartProcess(argsProcess[0], argsProcess, &os.ProcAttr{
                Files: []*os.File{os.Stdin, file, file},
        })
@@ -133,7 +170,8 @@ func launchXdsServer(proc **os.Process) *os.File {
        return file
 }
 
-func getHTTPClient(lvl int) (*common.HTTPClient, *os.File) {
+// getHTTPClient
+func getHTTPClient(lvl int, url string) (*common.HTTPClient, *os.File) {
        logFile := logDir + logFileClient
        file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY, 0644)
        if err != nil {
@@ -147,11 +185,27 @@ func getHTTPClient(lvl int) (*common.HTTPClient, *os.File) {
                LogPrefix:           "XDSSERVERTEST: ",
                LogLevel:            lvl,
        }
-       HTTPcli, err := common.HTTPNewClient(prefixURL, conf)
-       if err != nil {
-               log.Fatal(err)
+
+       // Try to connect during 30 seconds
+       var HTTPcli *common.HTTPClient
+       retry := 30
+       for retry > 0 {
+               if HTTPcli, err = common.HTTPNewClient(url, conf); err == nil {
+                       break
+               }
+               if retry < 25 {
+                       log.Printf("Establishing connection to XDS Server (retry %d/10)", retry)
+               }
+               time.Sleep(time.Second)
+               retry--
        }
+       if retry == 0 {
+               log.Fatalf("Cannot establish connection with xds-server:\n %v", err)
+       }
+
        log.Printf("HTTP session ID : %v", HTTPcli.GetClientID())
+
+       // Basic check
        var ver xsapiv1.Version
        err = HTTPcli.Get("/version", &ver)
        if err != nil {
@@ -189,10 +243,12 @@ func NewIoSocketClient(url, clientID string) (*IOSockClient, error) {
                sCli.Connected = false
        })
 
-       log.Printf("Connect websocket with url=%v clientId=%v\n", prefixURL, HTTPCli.GetClientID())
        return sCli, nil
 }
+
+// TestMain is the main entry point of testsuite
 func TestMain(m *testing.M) {
+
        /* useful for debugging, preventing from launching xds-server
         * it can be launch separately */
        launchProcess := true
@@ -208,25 +264,49 @@ func TestMain(m *testing.M) {
                        if status, err := p.Wait(); err != nil {
                                log.Fatalf("status=%v\n err=%v\n", status, err)
                        }
+                       os.Exit(0)
                }(proc)
                defer fileXdsServer.Close()
        }
-       time.Sleep(1 * time.Second)
 
+       // Extract URL from _test-config.json file
+       fd, _ := os.Open(testConfigFile)
+       defer fd.Close()
+       fCfg := xdsconfig.FileConfig{}
+       if err := json.NewDecoder(fd).Decode(&fCfg); err != nil {
+               log.Fatalf("Cannot decode test config file %v : %v", testConfigFile, err)
+       }
+
+       if fCfg.HTTPPort == "" {
+               log.Fatalf("Cannot retrieve httpPort in test config file %v", testConfigFile)
+       }
+       prefixURL := "http://localhost:" + fCfg.HTTPPort
+
+       // Start HTTP client to send test commands
        lvl := common.HTTPLogLevelDebug
        var fileHTTPClient *os.File
-       HTTPCli, fileHTTPClient = getHTTPClient(lvl)
+       HTTPCli, fileHTTPClient = getHTTPClient(lvl, prefixURL)
        defer fileHTTPClient.Close()
        var err error
        sCli, err = NewIoSocketClient(prefixURL, HTTPCli.GetClientID())
        if err != nil {
                log.Fatal(err)
        }
-
        if HTTPCli == nil {
-               log.Fatal("HTTPCLi is nil")
+               log.Fatal("HTTPCli is nil")
        }
+
+       // Run tests
        res := m.Run()
        defer os.Exit(res)
+
+       // Gracefully stop xds-server process
+       if err := proc.Signal(os.Interrupt); err != nil {
+               log.Fatalf("xds-server proc interrupt error : %v", err)
+       }
+
+       // Should not be executed, normal exit must be above go routine after on p.Wait returns
+       time.Sleep(10 * time.Second)
+       log.Printf("xds-server not gravefully stop, kill it\n")
        proc.Kill()
 }