func TestClient_Start(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) socketFile, l := createSocketServer(t) defer l.Close() var startContent string readChan := setupReadRequest(t, l, &startContent, "REQUEST OK\n") client := New(socketFile) err := client.Start( "echo", []string{"123"}, "dir", []string{"FOO=bar"}, "/a", "/b", "123", "456", time.Second, ) tt.TestExpectSuccess(t, err) select { case <-readChan: case <-time.After(time.Second): tt.Fatalf(t, "Expected to have read client response within 1 second") } expectedRequest := "1\n6\n2\n5\nSTART4\necho1\n3\n1231\n3\ndir1\n7\nFOO=bar2\n2\n/a2\n/b2\n3\n1233\n456" tt.TestEqual(t, startContent, expectedRequest) }
func TestClient_Exec(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) socketFile, l := createSocketServer(t) defer l.Close() var execContent string readChan := setupReadRequest(t, l, &execContent, "REQUEST OK\n") client := New(socketFile) err := client.Exec( []string{"/sbin/init", "foo"}, []string{"FOO=bar"}, "/a", "/b", time.Second, ) tt.TestExpectSuccess(t, err) select { case <-readChan: case <-time.After(time.Second): tt.Fatalf(t, "Expected to have read client response within 1 second") } expectedRequest := "1\n4\n1\n4\nEXEC2\n10\n/sbin/init3\nfoo1\n7\nFOO=bar2\n2\n/a2\n/b" tt.TestEqual(t, execContent, expectedRequest) }
func TestEnvMap(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) expected := []string{ "START_COMMAND=XYZ", "TEST_CROSSREF1=cross_pkg2", "TEST_CROSSREF2=cross_pkg1", "TEST_CROSSREF_VAL1=cross_pkg1", "TEST_CROSSREF_VAL2=cross_pkg2", "TEST_ENV_VARIABLE=TEST_ENV_CONTENT", "TEST_MERGE_UNDEFINED=undef:", "TEST_MERGE_VARIABLE=pkg2:pkg1:", "TEST_OVERRIDE_VARIABLE=pkg2", } root := NewEnvMap() root.Set("TEST_ENV_VARIABLE", "TEST_ENV_CONTENT") root.Set("TEST_MERGE_VARIABLE", "pkg1:$TEST_MERGE_VARIABLE") root.Set("TEST_MERGE_UNDEFINED", "undef:$TEST_NOT_SET") root.Set("TEST_OVERRIDE_VARIABLE", "pkg1") root.Set("TEST_CROSSREF1", "$TEST_CROSSREF_VAL2") root.Set("TEST_CROSSREF_VAL1", "cross_pkg1") root.Set("START_COMMAND", "XYZ") c1 := root.NewChild() c1.Set("TEST_MERGE_VARIABLE", "pkg2:$TEST_MERGE_VARIABLE") c1.Set("TEST_OVERRIDE_VARIABLE", "pkg2") c1.Set("TEST_CROSSREF2", "$TEST_CROSSREF_VAL1") c1.Set("TEST_CROSSREF_VAL2", "cross_pkg2") c1.Set("START_COMMAND", "XYZ") envstrs := c1.Strings() // Sort the two list just in case. sort.Sort(sort.StringSlice(envstrs)) sort.Sort(sort.StringSlice(expected)) msg := make([]string, 0, len(envstrs)) failed := false a := func(fmtstr string, args ...interface{}) { msg = append(msg, fmt.Sprintf(fmtstr, args...)) } for i := 0; i < len(expected) || i < len(envstrs); i++ { if i >= len(expected) { a("\t'' > '%s'", envstrs[i]) } else if i >= len(envstrs) { a("\t'%s' < ''", expected[i]) } else if expected[i] != envstrs[i] { a("\t'%s' != '%s'", expected[i], envstrs[i]) } else { a("\t'%s' == '%s'", expected[i], envstrs[i]) continue } failed = true } if failed == true { tt.Fatalf(t, "results are not the same:\n%s", strings.Join(msg, "\n")) } }
func TestEnvMapSimple(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) // Simple case. e := NewEnvMap() e.Set("A", "$A") m := e.Map() if len(m) != 1 { tt.Fatalf(t, "Invlid number of environment variables set.") } else if v, ok := m["A"]; ok == false { tt.Fatalf(t, "$A was not defined.") } else if v != "" { tt.Fatalf(t, "$A has a bad value: %s", v) } }
func TestClient_Stop(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) // To effectively test stop, we also want to ensure a request is inflight and // that it makes that request return. socketFile, l := createSocketServer(t) defer l.Close() setupRequestThatNeverReturns(t, l) stopReadyCh := make(chan bool) waitDoneCh := make(chan bool) client := New(socketFile) go func() { close(stopReadyCh) defer close(waitDoneCh) err := client.Wait(time.Minute) if err == nil { t.Errorf("wait should have returned an error about the client stopping") return } if err.Error() != "client is stopped." { t.Errorf("client should have returned an error that the client was stopping, but got: %v", err) } }() select { case <-stopReadyCh: case <-time.After(5 * time.Second): tt.Fatalf(t, "the wait goroutine wasn't setup within 5 seconds") } tt.TestEqual(t, client.Stopped(), false) client.Stop() tt.TestEqual(t, client.Stopped(), true) select { case <-waitDoneCh: case <-time.After(5 * time.Second): tt.Fatalf(t, "the wait goroutine should have unblocked within 5 seconds") } }
func TestEnvMapGetRaw(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) root := NewEnvMap() root.Set("VARIABLE", "foo bar $STR") root.Set("VAR1", "abc 123 $VAR2") root.Set("VAR2", "xyz") if v, _ := root.Get("VARIABLE"); v != "foo bar " { tt.Fatalf(t, "Get(VARIABLE) should have blanked out STR: %q", v) } if v, _ := root.GetRaw("VARIABLE"); v != "foo bar $STR" { tt.Fatalf(t, "GetRaw(VARIABLE) should include raw $STR: %q", v) } if v, _ := root.Get("VAR1"); v != "abc 123 xyz" { tt.Fatalf(t, "Get(VAR1) should have parsed mentioned variables: %q", v) } if v, _ := root.GetRaw("VAR1"); v != "abc 123 $VAR2" { tt.Fatalf(t, "GetRaw(VAR1) should be the raw string: %q", v) } }
func TestClient_StopAndWaitRace(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) // This test is going to monkey with the internals. The goal is to get Wait() // to start before calling Stop(), but to then have the request flow begin // until after Stop() is done. The goal is test a race around the combination // of the two. // // This is done by triggering the Stop() call immediately after // l.Accept(). The Wait() call is a request that will never return with a 1 // minute timeout, and we validate the response from Wait() is about stopping // rather than hitting the timeout. socketFile, l := createSocketServer(t) defer l.Close() client := New(socketFile) waitDoneCh := make(chan bool) go func() { l.Accept() client.Stop() }() go func() { defer close(waitDoneCh) err := client.Wait(5 * time.Second) if err == nil { t.Errorf("wait should have returned an error about the client stopping") return } if err.Error() != "client is stopped." { t.Errorf("client should have returned an error that the client was stopping, but got: %v", err) } }() select { case <-waitDoneCh: case <-time.After(6 * time.Second): tt.Fatalf(t, "the wait goroutine should have unblocked within 5 seconds") } }
func TestClient_Wait(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) socketFile, l := createSocketServer(t) defer l.Close() var waitContent string readChan := setupReadRequest(t, l, &waitContent, "REQUEST OK\n") client := New(socketFile) err := client.Wait(time.Second) tt.TestExpectSuccess(t, err) select { case <-readChan: case <-time.After(time.Second): tt.Fatalf(t, "Expected to have read client response within 1 second") } expectedRequest := "1\n1\n1\n4\nWAIT" tt.TestEqual(t, waitContent, expectedRequest) }
func TestClient_Status(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) socketFile, l := createSocketServer(t) defer l.Close() var statusContent string readChan := setupReadRequest(t, l, &statusContent, "REQUEST OK\nfoo\nrunning\nbar\nexit(1)\nend\n") client := New(socketFile) status, err := client.Status(time.Second) tt.TestExpectSuccess(t, err) select { case <-readChan: case <-time.After(time.Second): tt.Fatalf(t, "Expected to have read client response within 1 second") } expectedStatus := map[string]string{"foo": "running", "bar": "exit(1)"} tt.TestEqual(t, status, expectedStatus) }
func TestClient_Mount(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) socketFile, l := createSocketServer(t) defer l.Close() var startContent string readChan := setupReadRequest(t, l, &startContent, "REQUEST OK\n") client := New(socketFile) err := client.Mount("/src", "/dst", "ext4", 0, "", time.Second) tt.TestExpectSuccess(t, err) select { case <-readChan: case <-time.After(time.Second): tt.Fatalf(t, "Expected to have read client response within 1 second") } expectedRequest := "1\n2\n3\n5\nMOUNT4\n/src4\n/dst3\n4\next41\n00\n" tt.TestEqual(t, startContent, expectedRequest) }
func TestParseSimpleProcFile(t *testing.T) { tt.StartTest(t) defer tt.FinishTest(t) // Test 1: Success. lines := []string{ "aelm0 aelm1\taelm2", " belm0 belm1\t belm2\t\t\t", "", "delm0"} f := tt.WriteTempFile(t, strings.Join(lines, "\n")) err := ParseSimpleProcFile( f, func(index int, line string) error { if index > len(lines) { tt.Fatalf(t, "Too many lines read: %d", index) } else if line != lines[index] { tt.Fatalf(t, "Invalid line read: %s", line) } return nil }, func(line int, index int, elm string) error { switch { case line == 0 && index == 0 && elm == "aelm0": case line == 0 && index == 1 && elm == "aelm1": case line == 0 && index == 2 && elm == "aelm2": case line == 1 && index == 0 && elm == "belm0": case line == 1 && index == 1 && elm == "belm1": case line == 1 && index == 2 && elm == "belm2": case line == 3 && index == 0 && elm == "delm0": default: tt.Fatalf( t, "Unknown element read: %d, %d, %s", line, index, elm) } return nil }) if err != nil { tt.Fatalf(t, "Unexpected error from ParseSimpleProcFile()") } // Test 2: No function defined. This should be successful. err = ParseSimpleProcFile(f, nil, nil) if err != nil { tt.Fatalf(t, "Unexpected error from ParseSimpleProcFile()") } // Test 3: ef returns an error. err = ParseSimpleProcFile( f, func(index int, line string) error { return fmt.Errorf("error.") }, nil) if err == nil { tt.Fatalf(t, "Expected error not returned.") } // Test 4: lf returns an error. err = ParseSimpleProcFile( f, nil, func(line int, index int, elm string) error { return fmt.Errorf("error.") }) if err == nil { tt.Fatalf(t, "Expected error not returned.") } // Test 6: last case lf operation. err = ParseSimpleProcFile( f, func(index int, line string) error { if line == "delm0" { return fmt.Errorf("error") } return nil }, nil) // Test 5: last case lf operation. err = ParseSimpleProcFile( f, nil, func(line int, index int, elm string) error { if elm == "delm0" { return fmt.Errorf("error") } return nil }) }