2 * Copyright (C) 2017-2018 "IoT.bzh"
3 * Author Clément Bénier <clement.benier@iot.bzh>
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
30 common "gerrit.automotivelinux.org/gerrit/src/xds/xds-common.git"
31 "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xdsconfig"
32 "gerrit.automotivelinux.org/gerrit/src/xds/xds-server.git/lib/xsapiv1"
33 socketio_client "github.com/sebd71/go-socket.io-client"
37 type IOSockClient struct {
39 Conn *socketio_client.Client
40 Options *socketio_client.Options
43 //ServerDiscoChan chan Disconnection
48 var HTTPCli *common.HTTPClient
50 var sCli *IOSockClient
53 // Debug function used to print debug logs
54 func Debug(t *testing.T, args ...interface{}) {
55 if os.Getenv("VERBOSE") != "" {
60 // Debugf function used to print debug logs
61 func Debugf(t *testing.T, format string, args ...interface{}) {
62 if os.Getenv("VERBOSE") != "" {
63 t.Logf(format, args...)
67 // Copy copies from src to dst until either EOF
68 func Copy(src, dst string) error {
69 in, err := os.Open(src)
75 out, err := os.Create(dst)
81 _, err = io.Copy(out, in)
88 // init function will run once before execution of test functions begins.
97 // isCommandAvailable verify if a command/utility is available
98 func isCommandAvailable(name string) bool {
99 cmd := exec.Command("/bin/sh", "-c", "command -v "+name)
100 if err := cmd.Run(); err != nil {
106 // checkTestDep checks if all dependency tools are available to be able to run tests
107 func checkTestDep() error {
108 for _, cmd := range dependency_tools {
109 if !isCommandAvailable(cmd) {
110 return fmt.Errorf(cmd + " is not installed and is mandatory to run tests")
117 func initEnv(launchProcess bool) {
119 /*kill xds-server if needed*/
120 cmd := exec.Command("pkill", "-9", "xds-server")
121 if err := cmd.Start(); err != nil {
126 /*set environment variable*/
127 rootTestLog := "/tmp/xds-server-test"
128 if err := os.Setenv(envRootCfgDir, rootTestLog); err != nil {
131 sdkDir := rootTestLog + "/sdks/"
132 if err := os.Setenv(envXdtSdk, sdkDir); err != nil {
135 if err := os.Setenv(envXdsServerWorkspaceDir, rootTestLog); err != nil {
138 if err := os.Setenv(envXdsServerRootCfgDir, rootTestLog); err != nil {
141 if err := os.Setenv("XDS_LOG_SILLY", "1"); err != nil {
144 /*remove and recreate working directories*/
145 os.RemoveAll(rootTestLog)
146 os.MkdirAll(rootTestLog, 0755)
147 logDir = rootTestLog + "/logs/"
148 os.MkdirAll(logDir, 0755)
151 /*prepare xds-server process*/
152 func launchXdsServer(proc **os.Process) *os.File {
153 logFile := logDir + logFileXdsServer
154 file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY, 0644)
158 var argsProcess = []string{"../bin/xds-server",
160 "-c", testConfigFile,
163 tmpProc, err := os.StartProcess(argsProcess[0], argsProcess, &os.ProcAttr{
164 Files: []*os.File{os.Stdin, file, file},
174 func getHTTPClient(lvl int, url string) (*common.HTTPClient, *os.File) {
175 logFile := logDir + logFileClient
176 file, err := os.OpenFile(logFile, os.O_CREATE|os.O_WRONLY, 0644)
180 conf := common.HTTPClientConfig{
181 URLPrefix: "/api/v1",
182 HeaderClientKeyName: "Xds-Sid",
185 LogPrefix: "XDSSERVERTEST: ",
189 // Try to connect during 30 seconds
190 var HTTPcli *common.HTTPClient
193 if HTTPcli, err = common.HTTPNewClient(url, conf); err == nil {
197 log.Printf("Establishing connection to XDS Server (retry %d/10)", retry)
199 time.Sleep(time.Second)
203 log.Fatalf("Cannot establish connection with xds-server:\n %v", err)
206 log.Printf("HTTP session ID : %v", HTTPcli.GetClientID())
209 var ver xsapiv1.Version
210 err = HTTPcli.Get("/version", &ver)
217 func NewIoSocketClient(url, clientID string) (*IOSockClient, error) {
220 sCli := &IOSockClient{
222 EmitMutex: &sync.Mutex{},
223 Options: &socketio_client.Options{
224 Transport: "websocket",
225 Header: make(map[string][]string),
228 sCli.Options.Header["XDS-SID"] = []string{clientID}
230 sCli.Conn, err = socketio_client.NewClient(url, sCli.Options)
232 return nil, fmt.Errorf("IO.socket connection error: " + err.Error())
235 sCli.Conn.On("connection", func() {
236 sCli.Connected = true
239 sCli.Conn.On("disconnection", func(err error) {
241 log.Printf("WS disconnection event with err: %v\n", err)
243 sCli.Connected = false
249 // TestMain is the main entry point of testsuite
250 func TestMain(m *testing.M) {
252 /* useful for debugging, preventing from launching xds-server
253 * it can be launch separately */
254 launchProcess := true
255 log.Printf("TestMain: launchProcess is %v, so launching xds-server", launchProcess)
256 initEnv(launchProcess)
259 var fileXdsServer *os.File
261 fileXdsServer = launchXdsServer(&proc)
262 go func(p *os.Process) {
263 log.Print("xds-server is launching")
264 if status, err := p.Wait(); err != nil {
265 log.Fatalf("status=%v\n err=%v\n", status, err)
269 defer fileXdsServer.Close()
272 // Extract URL from _test-config.json file
273 fd, _ := os.Open(testConfigFile)
275 fCfg := xdsconfig.FileConfig{}
276 if err := json.NewDecoder(fd).Decode(&fCfg); err != nil {
277 log.Fatalf("Cannot decode test config file %v : %v", testConfigFile, err)
280 if fCfg.HTTPPort == "" {
281 log.Fatalf("Cannot retrieve httpPort in test config file %v", testConfigFile)
283 prefixURL := "http://localhost:" + fCfg.HTTPPort
285 // Start HTTP client to send test commands
286 lvl := common.HTTPLogLevelDebug
287 var fileHTTPClient *os.File
288 HTTPCli, fileHTTPClient = getHTTPClient(lvl, prefixURL)
289 defer fileHTTPClient.Close()
291 sCli, err = NewIoSocketClient(prefixURL, HTTPCli.GetClientID())
296 log.Fatal("HTTPCli is nil")
303 // Gracefully stop xds-server process
304 if err := proc.Signal(os.Interrupt); err != nil {
305 log.Fatalf("xds-server proc interrupt error : %v", err)
308 // Should not be executed, normal exit must be above go routine after on p.Wait returns
309 time.Sleep(10 * time.Second)
310 log.Printf("xds-server not gravefully stop, kill it\n")