From 433d10b31924631f5b4c18b828301a4fe45bbf0c Mon Sep 17 00:00:00 2001 From: Tom Clegg Date: Fri, 22 Mar 2019 16:20:29 -0400 Subject: [PATCH] 14807: Add lib/service test. Arvados-DCO-1.1-Signed-off-by: Tom Clegg --- build/run-tests.sh | 2 ++ lib/service/cmd.go | 8 ++++- lib/service/cmd_test.go | 78 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 lib/service/cmd_test.go diff --git a/build/run-tests.sh b/build/run-tests.sh index a6858f315f..f2c7a3e867 100755 --- a/build/run-tests.sh +++ b/build/run-tests.sh @@ -85,6 +85,7 @@ lib/dispatchcloud/container lib/dispatchcloud/scheduler lib/dispatchcloud/ssh_executor lib/dispatchcloud/worker +lib/service services/api services/arv-git-httpd services/crunchstat @@ -953,6 +954,7 @@ gostuff=( lib/dispatchcloud/scheduler lib/dispatchcloud/ssh_executor lib/dispatchcloud/worker + lib/service sdk/go/arvados sdk/go/arvadosclient sdk/go/auth diff --git a/lib/service/cmd.go b/lib/service/cmd.go index e23791b30a..2d3fb90259 100644 --- a/lib/service/cmd.go +++ b/lib/service/cmd.go @@ -31,6 +31,7 @@ type NewHandlerFunc func(_ context.Context, _ *arvados.Cluster, _ *arvados.NodeP type command struct { newHandler NewHandlerFunc svcName arvados.ServiceName + ctx context.Context // enables tests to shutdown service; no public API yet } // Command returns a cmd.Handler that loads site config, calls @@ -43,6 +44,7 @@ func Command(svcName arvados.ServiceName, newHandler NewHandlerFunc) cmd.Handler return &command{ newHandler: newHandler, svcName: svcName, + ctx: context.Background(), } } @@ -77,7 +79,7 @@ func (c *command) RunCommand(prog string, args []string, stdin io.Reader, stdout log = ctxlog.New(stderr, cluster.Logging.Format, cluster.Logging.Level).WithFields(logrus.Fields{ "PID": os.Getpid(), }) - ctx := ctxlog.Context(context.Background(), log) + ctx := ctxlog.Context(c.ctx, log) profileName := *nodeProfile if profileName == "" { @@ -123,6 +125,10 @@ func (c *command) RunCommand(prog string, args []string, stdin io.Reader, stdout if _, err := daemon.SdNotify(false, "READY=1"); err != nil { log.WithError(err).Errorf("error notifying init daemon") } + go func() { + <-ctx.Done() + srv.Close() + }() err = srv.Wait() if err != nil { return 1 diff --git a/lib/service/cmd_test.go b/lib/service/cmd_test.go new file mode 100644 index 0000000000..62960dc31c --- /dev/null +++ b/lib/service/cmd_test.go @@ -0,0 +1,78 @@ +// Copyright (C) The Arvados Authors. All rights reserved. +// +// SPDX-License-Identifier: Apache-2.0 + +// package service provides a cmd.Handler that brings up a system service. +package service + +import ( + "bytes" + "context" + "fmt" + "io/ioutil" + "net/http" + "os" + "testing" + + "git.curoverse.com/arvados.git/sdk/go/arvados" + "git.curoverse.com/arvados.git/sdk/go/ctxlog" + check "gopkg.in/check.v1" +) + +func Test(t *testing.T) { + check.TestingT(t) +} + +var _ = check.Suite(&Suite{}) + +type Suite struct{} + +func (*Suite) TestCommand(c *check.C) { + cf, err := ioutil.TempFile("", "cmd_test.") + c.Assert(err, check.IsNil) + defer os.Remove(cf.Name()) + defer cf.Close() + fmt.Fprintf(cf, "Clusters:\n zzzzz:\n SystemRootToken: abcde\n NodeProfiles: {\"*\": {\"arvados-controller\": {Listen: \":1234\"}}}") + + healthCheck := make(chan bool, 1) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + cmd := Command(arvados.ServiceNameController, func(ctx context.Context, _ *arvados.Cluster, _ *arvados.NodeProfile, token string) Handler { + c.Check(ctx.Value("foo"), check.Equals, "bar") + c.Check(token, check.Equals, "abcde") + return &testHandler{ctx: ctx, healthCheck: healthCheck} + }) + cmd.(*command).ctx = context.WithValue(ctx, "foo", "bar") + + done := make(chan bool) + var stdin, stdout, stderr bytes.Buffer + + go func() { + cmd.RunCommand("arvados-controller", []string{"-config", cf.Name()}, &stdin, &stdout, &stderr) + close(done) + }() + select { + case <-healthCheck: + case <-done: + c.Error("command exited without health check") + } + cancel() + c.Check(stdout.String(), check.Equals, "") + c.Check(stderr.String(), check.Matches, `(?ms).*"msg":"CheckHealth called".*`) +} + +type testHandler struct { + ctx context.Context + healthCheck chan bool +} + +func (th *testHandler) ServeHTTP(http.ResponseWriter, *http.Request) {} +func (th *testHandler) CheckHealth() error { + ctxlog.FromContext(th.ctx).Info("CheckHealth called") + select { + case th.healthCheck <- true: + default: + } + return nil +} -- 2.30.2