func (s *ManagerTestSuite) TestGetConfig(t *C) {
	// Make a qan.Manager with mock factories.
	mockConnFactory := &mock.ConnectionFactory{Conn: s.nullmysql}
	a := mock.NewQanAnalyzer()
	f := mock.NewQanAnalyzerFactory(a)
	m := qan.NewManager(s.logger, s.clock, s.im, s.mrmsMonitor, mockConnFactory, f)
	t.Assert(m, NotNil)

	// Write a realistic qan.conf config to disk.
	config := qan.Config{
		ServiceInstance: s.mysqlInstance,
		CollectFrom:     "slowlog",
		Interval:        300,
		MaxWorkers:      1,
		WorkerRunTime:   600,
		Start: []mysql.Query{
			mysql.Query{Set: "SET GLOBAL slow_query_log=OFF"},
			mysql.Query{Set: "SET GLOBAL long_query_time=0.456"},
			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"},
		},
	}
	err := pct.Basedir.WriteConfig("qan", &config)
	t.Assert(err, IsNil)

	qanConfig, err := json.Marshal(config)
	t.Assert(err, IsNil)

	// Start the manager and analyzer.
	err = m.Start()
	t.Check(err, IsNil)
	test.WaitStatus(1, m, "qan", "Running")

	// Get the manager config which should be just the analyzer config.
	got, errs := m.GetConfig()
	t.Assert(errs, HasLen, 0)
	t.Assert(got, HasLen, 1)
	expect := []proto.AgentConfig{
		{
			InternalService: "qan",
			Config:          string(qanConfig),
			Running:         true,
		},
	}
	if same, diff := IsDeeply(got, expect); !same {
		Dump(got)
		t.Error(diff)
	}

	// Stop the manager.
	err = m.Stop()
	t.Assert(err, IsNil)
}
func (s *ManagerTestSuite) TestBadCmd(t *C) {
	mockConnFactory := &mock.ConnectionFactory{Conn: s.nullmysql}
	a := mock.NewQanAnalyzer()
	f := mock.NewQanAnalyzerFactory(a)
	m := qan.NewManager(s.logger, s.clock, s.im, s.mrmsMonitor, mockConnFactory, f)
	t.Assert(m, NotNil)
	err := m.Start()
	t.Check(err, IsNil)
	defer m.Stop()
	test.WaitStatus(1, m, "qan", "Running")
	cmd := &proto.Cmd{
		User:      "******",
		Ts:        time.Now(),
		AgentUuid: "123",
		Service:   "qan",
		Cmd:       "foo", // bad cmd
	}
	reply := m.Handle(cmd)
	t.Assert(reply.Error, Equals, "Unknown command: foo")
}
func (s *ManagerTestSuite) TestStarNoConfig(t *C) {
	// Make a qan.Manager with mock factories.
	mockConnFactory := &mock.ConnectionFactory{Conn: s.nullmysql}
	a := mock.NewQanAnalyzer()
	f := mock.NewQanAnalyzerFactory(a)
	m := qan.NewManager(s.logger, s.clock, s.im, s.mrmsMonitor, mockConnFactory, f)
	t.Assert(m, NotNil)

	// qan.Manager should be able to start without a qan.conf, i.e. no analyzer.
	err := m.Start()
	t.Check(err, IsNil)

	// Wait for qan.Manager.Start() to finish.
	test.WaitStatus(1, m, "qan", "Running")

	// No analyzer is configured, so the mock analyzer should not be started.
	select {
	case <-a.StartChan:
		t.Error("Analyzer.Start() called")
	default:
	}

	// And the mock analyzer's status should not be reported.
	status := m.Status()
	t.Check(status["qan"], Equals, "Running")

	// Stop the manager.
	err = m.Stop()
	t.Assert(err, IsNil)

	// No analyzer is configured, so the mock analyzer should not be stop.
	select {
	case <-a.StartChan:
		t.Error("Analyzer.Stop() called")
	default:
	}
}
func (s *ManagerTestSuite) TestStartService(t *C) {
	// Make and start a qan.Manager with mock factories, no analyzer yet.
	mockConnFactory := &mock.ConnectionFactory{Conn: s.nullmysql}
	a := mock.NewQanAnalyzer()
	f := mock.NewQanAnalyzerFactory(a)
	m := qan.NewManager(s.logger, s.clock, s.im, s.mrmsMonitor, mockConnFactory, f)
	t.Assert(m, NotNil)
	err := m.Start()
	t.Check(err, IsNil)
	test.WaitStatus(1, m, "qan", "Running")

	// Create the qan config.
	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:          300,        // 5 min
		MaxSlowLogSize:    1073741824, // 1 GiB
		RemoveOldSlowLogs: true,
		ExampleQueries:    true,
		MaxWorkers:        2,
		WorkerRunTime:     600, // 10 min
		CollectFrom:       "slowlog",
	}

	// Send a StartService cmd with the qan config to start an analyzer.
	now := time.Now()
	qanConfig, _ := json.Marshal(config)
	cmd := &proto.Cmd{
		User:      "******",
		Ts:        now,
		AgentUuid: "123",
		Service:   "agent",
		Cmd:       "StartService",
		Data:      qanConfig,
	}
	reply := m.Handle(cmd)
	t.Assert(reply.Error, Equals, "")

	// The manager writes the qan config to disk.
	data, err := ioutil.ReadFile(pct.Basedir.ConfigFile("qan"))
	t.Check(err, IsNil)
	gotConfig := &qan.Config{}
	err = json.Unmarshal(data, gotConfig)
	t.Check(err, IsNil)
	if same, diff := IsDeeply(gotConfig, config); !same {
		Dump(gotConfig)
		t.Error(diff)
	}

	// Now the manager and analyzer should be running.
	status := m.Status()
	t.Check(status["qan"], Equals, "Running")
	t.Check(status["qan-analyzer"], Equals, "ok")

	// Try to start the same analyzer again. It results in an error because
	// double tooling is not allowed.
	reply = m.Handle(cmd)
	t.Check(reply.Error, Equals, "qan-analyzer service is running")

	// Send a StopService cmd to stop the analyzer.
	// todo-1.1: send Data with analyzer instance to stop.
	now = time.Now()
	cmd = &proto.Cmd{
		User:      "******",
		Ts:        now,
		AgentUuid: "123",
		Service:   "qan",
		Cmd:       "StopService",
	}
	reply = m.Handle(cmd)
	t.Assert(reply.Error, Equals, "")

	// Now the manager is still running, but the analyzer is not.
	status = m.Status()
	t.Check(status["qan"], Equals, "Running")

	// And the manager has removed the qan config from disk so next time
	// the agent starts the analyzer is not started.
	t.Check(test.FileExists(pct.Basedir.ConfigFile("qan")), Equals, false)

	// StopService should be idempotent, so send it again and expect no error.
	reply = m.Handle(cmd)
	t.Assert(reply.Error, Equals, "")

	// Stop the manager.
	err = m.Stop()
	t.Assert(err, IsNil)
}
func (s *ManagerTestSuite) TestStartWithConfig(t *C) {
	for _, analyzerType := range []string{"slowlog", "perfschema"} {
		// Make a qan.Manager with mock factories.
		mockConnFactory := &mock.ConnectionFactory{Conn: s.nullmysql}
		a := mock.NewQanAnalyzer()
		f := mock.NewQanAnalyzerFactory(a)
		m := qan.NewManager(s.logger, s.clock, s.im, s.mrmsMonitor, mockConnFactory, f)
		t.Assert(m, NotNil)

		// Write a realistic qan.conf config to disk.
		config := qan.Config{
			ServiceInstance: s.mysqlInstance,
			CollectFrom:     analyzerType,
			Interval:        300,
			MaxWorkers:      1,
			WorkerRunTime:   600,
			Start: []mysql.Query{
				mysql.Query{Set: "SET GLOBAL slow_query_log=OFF"},
				mysql.Query{Set: "SET GLOBAL long_query_time=0.456"},
				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"},
			},
		}
		err := pct.Basedir.WriteConfig("qan", &config)
		t.Assert(err, IsNil)

		// qan.Start() reads qan.conf from disk and starts an analyzer for it.
		err = m.Start()
		t.Check(err, IsNil)

		// Wait until qan.Start() calls analyzer.Start().
		if !test.WaitState(a.StartChan) {
			t.Fatal("Timeout waiting for <-a.StartChan")
		}

		// After starting, the manager's status should be Running and the analyzer's
		// status should be reported too.
		status := m.Status()
		t.Check(status["qan"], Equals, "Running")
		t.Check(status["qan-analyzer"], Equals, "ok")

		// Check the args passed by the manager to the analyzer factory.
		if len(f.Args) == 0 {
			t.Error("len(f.Args) == 0, expected 1")
		} else {
			t.Check(f.Args, HasLen, 1)
			t.Check(f.Args[0].Config, DeepEquals, config)
			t.Check(f.Args[0].Name, Equals, "qan-analyzer")
		}

		// qan.Stop() stops the analyzer and leaves qan.conf on disk.
		err = m.Stop()
		t.Assert(err, IsNil)

		// Wait until qan.Stop() calls analyzer.Stop().
		if !test.WaitState(a.StopChan) {
			t.Fatal("Timeout waiting for <-a.StopChan")
		}

		// qan.conf still exists after qan.Stop().
		t.Check(test.FileExists(pct.Basedir.ConfigFile("qan")), Equals, true)

		// The analyzer is no longer reported in the status because it was stopped
		// and removed when the manager was stopped.
		status = m.Status()
		t.Check(status["qan"], Equals, "Stopped")
	}
}