func (s *ManagerTestSuite) SetUpSuite(t *C) {
	s.logChan = make(chan *proto.LogEntry, 10)
	s.logger = pct.NewLogger(s.logChan, "sysconfig-manager-test")

	s.mockMonitor = mock.NewSysconfigMonitor()
	s.factory = mock.NewSysconfigMonitorFactory([]sysconfig.Monitor{s.mockMonitor})

	s.tickChan = make(chan time.Time)

	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")

	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.im = instance.NewRepo(pct.NewLogger(s.logChan, "im-test"), s.configDir, s.api)
}
示例#2
0
func (s *SenderTestSuite) TestSendEmptyFile(t *C) {
	// Make mock spooler which returns a single file name and zero bytes
	// for that file.
	spool := mock.NewSpooler(nil)
	spool.FilesOut = []string{"empty.json"}
	spool.DataOut = map[string][]byte{"empty.json": []byte{}}

	// Start the sender.
	sender := data.NewSender(s.logger, s.client)
	err := sender.Start(spool, s.tickerChan, 5, false)
	t.Assert(err, IsNil)

	// Tick to make sender send.
	s.tickerChan <- time.Now()

	// Sender shouldn't zero-length data files...
	data := test.WaitBytes(s.dataChan)
	t.Check(data, HasLen, 0)

	err = sender.Stop()
	t.Assert(err, IsNil)

	// ...but it should remove them.
	t.Check(len(spool.DataOut), Equals, 0)
}
示例#3
0
func (s *SenderTestSuite) TestBlackhole(t *C) {
	spool := mock.NewSpooler(nil)

	slow001, err := ioutil.ReadFile(sample + "slow001.json")
	if err != nil {
		t.Fatal(err)
	}

	spool.FilesOut = []string{"slow001.json"}
	spool.DataOut = map[string][]byte{"slow001.json": slow001}

	sender := data.NewSender(s.logger, s.client)

	err = sender.Start(spool, s.tickerChan, 5, true) // <- true = enable blackhole
	if err != nil {
		t.Fatal(err)
	}

	s.tickerChan <- time.Now()

	data := test.WaitBytes(s.dataChan)
	if len(data) != 0 {
		t.Errorf("Data sent despite blackhole; got %+v", data)
	}

	select {
	case s.respChan <- &proto.Response{Code: 200}:
		// Should not recv response because no data was sent.
		t.Error("Sender receives prot.Response after sending data")
	case <-time.After(500 * time.Millisecond):
	}

	err = sender.Stop()
	t.Assert(err, IsNil)
}
示例#4
0
func (s *AggregatorTestSuite) SetUpSuite(t *C) {
	s.logChan = make(chan *proto.LogEntry, 10)
	s.logger = pct.NewLogger(s.logChan, "mm-manager-test")
	s.tickChan = make(chan time.Time)
	s.collectionChan = make(chan *mm.Collection)
	s.dataChan = make(chan interface{}, 1)
	s.spool = mock.NewSpooler(s.dataChan)
}
示例#5
0
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)
}
示例#6
0
func (s *SenderTestSuite) TestConnectErrors(t *C) {
	spool := mock.NewSpooler(nil)

	spool.FilesOut = []string{"slow001.json"}
	spool.DataOut = map[string][]byte{"slow001.json": []byte("...")}

	sender := data.NewSender(s.logger, s.client)

	err := sender.Start(spool, s.tickerChan, 60, false)
	t.Assert(err, IsNil)

	// Any connect error will do.
	s.client.ConnectError = io.EOF
	defer func() { s.client.ConnectError = nil }()

	// Tick causes send to connect and send all files.
	s.tickerChan <- time.Now()
	t0 := time.Now()

	// Wait for sender to start trying to connect...
	if !test.WaitStatus(5, sender, "data-sender", "Connecting") {
		t.Fatal("Timeout waiting for data-sender status=Connecting")
	}
	// ...then wait for it to finsih and return.
	if !test.WaitStatusPrefix(data.MAX_SEND_ERRORS*data.CONNECT_ERROR_WAIT, sender, "data-sender", "Idle") {
		t.Fatal("Timeout waiting for data-sender status=Idle")
	}
	d := time.Now().Sub(t0).Seconds()

	// It should wait between reconnects, but not too long.
	if d < float64((data.MAX_SEND_ERRORS-1)*data.CONNECT_ERROR_WAIT) {
		t.Error("Waits between reconnects")
	}
	if d > float64(data.MAX_SEND_ERRORS*data.CONNECT_ERROR_WAIT) {
		t.Error("Waited too long between reconnects")
	}

	err = sender.Stop()
	t.Assert(err, IsNil)

	// Couldn't connect, so it doesn't send or reject anything.
	t.Check(len(spool.DataOut), Equals, 1)
	t.Check(len(spool.RejectedFiles), Equals, 0)

	// It should have called ConnectOnce() serveral times, else it didn't
	// really try to reconnect.
	trace := test.DrainTraceChan(s.client.TraceChan)
	t.Check(trace, DeepEquals, []string{
		"ConnectOnce",
		"ConnectOnce",
		"ConnectOnce",
		"DisconnectOnce",
	})
}
示例#7
0
func (s *SenderTestSuite) Test500Error(t *C) {
	spool := mock.NewSpooler(nil)
	spool.FilesOut = []string{"file1", "file2", "file3"}
	spool.DataOut = map[string][]byte{
		"file1": []byte("file1"),
		"file2": []byte("file2"),
		"file3": []byte("file3"),
	}

	sender := data.NewSender(s.logger, s.client)
	err := sender.Start(spool, s.tickerChan, 5, false)
	t.Assert(err, IsNil)

	s.tickerChan <- time.Now()

	got := test.WaitBytes(s.dataChan)
	if same, diff := test.IsDeeply(got[0], []byte("file1")); !same {
		t.Error(diff)
	}

	// 3 files before API error.
	t.Check(len(spool.DataOut), Equals, 3)

	// Simulate API error.
	select {
	case s.respChan <- &proto.Response{Code: 503}:
	case <-time.After(500 * time.Millisecond):
		t.Error("Sender receives prot.Response after sending data")
	}

	// Wait for it to finsih and return.
	if !test.WaitStatusPrefix(data.MAX_SEND_ERRORS*data.CONNECT_ERROR_WAIT, sender, "data-sender", "Idle") {
		t.Fatal("Timeout waiting for data-sender status=Idle")
	}

	// Still 3 files after API error.
	t.Check(len(spool.DataOut), Equals, 3)
	t.Check(len(spool.RejectedFiles), Equals, 0)

	// There's only 1 call to SendBytes because after an API error
	// the send stops immediately.
	trace := test.DrainTraceChan(s.client.TraceChan)
	t.Check(trace, DeepEquals, []string{
		"ConnectOnce",
		"SendBytes",
		"Recv",
		"DisconnectOnce",
	})

	err = sender.Stop()
	t.Assert(err, IsNil)
}
示例#8
0
func (s *SenderTestSuite) TestSendData(t *C) {
	spool := mock.NewSpooler(nil)

	slow001, err := ioutil.ReadFile(sample + "slow001.json")
	if err != nil {
		t.Fatal(err)
	}

	spool.FilesOut = []string{"slow001.json"}
	spool.DataOut = map[string][]byte{"slow001.json": slow001}

	sender := data.NewSender(s.logger, s.client)

	err = sender.Start(spool, s.tickerChan, 5, false)
	if err != nil {
		t.Fatal(err)
	}

	data := test.WaitBytes(s.dataChan)
	if len(data) != 0 {
		t.Errorf("No data sent before tick; got %+v", data)
	}

	s.tickerChan <- time.Now()

	data = test.WaitBytes(s.dataChan)
	if same, diff := test.IsDeeply(data[0], slow001); !same {
		t.Error(diff)
	}

	t.Check(len(spool.DataOut), Equals, 1)

	select {
	case s.respChan <- &proto.Response{Code: 200}:
	case <-time.After(500 * time.Millisecond):
		t.Error("Sender receives prot.Response after sending data")
	}

	// Sender should include its websocket client status.  We're using a mock ws client
	// which reports itself as "data-client: ok".
	status := sender.Status()
	t.Check(status["data-client"], Equals, "ok")

	err = sender.Stop()
	t.Assert(err, IsNil)

	t.Check(len(spool.DataOut), Equals, 0)
	t.Check(len(spool.RejectedFiles), Equals, 0)
}
示例#9
0
func (s *SenderTestSuite) TestBadFiles(t *C) {
	spool := mock.NewSpooler(nil)
	spool.FilesOut = []string{"file1", "file2", "file3"}
	spool.DataOut = map[string][]byte{
		"file1": []byte("file1"),
		"file2": []byte("file2"),
		"file3": []byte("file3"),
	}

	sender := data.NewSender(s.logger, s.client)
	err := sender.Start(spool, s.tickerChan, 5, false)
	t.Assert(err, IsNil)

	doneChan := make(chan bool, 1)
	go func() {
		resp := []uint{400, 400, 200}
		for i := 0; i < 3; i++ {
			// Wait for sender to send data.
			select {
			case <-s.dataChan:
			case <-doneChan:
				return
			}

			// Simulate API returns 400.
			select {
			case s.respChan <- &proto.Response{Code: resp[i]}:
			case <-doneChan:
				return
			}
		}
	}()

	s.tickerChan <- time.Now()

	// Wait for sender to finish.
	if !test.WaitStatusPrefix(data.MAX_SEND_ERRORS*data.CONNECT_ERROR_WAIT, sender, "data-sender", "Idle") {
		t.Fatal("Timeout waiting for data-sender status=Idle")
	}

	doneChan <- true
	err = sender.Stop()
	t.Assert(err, IsNil)

	// Bad files are removed, so all files should have been sent.
	t.Check(len(spool.DataOut), Equals, 0)
	t.Check(len(spool.RejectedFiles), Equals, 0)
}
示例#10
0
func (s *ManagerTestSuite) SetUpSuite(t *C) {
	s.logChan = make(chan *proto.LogEntry, 10)
	s.logger = pct.NewLogger(s.logChan, "mm-manager-test")
	s.tickChan = make(chan time.Time)
	s.traceChan = make(chan string, 10)
	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"), s.configDir, s.api)
	data, err := json.Marshal(&proto.MySQLInstance{
		Hostname: "db1",
		DSN:      "user:host@tcp:(127.0.0.1:3306)",
	})
	t.Assert(err, IsNil)
	s.im.Add("mysql", 1, data, false)
	data, err = json.Marshal(&proto.ServerInstance{Hostname: "host1"})
	t.Assert(err, IsNil)
	s.im.Add("server", 1, data, false)

	s.mysqlMonitor = mock.NewMmMonitor()
	s.systemMonitor = mock.NewMmMonitor()
	s.factory = mock.NewMmMonitorFactory(map[string]mm.Monitor{
		"mysql-1":  s.mysqlMonitor,
		"server-1": s.systemMonitor,
	})

	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)
}
示例#11
0
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)
}
示例#12
0
func (s *SenderTestSuite) TestRecvErrors(t *C) {
	spool := mock.NewSpooler(nil)
	spool.FilesOut = []string{"slow001.json"}
	spool.DataOut = map[string][]byte{"slow001.json": []byte("...")}

	sender := data.NewSender(s.logger, s.client)

	err := sender.Start(spool, s.tickerChan, 60, false)
	t.Assert(err, IsNil)

	// Any recv error will do.
	doneChan := make(chan bool)
	go func() {
		for {
			select {
			case s.client.RecvError <- io.EOF:
			case <-doneChan:
				return
			}
		}
	}()
	defer func() { doneChan <- true }()

	// Tick causes send to connect and send all files.
	s.tickerChan <- time.Now()
	t0 := time.Now()

	// Wait for sender to finsih and return.
	if !test.WaitStatusPrefix(data.MAX_SEND_ERRORS*data.CONNECT_ERROR_WAIT, sender, "data-sender", "Idle") {
		t.Fatal("Timeout waiting for data-sender status=Idle")
	}
	d := time.Now().Sub(t0).Seconds()

	// It should wait between reconnects, but not too long.
	if d < float64((data.MAX_SEND_ERRORS-1)*data.CONNECT_ERROR_WAIT) {
		t.Error("Waits between reconnects")
	}
	if d > float64(data.MAX_SEND_ERRORS*data.CONNECT_ERROR_WAIT) {
		t.Error("Waited too long between reconnects")
	}
	err = sender.Stop()
	t.Assert(err, IsNil)

	// Didn't receive proper ack, so it doesn't remove any data.
	t.Check(len(spool.DataOut), Equals, 1)
	t.Check(len(spool.RejectedFiles), Equals, 0)

	// It should have called ConnectOnce() serveral times, else it didn't
	// really try to reconnect.
	trace := test.DrainTraceChan(s.client.TraceChan)
	t.Check(trace, DeepEquals, []string{
		"ConnectOnce",
		"SendBytes",
		"Recv",
		"DisconnectOnce",
		"ConnectOnce",
		"SendBytes",
		"Recv",
		"DisconnectOnce",
		"ConnectOnce",
		"SendBytes",
		"Recv",
		"DisconnectOnce",
		"DisconnectOnce",
	})
}