func (s *WorkerTestSuite) SetUpSuite(t *C) { s.dsn = os.Getenv("PCT_TEST_MYSQL_DSN") s.logChan = make(chan *proto.LogEntry, 100) s.logger = pct.NewLogger(s.logChan, "qan-worker") s.now = time.Now() s.mysqlInstance = proto.ServiceInstance{Service: "mysql", InstanceId: 1} s.config = qan.Config{ ServiceInstance: s.mysqlInstance, Start: []mysql.Query{ mysql.Query{Set: "SET GLOBAL slow_query_log=OFF"}, mysql.Query{Set: "SET GLOBAL long_query_time=0.123"}, mysql.Query{Set: "SET GLOBAL slow_query_log=ON"}, }, Stop: []mysql.Query{ mysql.Query{Set: "SET GLOBAL slow_query_log=OFF"}, mysql.Query{Set: "SET GLOBAL long_query_time=10"}, }, Interval: 60, // 1 min MaxSlowLogSize: 1073741824, // 1 GiB RemoveOldSlowLogs: true, ExampleQueries: true, WorkerRunTime: 60, // 1 min CollectFrom: "slowlog", } s.nullmysql = mock.NewNullMySQL() }
func (i *InstallerTestSuite) TestIsSupportedMySQLVersion(t *C) { var got bool var err error agentConfig := &agent.Config{} flags := installer.Flags{} apiConnector := pct.NewAPI() api := api.New(apiConnector, false) logChan := make(chan *proto.LogEntry, 100) logger := pct.NewLogger(logChan, "instance-repo") instanceRepo := instance.NewRepo(logger, pct.Basedir.Dir("config"), apiConnector) terminal := term.NewTerminal(os.Stdin, false, true) inst := installer.NewInstaller(terminal, "", api, instanceRepo, agentConfig, flags) conn := mock.NewNullMySQL() errSomethingWentWrong := fmt.Errorf("Something went wrong") conn.SetAtLeastVersion(false, errSomethingWentWrong) got, err = inst.IsVersionSupported(conn) t.Assert(conn.Version, Equals, agent.MIN_SUPPORTED_MYSQL_VERSION) t.Assert(err, Equals, errSomethingWentWrong) t.Assert(got, Equals, false) conn.SetAtLeastVersion(true, nil) got, err = inst.IsVersionSupported(conn) t.Assert(conn.Version, Equals, agent.MIN_SUPPORTED_MYSQL_VERSION) t.Assert(err, IsNil) t.Assert(got, Equals, true) conn.Close() }
func (s *WorkerTestSuite) TestWorkerSlow001Half(t *C) { // This tests that the worker will stop processing events before // the end of the slow log file. 358 is the last byte of the first // (of 2) events. i := &qan.Interval{ Number: 1, StartTime: s.now, StopTime: s.now.Add(1 * time.Minute), Filename: inputDir + "slow001.log", StartOffset: 0, EndOffset: 358, } got, err := s.RunWorker(s.config, mock.NewNullMySQL(), i) t.Check(err, IsNil) expect := &qan.Result{} if err := test.LoadMmReport(outputDir+"slow001-half.json", expect); err != nil { t.Fatal(err) } sort.Sort(ByQueryId(got.Class)) sort.Sort(ByQueryId(expect.Class)) if ok, diff := IsDeeply(got, expect); !ok { Dump(got) t.Error(diff) } }
func (s *TestSuite) TestStartStop(t *C) { mockConn := mock.NewNullMySQL() mockConnFactory := &mock.ConnectionFactory{ Conn: mockConn, } m := monitor.NewMonitor(s.logger, mockConnFactory) dsn := "fake:dsn@tcp(127.0.0.1:3306)/?parseTime=true" /** * Register new subscriber */ // Set initial uptime mockConn.SetUptime(10) t.Assert(mockConn.GetUptimeCount(), Equals, uint(0)) subChan, err := m.Add(dsn) t.Assert(err, IsNil) t.Assert(mockConn.GetUptimeCount(), Equals, uint(1), Commentf("MRMS didn't checked uptime after adding first subscriber")) /** * Start MRMS */ interval := 1 * time.Second err = m.Start(interval) t.Assert(err, IsNil) // Imitate MySQL restart by setting uptime to 5s (previously 10s) mockConn.SetUptime(5) // After max 1 second it should notify subscriber about MySQL restart var notified bool select { case notified = <-subChan: case <-time.After(1 * time.Second): } t.Assert(notified, Equals, true, Commentf("MySQL was restarted but MRMS didn't notify subscribers")) /** * Stop MRMS */ err = m.Stop() t.Assert(err, IsNil) // Check status status := m.Status() t.Assert(status, DeepEquals, map[string]string{ monitor.MONITOR_NAME: "Stopped", }) // Imitate MySQL restart by setting uptime to 1s (previously 5s) mockConn.SetUptime(1) // After stopping service it should not notify subscribers anymore time.Sleep(2 * time.Second) select { case notified = <-subChan: default: } t.Assert(notified, Equals, true, Commentf("MRMS notified subscribers after being stopped")) }
func (s *ManagerTestSuite) SetUpSuite(t *C) { s.dsn = os.Getenv("PCT_TEST_MYSQL_DSN") if s.dsn == "" { t.Fatal("PCT_TEST_MYSQL_DSN is not set") } s.realmysql = mysql.NewConnection(s.dsn) if err := s.realmysql.Connect(1); err != nil { t.Fatal(err) } s.reset = []mysql.Query{ mysql.Query{Set: "SET GLOBAL slow_query_log=OFF"}, mysql.Query{Set: "SET GLOBAL long_query_time=10"}, } s.nullmysql = mock.NewNullMySQL() s.logChan = make(chan *proto.LogEntry, 1000) s.logger = pct.NewLogger(s.logChan, "qan-test") s.intervalChan = make(chan *qan.Interval, 1) s.iter = mock.NewMockIntervalIter(s.intervalChan) s.iterFactory = &mock.IntervalIterFactory{ Iters: []qan.IntervalIter{s.iter}, TickChans: make(map[qan.IntervalIter]chan time.Time), } s.dataChan = make(chan interface{}, 2) s.spool = mock.NewSpooler(s.dataChan) s.workerFactory = &qan.SlowLogWorkerFactory{} var err error s.tmpDir, err = ioutil.TempDir("/tmp", "agent-test") t.Assert(err, IsNil) if err := pct.Basedir.Init(s.tmpDir); err != nil { t.Fatal(err) } s.configDir = pct.Basedir.Dir("config") s.im = instance.NewRepo(pct.NewLogger(s.logChan, "im-test"), s.configDir, s.api) data, err := json.Marshal(&proto.MySQLInstance{ Hostname: "db1", DSN: s.dsn, }) t.Assert(err, IsNil) s.im.Add("mysql", 1, data, false) s.mysqlInstance = proto.ServiceInstance{Service: "mysql", InstanceId: 1} links := map[string]string{ "agent": "http://localhost/agent", "instances": "http://localhost/instances", } s.api = mock.NewAPI("http://localhost", "http://localhost", "123", "abc-123-def", links) }
func (s *TestSuite) TestGlobalSubscribe(t *C) { mockConn := mock.NewNullMySQL() mockConnFactory := &mock.ConnectionFactory{ Conn: mockConn, } m := monitor.NewMonitor(s.logger, mockConnFactory) dsn := "fake:dsn@tcp(127.0.0.1:3306)/?parseTime=true" subChan, err := m.Add(dsn) t.Assert(err, IsNil) t.Assert(subChan, NotNil) gc, err := m.GlobalSubscribe() t.Assert(err, IsNil) t.Assert(gc, NotNil) }
func (s *TestSuite) Test2Subscribers(t *C) { mockConn := mock.NewNullMySQL() mockConnFactory := &mock.ConnectionFactory{ Conn: mockConn, } m := monitor.NewMonitor(s.logger, mockConnFactory) dsn := "fake:dsn@tcp(127.0.0.1:3306)/?parseTime=true" c1, err := m.Add(dsn) t.Assert(err, IsNil) c2, err := m.Add(dsn) t.Assert(err, IsNil) var notified bool mockConn.SetUptime(1) m.Check() select { case notified = <-c1: default: } t.Check(notified, Equals, false) select { case notified = <-c2: default: } t.Check(notified, Equals, false) mockConn.SetUptime(2) m.Check() select { case notified = <-c1: default: } t.Check(notified, Equals, false) select { case notified = <-c2: default: } t.Check(notified, Equals, false) }
func (s *WorkerTestSuite) TestWorkerSlow001(t *C) { i := &qan.Interval{ Number: 1, StartTime: s.now, StopTime: s.now.Add(1 * time.Minute), Filename: inputDir + "slow001.log", StartOffset: 0, EndOffset: 524, } got, err := s.RunWorker(s.config, mock.NewNullMySQL(), i) t.Check(err, IsNil) expect := &qan.Result{} test.LoadMmReport(outputDir+"slow001.json", expect) sort.Sort(ByQueryId(got.Class)) sort.Sort(ByQueryId(expect.Class)) if ok, diff := IsDeeply(got, expect); !ok { Dump(got) t.Error(diff) } }
func (s *AnalyzerTestSuite) SetUpSuite(t *C) { s.nullmysql = mock.NewNullMySQL() s.logChan = make(chan *proto.LogEntry, 1000) s.logger = pct.NewLogger(s.logChan, "qan-test") s.intervalChan = make(chan *qan.Interval, 1) s.iter = mock.NewIter(s.intervalChan) s.dataChan = make(chan interface{}, 1) s.spool = mock.NewSpooler(s.dataChan) var err error s.tmpDir, err = ioutil.TempDir("/tmp", "agent-test") t.Assert(err, IsNil) if err := pct.Basedir.Init(s.tmpDir); err != nil { t.Fatal(err) } s.configDir = pct.Basedir.Dir("config") s.im = instance.NewRepo(pct.NewLogger(s.logChan, "im-test"), s.configDir, s.api) data, err := json.Marshal(&proto.MySQLInstance{ Hostname: "bm-cloud-db01", Alias: "db01", DSN: "user:pass@tcp/", }) t.Assert(err, IsNil) s.im.Add("mysql", 1, data, false) s.mysqlInstance = proto.ServiceInstance{Service: "mysql", InstanceId: 1} links := map[string]string{ "agent": "http://localhost/agent", "instances": "http://localhost/instances", } s.api = mock.NewAPI("http://localhost", "http://localhost", "123", "abc-123-def", links) s.restartChan = make(chan bool, 1) }
func (s *ReportTestSuite) TestResult014(t *C) { si := proto.ServiceInstance{Service: "mysql", InstanceId: 1} config := qan.Config{ ServiceInstance: si, CollectFrom: "slowlog", Interval: 60, WorkerRunTime: 60, ReportLimit: 500, MaxSlowLogSize: 1024 * 1024 * 1000, } logChan := make(chan *proto.LogEntry, 1000) w := slowlog.NewWorker(pct.NewLogger(logChan, "w"), config, mock.NewNullMySQL()) i := &qan.Interval{ Filename: inputDir + "slow014.log", StartOffset: 0, EndOffset: 127118681, } w.Setup(i) result, err := w.Run() t.Assert(err, IsNil) w.Cleanup() start := time.Now().Add(-1 * time.Second) stop := time.Now() interval := &qan.Interval{ Filename: "slow.log", StartTime: start, StopTime: stop, StartOffset: 0, EndOffset: 127118680, } report := qan.MakeReport(config, interval, result) t.Check(report.Global.TotalQueries, Equals, uint64(4)) t.Check(report.Global.UniqueQueries, Equals, uint64(4)) t.Assert(report.Class, HasLen, 4) // This query required improving the log parser to get the correct checksum ID: t.Check(report.Class[0].Id, Equals, "DB9EF18846547B8C") }
func (s *WorkerTestSuite) TestWorkerSlow011(t *C) { // Percona Server rate limit i := &qan.Interval{ Number: 1, StartTime: s.now, StopTime: s.now.Add(1 * time.Minute), Filename: inputDir + "slow011.log", StartOffset: 0, EndOffset: 3000, } got, err := s.RunWorker(s.config, mock.NewNullMySQL(), i) t.Check(err, IsNil) expect := &qan.Result{} if err := test.LoadMmReport(outputDir+"slow011.json", expect); err != nil { t.Fatal(err) } sort.Sort(ByQueryId(got.Class)) sort.Sort(ByQueryId(expect.Class)) if same, diff := IsDeeply(got, expect); !same { Dump(got) t.Error(diff) } }
func (s *WorkerTestSuite) TestWorkerSlow001Resume(t *C) { // This tests that the worker will resume processing events from // somewhere in the slow log file. 359 is the first byte of the // second (of 2) events. i := &qan.Interval{ Number: 2, StartTime: s.now, StopTime: s.now.Add(1 * time.Minute), Filename: inputDir + "slow001.log", StartOffset: 359, EndOffset: 524, } got, err := s.RunWorker(s.config, mock.NewNullMySQL(), i) t.Check(err, IsNil) expect := &qan.Result{} test.LoadMmReport(outputDir+"slow001-resume.json", expect) sort.Sort(ByQueryId(got.Class)) sort.Sort(ByQueryId(expect.Class)) if ok, diff := IsDeeply(got, expect); !ok { Dump(got) t.Error(diff) } }
func (s *WorkerTestSuite) TestWorkerSlow001NoExamples(t *C) { i := &qan.Interval{ Number: 99, StartTime: s.now, StopTime: s.now.Add(1 * time.Minute), Filename: inputDir + "slow001.log", StartOffset: 0, EndOffset: 524, } config := s.config config.ExampleQueries = false got, err := s.RunWorker(config, mock.NewNullMySQL(), i) t.Check(err, IsNil) expect := &qan.Result{} if err := test.LoadMmReport(outputDir+"slow001-no-examples.json", expect); err != nil { t.Fatal(err) } sort.Sort(ByQueryId(got.Class)) sort.Sort(ByQueryId(expect.Class)) if same, diff := IsDeeply(got, expect); !same { Dump(got) t.Error(diff) } }
func (s *WorkerTestSuite) SetUpSuite(t *C) { s.dsn = os.Getenv("PCT_TEST_MYSQL_DSN") s.logChan = make(chan *proto.LogEntry, 100) s.logger = pct.NewLogger(s.logChan, "qan-worker") s.nullmysql = mock.NewNullMySQL() }
func (s *TestSuite) SetUpSuite(t *C) { s.nullmysql = mock.NewNullMySQL() s.logChan = make(chan *proto.LogEntry, 1000) s.logger = pct.NewLogger(s.logChan, "mrms-monitor-test") }
func (s *TestSuite) TestNotifications(t *C) { mockConn := mock.NewNullMySQL() mockConnFactory := &mock.ConnectionFactory{ Conn: mockConn, } m := monitor.NewMonitor(s.logger, mockConnFactory) dsn := "fake:dsn@tcp(127.0.0.1:3306)/?parseTime=true" /** * Register new subscriber */ // Set initial uptime mockConn.SetUptime(10) subChan, err := m.Add(dsn) t.Assert(err, IsNil) /** * MRMS should not send notification after first check for given dsn */ var notified bool select { case notified = <-subChan: default: } t.Assert(notified, Equals, false, Commentf("MySQL was not restarted (first check of MySQL server), but MRMS notified subscribers")) /** * If MySQL was restarted then MRMS should notify subscriber */ // Imitate MySQL restart by returning 0s uptime (previously 10s) mockConn.SetUptime(0) m.Check() notified = false select { case notified = <-subChan: default: } t.Assert(notified, Equals, true, Commentf("MySQL was restarted, but MRMS didn't notify subscribers")) /** * If MySQL was not restarted then MRMS should not notify subscriber */ // 2s uptime is higher than previous 0s, this indicates MySQL was not restarted mockConn.SetUptime(2) m.Check() notified = false select { case notified = <-subChan: default: } t.Assert(notified, Equals, false, Commentf("MySQL was not restarted, but MRMS notified subscribers")) /** * Now let's imitate MySQL server restart and let's wait 3 seconds before next check. * Since MySQL server was restarted and we waited 3s then uptime=3s * which is higher than last registered uptime=2s * * However we expect in this test that this is properly detected as MySQL restart * and the MRMS notifies subscribers */ waitTime := int64(3) time.Sleep(time.Duration(waitTime) * time.Second) mockConn.SetUptime(waitTime) m.Check() select { case notified = <-subChan: default: } t.Assert(notified, Equals, true, Commentf("MySQL was restarted (uptime overlaped last registered uptime), but MRMS didn't notify subscribers")) /** * After removing subscriber MRMS should not notify it anymore about MySQL restarts */ // Imitate MySQL restart by returning 0s uptime (previously 3s) mockConn.SetUptime(0) m.Remove(dsn, subChan) m.Check() notified = false select { case notified = <-subChan: default: } t.Assert(notified, Equals, false, Commentf("Subscriber was removed but MRMS still notified it about MySQL restart")) }