1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
5 // package service provides a cmd.Handler that brings up a system service.
19 "git.arvados.org/arvados.git/sdk/go/arvados"
20 "git.arvados.org/arvados.git/sdk/go/ctxlog"
21 "github.com/prometheus/client_golang/prometheus"
22 check "gopkg.in/check.v1"
25 func Test(t *testing.T) {
29 var _ = check.Suite(&Suite{})
38 func (*Suite) TestCommand(c *check.C) {
39 cf, err := ioutil.TempFile("", "cmd_test.")
40 c.Assert(err, check.IsNil)
41 defer os.Remove(cf.Name())
43 fmt.Fprintf(cf, "Clusters:\n zzzzz:\n SystemRootToken: abcde\n NodeProfiles: {\"*\": {\"arvados-controller\": {Listen: \":1234\"}}}")
45 healthCheck := make(chan bool, 1)
46 ctx, cancel := context.WithCancel(context.Background())
49 cmd := Command(arvados.ServiceNameController, func(ctx context.Context, _ *arvados.Cluster, token string, reg *prometheus.Registry) Handler {
50 c.Check(ctx.Value(contextKey), check.Equals, "bar")
51 c.Check(token, check.Equals, "abcde")
52 return &testHandler{ctx: ctx, healthCheck: healthCheck}
54 cmd.(*command).ctx = context.WithValue(ctx, contextKey, "bar")
56 done := make(chan bool)
57 var stdin, stdout, stderr bytes.Buffer
60 cmd.RunCommand("arvados-controller", []string{"-config", cf.Name()}, &stdin, &stdout, &stderr)
66 c.Error("command exited without health check")
69 c.Check(stdout.String(), check.Equals, "")
70 c.Check(stderr.String(), check.Matches, `(?ms).*"msg":"CheckHealth called".*`)
73 func (*Suite) TestTLS(c *check.C) {
74 cwd, err := os.Getwd()
75 c.Assert(err, check.IsNil)
77 stdin := bytes.NewBufferString(`
80 SystemRootToken: abcde
83 ExternalURL: "https://localhost:12345"
84 InternalURLs: {"https://localhost:12345": {}}
86 Key: file://` + cwd + `/../../services/api/tmp/self-signed.key
87 Certificate: file://` + cwd + `/../../services/api/tmp/self-signed.pem
90 called := make(chan bool)
91 cmd := Command(arvados.ServiceNameController, func(ctx context.Context, _ *arvados.Cluster, token string, reg *prometheus.Registry) Handler {
92 return &testHandler{handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
98 exited := make(chan bool)
99 var stdout, stderr bytes.Buffer
101 cmd.RunCommand("arvados-controller", []string{"-config", "-"}, stdin, &stdout, &stderr)
104 got := make(chan bool)
107 client := &http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}}}
108 for range time.NewTicker(time.Millisecond).C {
109 resp, err := client.Get("https://localhost:12345")
114 body, err := ioutil.ReadAll(resp.Body)
115 c.Check(err, check.IsNil)
116 c.Logf("status %d, body %s", resp.StatusCode, string(body))
117 c.Check(resp.StatusCode, check.Equals, http.StatusOK)
124 c.Error("command exited without calling handler")
125 case <-time.After(time.Second):
131 c.Error("command exited before client received response")
132 case <-time.After(time.Second):
135 c.Log(stderr.String())
138 type testHandler struct {
141 healthCheck chan bool
144 func (th *testHandler) Done() <-chan struct{} { return nil }
145 func (th *testHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { th.handler.ServeHTTP(w, r) }
146 func (th *testHandler) CheckHealth() error {
147 ctxlog.FromContext(th.ctx).Info("CheckHealth called")
149 case th.healthCheck <- true: