github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/cmd/jujud/introspect/introspect_test.go (about) 1 // Copyright 2017 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package introspect_test 5 6 import ( 7 "bufio" 8 "context" 9 "flag" 10 "fmt" 11 "io/ioutil" 12 "net" 13 "net/http" 14 "os" 15 "os/exec" 16 "path/filepath" 17 "runtime" 18 "strings" 19 stdtesting "testing" 20 21 "github.com/juju/cmd" 22 "github.com/juju/cmd/cmdtesting" 23 jc "github.com/juju/testing/checkers" 24 gc "gopkg.in/check.v1" 25 "gopkg.in/juju/names.v2" 26 27 "github.com/juju/juju/cmd/jujud/introspect" 28 cmdutil "github.com/juju/juju/cmd/jujud/util" 29 "github.com/juju/juju/testing" 30 ) 31 32 type IntrospectCommandSuite struct { 33 testing.BaseSuite 34 } 35 36 func (s *IntrospectCommandSuite) SetUpTest(c *gc.C) { 37 if runtime.GOOS == "windows" { 38 c.Skip("introspection socket does not run on windows") 39 } 40 s.BaseSuite.SetUpTest(c) 41 s.PatchValue(&cmdutil.DataDir, c.MkDir()) 42 } 43 44 var _ = gc.Suite(&IntrospectCommandSuite{}) 45 46 func (s *IntrospectCommandSuite) TestInitErrors(c *gc.C) { 47 s.assertInitError(c, "either a query path or a --listen address must be specified") 48 s.assertInitError(c, "a query path may not be specified with --listen", "query-path", "--listen=foo") 49 s.assertInitError(c, `unrecognized args: \["path"\]`, "query", "path") 50 } 51 52 func (*IntrospectCommandSuite) assertInitError(c *gc.C, expect string, args ...string) { 53 err := cmdtesting.InitCommand(&introspect.IntrospectCommand{}, args) 54 c.Assert(err, gc.ErrorMatches, expect) 55 } 56 57 func (*IntrospectCommandSuite) run(c *gc.C, args ...string) (*cmd.Context, error) { 58 return cmdtesting.RunCommand(c, &introspect.IntrospectCommand{ 59 IntrospectionSocketName: func(tag names.Tag) string { 60 return filepath.Join(cmdutil.DataDir, "jujud-"+tag.String()) 61 }, 62 }, args...) 63 } 64 65 func (s *IntrospectCommandSuite) TestAutoDetectMachineAgent(c *gc.C) { 66 machineDir := filepath.Join(cmdutil.DataDir, "agents", "machine-1024") 67 err := os.MkdirAll(machineDir, 0755) 68 c.Assert(err, jc.ErrorIsNil) 69 70 _, err = s.run(c, "query") 71 c.Assert(err, gc.ErrorMatches, ".*jujud-machine-1024.*") 72 } 73 74 func (s *IntrospectCommandSuite) TestAutoDetectMachineAgentFails(c *gc.C) { 75 machineDir := filepath.Join(cmdutil.DataDir, "agents") 76 err := os.MkdirAll(machineDir, 0755) 77 c.Assert(err, jc.ErrorIsNil) 78 79 _, err = s.run(c, "query") 80 c.Assert(err, gc.ErrorMatches, "could not determine machine tag") 81 } 82 83 func (s *IntrospectCommandSuite) TestAgentSpecified(c *gc.C) { 84 _, err := s.run(c, "query", "--agent=unit-foo-0") 85 c.Assert(err, gc.ErrorMatches, ".*jujud-unit-foo-0.*") 86 } 87 88 func (s *IntrospectCommandSuite) TestQuery(c *gc.C) { 89 listener, err := net.Listen("unix", "@"+filepath.Join(cmdutil.DataDir, "jujud-machine-0")) 90 c.Assert(err, jc.ErrorIsNil) 91 defer listener.Close() 92 93 srv := newServer(listener) 94 go srv.Serve(listener) 95 defer srv.Shutdown(context.Background()) 96 97 ctx, err := s.run(c, "query", "--agent=machine-0") 98 c.Assert(err, jc.ErrorIsNil) 99 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "hello") 100 } 101 102 func (s *IntrospectCommandSuite) TestQueryFails(c *gc.C) { 103 listener, err := net.Listen("unix", "@"+filepath.Join(cmdutil.DataDir, "jujud-machine-0")) 104 c.Assert(err, jc.ErrorIsNil) 105 defer listener.Close() 106 107 srv := newServer(listener) 108 go srv.Serve(listener) 109 defer srv.Shutdown(context.Background()) 110 111 ctx, err := s.run(c, "missing", "--agent=machine-0") 112 c.Assert(err, gc.ErrorMatches, `response returned 404 \(Not Found\)`) 113 c.Assert(cmdtesting.Stderr(ctx), gc.Equals, fmt.Sprintf(` 114 Querying @%s introspection socket: missing 115 404 page not found 116 `[1:], filepath.Join(cmdutil.DataDir, "jujud-machine-0"))) 117 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 118 119 ctx, err = s.run(c, "badness", "--agent=machine-0") 120 c.Assert(err, gc.ErrorMatches, `response returned 500 \(Internal Server Error\)`) 121 c.Assert(cmdtesting.Stderr(ctx), gc.Equals, fmt.Sprintf(` 122 Querying @%s introspection socket: badness 123 argh 124 `[1:], filepath.Join(cmdutil.DataDir, "jujud-machine-0"))) 125 c.Assert(cmdtesting.Stdout(ctx), gc.Equals, "") 126 } 127 128 func (s *IntrospectCommandSuite) TestListen(c *gc.C) { 129 socketName := filepath.Join(cmdutil.DataDir, "jujud-machine-0") 130 listener, err := net.Listen("unix", "@"+socketName) 131 c.Assert(err, jc.ErrorIsNil) 132 defer listener.Close() 133 134 srv := newServer(listener) 135 go srv.Serve(listener) 136 defer srv.Shutdown(context.Background()) 137 138 ctx, cancel := context.WithCancel(context.Background()) 139 defer cancel() 140 cmd := exec.CommandContext(ctx, os.Args[0], "-run-listen="+socketName) 141 stderr, err := cmd.StderrPipe() 142 c.Assert(err, jc.ErrorIsNil) 143 defer stderr.Close() 144 err = cmd.Start() 145 c.Assert(err, jc.ErrorIsNil) 146 147 scanner := bufio.NewScanner(stderr) 148 c.Assert(scanner.Scan(), jc.IsTrue) 149 line := scanner.Text() 150 c.Assert(line, gc.Matches, "Exposing @.* introspection socket on 127.0.0.1:.*") 151 152 fields := strings.Fields(line) 153 addr := fields[len(fields)-1] 154 resp, err := http.Get(fmt.Sprintf("http://%s/query", addr)) 155 c.Assert(err, jc.ErrorIsNil) 156 defer resp.Body.Close() 157 c.Assert(resp.StatusCode, gc.Equals, http.StatusOK) 158 body, err := ioutil.ReadAll(resp.Body) 159 c.Assert(err, jc.ErrorIsNil) 160 c.Assert(string(body), gc.Equals, "hello") 161 } 162 163 func newServer(l net.Listener) *http.Server { 164 mux := http.NewServeMux() 165 mux.HandleFunc("/query", func(w http.ResponseWriter, r *http.Request) { 166 w.Write([]byte("hello")) 167 }) 168 mux.HandleFunc("/badness", func(w http.ResponseWriter, r *http.Request) { 169 http.Error(w, "argh", http.StatusInternalServerError) 170 }) 171 srv := &http.Server{} 172 srv.Handler = mux 173 return srv 174 } 175 176 var flagListen = flag.String("run-listen", "", "Name of the Unix socket to connect the introspect command to using --listen=:0") 177 178 func TestRunListen(t *stdtesting.T) { 179 if *flagListen != "" { 180 introspectCommand := &introspect.IntrospectCommand{ 181 IntrospectionSocketName: func(names.Tag) string { 182 return *flagListen 183 }, 184 } 185 args := append(flag.Args(), "--listen=127.0.0.1:0", "--agent=machine-0") 186 if err := cmdtesting.InitCommand(introspectCommand, args); err != nil { 187 t.Fatal(err) 188 } 189 ctx, err := cmd.DefaultContext() 190 if err != nil { 191 t.Fatal(err) 192 } 193 if err := introspectCommand.Run(ctx); err != nil { 194 t.Fatal(err) 195 } 196 } 197 }