func TestRun(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	mockOR := pipelinemock.NewMockOutputRunner(mockCtrl)
	mockPH := pipelinemock.NewMockPluginHelper(mockCtrl)
	mockFirehose := NewMockRecordPutter(mockCtrl)

	firehoseOutput := FirehoseOutput{
		client: mockFirehose,
	}

	testChan := make(chan *pipeline.PipelinePack)
	mockOR.EXPECT().InChan().Return(testChan)

	// Send test input through the channel
	input := `{"key":"value"}`
	go func() {
		testPack := pipeline.PipelinePack{
			Message: &message.Message{
				Payload: &input,
			},
		}

		testChan <- &testPack
		close(testChan)
	}()

	mockFirehose.EXPECT().PutRecord([]byte(input)).Return(nil)

	err := firehoseOutput.Run(mockOR, mockPH)
	assert.NoError(t, err, "did not expect err for valid Run()")
}
// TestRunWithTimestamp tests that if a TimestampColumn is provided in the config
// then the Heka message's timestamp gets added to the message with that column name.
func TestRunWithTimestamp(t *testing.T) {
	mockCtrl := gomock.NewController(t)
	defer mockCtrl.Finish()

	mockOR := pipelinemock.NewMockOutputRunner(mockCtrl)
	mockPH := pipelinemock.NewMockPluginHelper(mockCtrl)
	mockFirehose := NewMockRecordPutter(mockCtrl)

	firehoseOutput := FirehoseOutput{
		client:          mockFirehose,
		timestampColumn: "created",
	}

	testChan := make(chan *pipeline.PipelinePack)
	mockOR.EXPECT().InChan().Return(testChan)

	// Send test input through the channel
	input := `{}`
	timestamp := time.Date(2015, 07, 1, 13, 14, 15, 0, time.UTC).UnixNano()
	go func() {
		testPack := pipeline.PipelinePack{
			Message: &message.Message{
				Payload:   &input,
				Timestamp: &timestamp,
			},
		}

		testChan <- &testPack
		close(testChan)
	}()

	expected := `{"created":"2015-07-01 13:14:15.000"}`
	mockFirehose.EXPECT().PutRecord([]byte(expected)).Return(nil)

	err := firehoseOutput.Run(mockOR, mockPH)
	assert.NoError(t, err, "did not expect err for valid Run()")
}
Exemplo n.º 3
0
func DashboardOutputSpec(c gs.Context) {
	t := new(pipeline_ts.SimpleT)
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()
	pConfig := pipeline.NewPipelineConfig(nil)

	dashboardOutput := new(DashboardOutput)
	dashboardOutput.pConfig = pConfig

	oth := plugins_ts.NewOutputTestHelper(ctrl)
	oth.MockHelper = pipelinemock.NewMockPluginHelper(ctrl)
	oth.MockOutputRunner = pipelinemock.NewMockOutputRunner(ctrl)

	errChan := make(chan error, 1)

	startOutput := func() {
		go func() {
			errChan <- dashboardOutput.Run(oth.MockOutputRunner, oth.MockHelper)
		}()
	}

	if runtime.GOOS != "windows" {
		c.Specify("A DashboardOutput", func() {

			tmpdir, err := ioutil.TempDir("", "dashboard_output_test")
			c.Assume(err, gs.IsNil)
			config := dashboardOutput.ConfigStruct().(*DashboardOutputConfig)
			config.WorkingDirectory = tmpdir

			c.Specify("Init halts if basedirectory is not writable", func() {
				err := os.MkdirAll(tmpdir, 0400)
				c.Assume(err, gs.IsNil)
				defer os.RemoveAll(tmpdir)
				err = dashboardOutput.Init(config)
				c.Assume(err, gs.Not(gs.IsNil))
			})

			c.Specify("that is running", func() {
				startedChan := make(chan bool, 1)
				defer close(startedChan)
				ts := httptest.NewUnstartedServer(nil)

				dashboardOutput.starterFunc = func(hli *DashboardOutput) error {
					ts.Start()
					startedChan <- true
					return nil
				}

				ticker := make(chan time.Time)
				inChan := make(chan *pipeline.PipelinePack, 1)
				recycleChan := make(chan *pipeline.PipelinePack, 1)
				pack := pipeline.NewPipelinePack(recycleChan)
				pack.Message = pipeline_ts.GetTestMessage()

				oth.MockOutputRunner.EXPECT().InChan().Return(inChan)
				oth.MockOutputRunner.EXPECT().Ticker().Return(ticker)

				err := os.MkdirAll(tmpdir, 0700)
				c.Assume(err, gs.IsNil)
				defer os.RemoveAll(tmpdir)

				dashboardOutput.handler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
					// Noop
				})

				c.Specify("sets custom http headers", func() {
					config.Headers = http.Header{
						"One":  []string{"two", "three"},
						"Four": []string{"five", "six", "seven"},
					}
					err = dashboardOutput.Init(config)
					c.Assume(err, gs.IsNil)
					ts.Config = dashboardOutput.server

					startOutput()

					inChan <- pack
					<-startedChan
					resp, err := http.Get(ts.URL)
					c.Assume(err, gs.IsNil)
					resp.Body.Close()
					c.Assume(resp.StatusCode, gs.Equals, 200)

					// Verify headers are there
					eq := reflect.DeepEqual(resp.Header["One"], config.Headers["One"])
					c.Expect(eq, gs.IsTrue)
					eq = reflect.DeepEqual(resp.Header["Four"], config.Headers["Four"])
					c.Expect(eq, gs.IsTrue)
				})

				close(inChan)
				c.Expect(<-errChan, gs.IsNil)

				ts.Close()
			})
		})
	}
}
Exemplo n.º 4
0
func WhisperOutputSpec(c gospec.Context) {
	t := &pipeline_ts.SimpleT{}
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	oth := new(plugins_ts.OutputTestHelper)
	oth.MockHelper = pipelinemock.NewMockPluginHelper(ctrl)
	oth.MockOutputRunner = pipelinemock.NewMockOutputRunner(ctrl)
	inChan := make(chan *PipelinePack, 1)
	pConfig := NewPipelineConfig(nil)

	c.Specify("A WhisperOutput", func() {
		o := &WhisperOutput{pConfig: pConfig}
		config := o.ConfigStruct().(*WhisperOutputConfig)
		config.BasePath = filepath.Join(os.TempDir(), config.BasePath)
		o.Init(config)

		const count = 5
		lines := make([]string, count)
		baseTime := time.Now().UTC().Add(-10 * time.Second)
		nameTmpl := "stats.name.%d"

		wChan := make(chan *whisper.Point, count)
		mockWr := NewMockWhisperRunner(ctrl)

		for i := 0; i < count; i++ {
			statName := fmt.Sprintf(nameTmpl, i)
			statTime := baseTime.Add(time.Duration(i) * time.Second)
			lines[i] = fmt.Sprintf("%s %d %d", statName, i*2, statTime.Unix())
			o.dbs[statName] = mockWr
		}

		pack := NewPipelinePack(pConfig.InputRecycleChan())
		pack.Message.SetPayload(strings.Join(lines, "\n"))

		c.Specify("turns statmetric lines into points", func() {
			oth.MockOutputRunner.EXPECT().InChan().Return(inChan)
			oth.MockOutputRunner.EXPECT().UpdateCursor("")
			wChanCall := mockWr.EXPECT().InChan().Times(count)
			wChanCall.Return(wChan)

			go o.Run(oth.MockOutputRunner, oth.MockHelper)
			inChan <- pack

			// Usually each wChan will be unique instead of shared across
			// multiple whisper runners. This weird dance here prevents our
			// mock wChan from being closed multiple times.
			bogusChan := make(chan *whisper.Point)
			wChanCall = mockWr.EXPECT().InChan().Times(count)
			wChanCall.Return(bogusChan)
			wChanCall.Do(func() {
				wChanCall.Return(make(chan *whisper.Point))
			})

			close(inChan)
			<-bogusChan // wait for inChan to flush
			close(wChan)

			i := 0
			for pt := range wChan {
				statTime := baseTime.Add(time.Duration(i) * time.Second)
				c.Expect(pt.Value, gs.Equals, float64(i*2))
				c.Expect(pt.Time().UTC().Unix(), gs.Equals, statTime.Unix())
				i++
			}
		})
	})
}
Exemplo n.º 5
0
func NewOutputTestHelper(ctrl *gomock.Controller) (oth *OutputTestHelper) {
	oth = new(OutputTestHelper)
	oth.MockHelper = pipelinemock.NewMockPluginHelper(ctrl)
	oth.MockOutputRunner = pipelinemock.NewMockOutputRunner(ctrl)
	return
}
Exemplo n.º 6
0
func NagiosOutputSpec(c gs.Context) {
	t := new(pipeline_ts.SimpleT)
	ctrl := gomock.NewController(t)
	defer ctrl.Finish()

	c.Specify("A NagiosOutput", func() {
		output := new(NagiosOutput)
		config := output.ConfigStruct().(*NagiosOutputConfig)
		config.Url = "http://localhost:55580/foo/bar"

		mockOutputRunner := pipelinemock.NewMockOutputRunner(ctrl)
		mockHelper := pipelinemock.NewMockPluginHelper(ctrl)

		inChan := make(chan *pipeline.PipelinePack)
		recycleChan := make(chan *pipeline.PipelinePack, 1)

		pack := pipeline.NewPipelinePack(recycleChan)
		msg := pipeline_ts.GetTestMessage()
		pack.Message = msg

		var req *http.Request
		var outputWg, reqWg sync.WaitGroup

		run := func() {
			mockOutputRunner.EXPECT().InChan().Return(inChan)
			mockOutputRunner.EXPECT().UpdateCursor("").AnyTimes()
			output.Run(mockOutputRunner, mockHelper)
			outputWg.Done()
		}

		const payload = "something"

		c.Specify("using HTTP transport", func() {
			// Spin up an HTTP listener.
			listener, err := net.Listen("tcp", "127.0.0.1:55580")
			c.Assume(err, gs.IsNil)

			mux := http.NewServeMux()
			mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
				w.Header().Set("Connection", "close")
				r.ParseForm()
				req = r
				listener.Close()
				reqWg.Done()
			})

			go http.Serve(listener, mux)

			c.Specify("sends a valid HTTP POST", func() {
				err = output.Init(config)
				c.Assume(err, gs.IsNil)
				outputWg.Add(1)
				go run()

				msg.SetPayload("OK:" + payload)
				reqWg.Add(1)
				inChan <- pack
				close(inChan)
				outputWg.Wait()
				reqWg.Wait()

				c.Expect(req.FormValue("plugin_output"), gs.Equals, payload)
				c.Expect(req.FormValue("plugin_state"), gs.Equals, "0")
			})

			c.Specify("correctly maps alternate state", func() {
				err = output.Init(config)
				c.Assume(err, gs.IsNil)
				outputWg.Add(1)
				go run()

				msg.SetPayload("CRITICAL:" + payload)
				reqWg.Add(1)
				inChan <- pack
				close(inChan)
				outputWg.Wait()
				reqWg.Wait()

				c.Expect(req.FormValue("plugin_output"), gs.Equals, payload)
				c.Expect(req.FormValue("plugin_state"), gs.Equals, "2")
			})
		})

		if runtime.GOOS != "windows" {
			outPath := filepath.Join(os.TempDir(), "heka-nagios-test-output.txt")
			echoFile := fmt.Sprintf(echoFileTmpl, outPath)

			c.Specify("using a send_ncsa binary", func() {
				binPath := pipeline_ts.WriteStringToTmpFile(echoFile)
				os.Chmod(binPath, 0700)
				defer func() {
					os.Remove(binPath)
					os.Remove(outPath)
				}()
				config.SendNscaBin = binPath
				config.SendNscaArgs = []string{"arg1", "arg2"}
				err := output.Init(config)
				c.Assume(err, gs.IsNil)
				outputWg.Add(1)
				go run()

				c.Specify("sends args and the right data through", func() {
					msg.SetPayload("OK:" + payload)
					inChan <- pack
					close(inChan)
					outputWg.Wait()

					outFile, err := os.Open(outPath)
					c.Expect(err, gs.IsNil)
					reader := bufio.NewReader(outFile)
					line, _, err := reader.ReadLine()
					c.Expect(err, gs.IsNil)
					c.Expect(string(line), gs.Equals, strings.Join(config.SendNscaArgs, " "))
					line, _, err = reader.ReadLine()
					c.Expect(err, gs.IsNil)
					c.Expect(string(line), gs.Equals, "my.host.name GoSpec 0 "+payload)
				})

				c.Specify("correctly maps alternate state", func() {
					msg.SetPayload("WARNING:" + payload)
					inChan <- pack
					close(inChan)
					outputWg.Wait()

					outFile, err := os.Open(outPath)
					c.Expect(err, gs.IsNil)
					reader := bufio.NewReader(outFile)
					line, _, err := reader.ReadLine()
					c.Expect(err, gs.IsNil)
					c.Expect(string(line), gs.Equals, strings.Join(config.SendNscaArgs, " "))
					line, _, err = reader.ReadLine()
					c.Expect(err, gs.IsNil)
					c.Expect(string(line), gs.Equals, "my.host.name GoSpec 1 "+payload)
				})
			})
		}
	})
}