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