github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/featuretests/dblog_test.go (about) 1 // Copyright 2015 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package featuretests 5 6 import ( 7 "bufio" 8 "io/ioutil" 9 "time" 10 11 "github.com/juju/loggo" 12 "github.com/juju/names" 13 jujutesting "github.com/juju/testing" 14 jc "github.com/juju/testing/checkers" 15 gc "gopkg.in/check.v1" 16 "gopkg.in/mgo.v2/bson" 17 18 "github.com/juju/juju/agent" 19 "github.com/juju/juju/api" 20 agentcmd "github.com/juju/juju/cmd/jujud/agent" 21 agenttesting "github.com/juju/juju/cmd/jujud/agent/testing" 22 "github.com/juju/juju/cmd/jujud/util/password" 23 "github.com/juju/juju/feature" 24 "github.com/juju/juju/state" 25 coretesting "github.com/juju/juju/testing" 26 "github.com/juju/juju/testing/factory" 27 "github.com/juju/juju/version" 28 "github.com/juju/juju/worker/logsender" 29 "github.com/juju/juju/worker/peergrouper" 30 ) 31 32 // dblogSuite tests that logs flow correctly from the machine and unit 33 // agents over the API into MongoDB. These are very much integration 34 // tests with more detailed testing of the individual components 35 // being done in unit tests. 36 type dblogSuite struct { 37 agenttesting.AgentSuite 38 } 39 40 func (s *dblogSuite) SetUpTest(c *gc.C) { 41 s.SetInitialFeatureFlags("db-log") 42 s.AgentSuite.SetUpTest(c) 43 s.PatchValue(&password.EnsureJujudPassword, func() error { return nil }) 44 45 // Change the path to "juju-run", so that the 46 // tests don't try to write to /usr/local/bin. 47 file, _ := ioutil.TempFile("", "juju-run") 48 defer file.Close() 49 s.PatchValue(&agentcmd.JujuRun, file.Name()) 50 } 51 52 func (s *dblogSuite) TestMachineAgentLogsGoToDB(c *gc.C) { 53 s.SetFeatureFlags("db-log") 54 foundLogs := s.runMachineAgentTest(c) 55 c.Assert(foundLogs, jc.IsTrue) 56 } 57 58 func (s *dblogSuite) TestMachineAgentLogsGoToDBWithJES(c *gc.C) { 59 s.SetFeatureFlags(feature.JES) 60 foundLogs := s.runMachineAgentTest(c) 61 c.Assert(foundLogs, jc.IsTrue) 62 } 63 64 func (s *dblogSuite) TestMachineAgentWithoutFeatureFlag(c *gc.C) { 65 s.SetFeatureFlags() 66 foundLogs := s.runMachineAgentTest(c) 67 c.Assert(foundLogs, jc.IsFalse) 68 } 69 70 func (s *dblogSuite) TestUnitAgentLogsGoToDB(c *gc.C) { 71 s.SetFeatureFlags("db-log") 72 foundLogs := s.runUnitAgentTest(c) 73 c.Assert(foundLogs, jc.IsTrue) 74 } 75 76 func (s *dblogSuite) TestUnitAgentLogsGoToDBWithJES(c *gc.C) { 77 s.SetFeatureFlags(feature.JES) 78 foundLogs := s.runUnitAgentTest(c) 79 c.Assert(foundLogs, jc.IsTrue) 80 } 81 82 func (s *dblogSuite) TestUnitAgentWithoutFeatureFlag(c *gc.C) { 83 s.SetFeatureFlags() 84 foundLogs := s.runUnitAgentTest(c) 85 c.Assert(foundLogs, jc.IsFalse) 86 } 87 88 func (s *dblogSuite) runMachineAgentTest(c *gc.C) bool { 89 // Create a machine and an agent for it. 90 m, password := s.Factory.MakeMachineReturningPassword(c, &factory.MachineParams{ 91 Nonce: agent.BootstrapNonce, 92 }) 93 94 s.PrimeAgent(c, m.Tag(), password, version.Current) 95 agentConf := agentcmd.NewAgentConf(s.DataDir()) 96 agentConf.ReadConfig(m.Tag().String()) 97 logsCh, err := logsender.InstallBufferedLogWriter(1000) 98 c.Assert(err, jc.ErrorIsNil) 99 machineAgentFactory := agentcmd.MachineAgentFactoryFn(agentConf, logsCh, nil) 100 a := machineAgentFactory(m.Id()) 101 102 // Ensure there's no logs to begin with. 103 c.Assert(s.getLogCount(c, m.Tag()), gc.Equals, 0) 104 105 // Start the agent. 106 go func() { c.Check(a.Run(nil), jc.ErrorIsNil) }() 107 defer a.Stop() 108 109 return s.waitForLogs(c, m.Tag()) 110 } 111 112 func (s *dblogSuite) runUnitAgentTest(c *gc.C) bool { 113 // Create a unit and an agent for it. 114 u, password := s.Factory.MakeUnitReturningPassword(c, nil) 115 s.PrimeAgent(c, u.Tag(), password, version.Current) 116 logsCh, err := logsender.InstallBufferedLogWriter(1000) 117 c.Assert(err, jc.ErrorIsNil) 118 a := agentcmd.NewUnitAgent(nil, logsCh) 119 s.InitAgent(c, a, "--unit-name", u.Name(), "--log-to-stderr=true") 120 121 // Ensure there's no logs to begin with. 122 c.Assert(s.getLogCount(c, u.Tag()), gc.Equals, 0) 123 124 // Start the agent. 125 go func() { c.Assert(a.Run(nil), jc.ErrorIsNil) }() 126 defer a.Stop() 127 128 return s.waitForLogs(c, u.Tag()) 129 } 130 131 func (s *dblogSuite) getLogCount(c *gc.C, entity names.Tag) int { 132 // TODO(mjs) - replace this with State's functionality for reading 133 // logs from the DB, once it gets this. This will happen before 134 // the DB logging feature branch is merged. 135 logs := s.Session.DB("logs").C("logs") 136 count, err := logs.Find(bson.M{"n": entity.String()}).Count() 137 c.Assert(err, jc.ErrorIsNil) 138 return count 139 } 140 141 func (s *dblogSuite) waitForLogs(c *gc.C, entityTag names.Tag) bool { 142 for a := coretesting.LongAttempt.Start(); a.Next(); { 143 if s.getLogCount(c, entityTag) > 0 { 144 return true 145 } 146 } 147 return false 148 } 149 150 // debugLogDbSuite tests that the debuglog API works when logs are 151 // being read from the database. 152 type debugLogDbSuite struct { 153 agenttesting.AgentSuite 154 } 155 156 var _ = gc.Suite(&debugLogDbSuite{}) 157 158 func (s *debugLogDbSuite) SetUpSuite(c *gc.C) { 159 s.SetInitialFeatureFlags("db-log") 160 161 // Restart mongod with a the replicaset enabled. 162 mongod := jujutesting.MgoServer 163 mongod.Params = []string{"--replSet", "juju"} 164 mongod.Restart() 165 166 // Initiate the replicaset. 167 info := mongod.DialInfo() 168 args := peergrouper.InitiateMongoParams{ 169 DialInfo: info, 170 MemberHostPort: mongod.Addr(), 171 } 172 err := peergrouper.MaybeInitiateMongoServer(args) 173 c.Assert(err, jc.ErrorIsNil) 174 175 s.AgentSuite.SetUpSuite(c) 176 } 177 178 func (s *debugLogDbSuite) TearDownSuite(c *gc.C) { 179 // Restart mongod without the replicaset enabled so as not to 180 // affect other test that reply on this mongod instance in this 181 // package. 182 mongod := jujutesting.MgoServer 183 mongod.Params = []string{} 184 mongod.Restart() 185 186 s.AgentSuite.TearDownSuite(c) 187 } 188 189 func (s *debugLogDbSuite) TestLogsAPI(c *gc.C) { 190 dbLogger := state.NewDbLogger(s.State, names.NewMachineTag("99")) 191 defer dbLogger.Close() 192 193 t := time.Date(2015, 6, 23, 13, 8, 49, 0, time.UTC) 194 dbLogger.Log(t, "juju.foo", "code.go:42", loggo.INFO, "all is well") 195 dbLogger.Log(t.Add(time.Second), "juju.bar", "go.go:99", loggo.ERROR, "no it isn't") 196 197 lines := make(chan string) 198 go func(numLines int) { 199 client := s.APIState.Client() 200 reader, err := client.WatchDebugLog(api.DebugLogParams{}) 201 c.Assert(err, jc.ErrorIsNil) 202 defer reader.Close() 203 204 bufReader := bufio.NewReader(reader) 205 for n := 0; n < numLines; n++ { 206 line, err := bufReader.ReadString('\n') 207 c.Assert(err, jc.ErrorIsNil) 208 lines <- line 209 } 210 }(3) 211 212 assertLine := func(expected string) { 213 select { 214 case actual := <-lines: 215 c.Assert(actual, gc.Equals, expected) 216 case <-time.After(coretesting.LongWait): 217 c.Fatal("timed out waiting for log line") 218 } 219 } 220 221 // Read the 2 lines that are in the logs collection. 222 assertLine("machine-99: 2015-06-23 13:08:49 INFO juju.foo code.go:42 all is well\n") 223 assertLine("machine-99: 2015-06-23 13:08:50 ERROR juju.bar go.go:99 no it isn't\n") 224 225 // Now write and observe another log. This should be read from the oplog. 226 dbLogger.Log(t.Add(2*time.Second), "ju.jitsu", "no.go:3", loggo.WARNING, "beep beep") 227 assertLine("machine-99: 2015-06-23 13:08:51 WARNING ju.jitsu no.go:3 beep beep\n") 228 }