github.com/axw/juju@v0.0.0-20161005053422-4bd6544d08d4/worker/introspection/socket_test.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package introspection_test 5 6 import ( 7 "bufio" 8 "bytes" 9 "fmt" 10 "io/ioutil" 11 "net" 12 "os" 13 "regexp" 14 "runtime" 15 16 "github.com/juju/testing" 17 jc "github.com/juju/testing/checkers" 18 gc "gopkg.in/check.v1" 19 20 "github.com/juju/juju/worker" 21 "github.com/juju/juju/worker/introspection" 22 "github.com/juju/juju/worker/workertest" 23 ) 24 25 type suite struct { 26 testing.IsolationSuite 27 } 28 29 var _ = gc.Suite(&suite{}) 30 31 func (s *suite) TestConfigValidation(c *gc.C) { 32 w, err := introspection.NewWorker(introspection.Config{}) 33 c.Check(w, gc.IsNil) 34 c.Assert(err, gc.ErrorMatches, "empty SocketName not valid") 35 } 36 37 func (s *suite) TestStartStop(c *gc.C) { 38 if runtime.GOOS != "linux" { 39 c.Skip("introspection worker not supported on non-linux") 40 } 41 42 w, err := introspection.NewWorker(introspection.Config{ 43 SocketName: "introspection-test", 44 }) 45 c.Assert(err, jc.ErrorIsNil) 46 workertest.CheckKill(c, w) 47 } 48 49 type introspectionSuite struct { 50 testing.IsolationSuite 51 52 name string 53 worker worker.Worker 54 reporter introspection.DepEngineReporter 55 } 56 57 var _ = gc.Suite(&introspectionSuite{}) 58 59 func (s *introspectionSuite) SetUpTest(c *gc.C) { 60 if runtime.GOOS != "linux" { 61 c.Skip("introspection worker not supported on non-linux") 62 } 63 s.IsolationSuite.SetUpTest(c) 64 s.reporter = nil 65 s.worker = nil 66 s.startWorker(c) 67 } 68 69 func (s *introspectionSuite) startWorker(c *gc.C) { 70 s.name = fmt.Sprintf("introspection-test-%d", os.Getpid()) 71 w, err := introspection.NewWorker(introspection.Config{ 72 SocketName: s.name, 73 Reporter: s.reporter, 74 }) 75 c.Assert(err, jc.ErrorIsNil) 76 s.worker = w 77 s.AddCleanup(func(c *gc.C) { 78 workertest.CheckKill(c, w) 79 }) 80 } 81 82 func (s *introspectionSuite) call(c *gc.C, url string) []byte { 83 path := "@" + s.name 84 conn, err := net.Dial("unix", path) 85 c.Assert(err, jc.ErrorIsNil) 86 defer conn.Close() 87 88 _, err = fmt.Fprintf(conn, "GET %s HTTP/1.0\r\n\r\n", url) 89 c.Assert(err, jc.ErrorIsNil) 90 91 buf, err := ioutil.ReadAll(conn) 92 c.Assert(err, jc.ErrorIsNil) 93 return buf 94 } 95 96 func (s *introspectionSuite) TestCmdLine(c *gc.C) { 97 buf := s.call(c, "/debug/pprof/cmdline") 98 c.Assert(buf, gc.NotNil) 99 matches(c, buf, ".*/introspection.test") 100 } 101 102 func (s *introspectionSuite) TestGoroutineProfile(c *gc.C) { 103 buf := s.call(c, "/debug/pprof/goroutine") 104 c.Assert(buf, gc.NotNil) 105 matches(c, buf, `^goroutine profile: total \d+`) 106 } 107 108 func (s *introspectionSuite) TestMissingReporter(c *gc.C) { 109 buf := s.call(c, "/depengine/") 110 matches(c, buf, "404 Not Found") 111 matches(c, buf, "missing reporter") 112 } 113 114 func (s *introspectionSuite) TestEngineReporter(c *gc.C) { 115 // We need to make sure the existing worker is shut down 116 // so we can connect to the socket. 117 workertest.CheckKill(c, s.worker) 118 s.reporter = &reporter{ 119 values: map[string]interface{}{ 120 "working": true, 121 }, 122 } 123 s.startWorker(c) 124 buf := s.call(c, "/depengine/") 125 126 matches(c, buf, "200 OK") 127 matches(c, buf, "working: true") 128 } 129 130 // matches fails if regex is not found in the contents of b. 131 // b is expected to be the response from the pprof http server, and will 132 // contain some HTTP preamble that should be ignored. 133 func matches(c *gc.C, b []byte, regex string) { 134 re, err := regexp.Compile(regex) 135 c.Assert(err, jc.ErrorIsNil) 136 r := bytes.NewReader(b) 137 sc := bufio.NewScanner(r) 138 for sc.Scan() { 139 if re.MatchString(sc.Text()) { 140 return 141 } 142 } 143 c.Fatalf("%q did not match regex %q", string(b), regex) 144 } 145 146 type reporter struct { 147 values map[string]interface{} 148 } 149 150 func (r *reporter) Report() map[string]interface{} { 151 return r.values 152 }