func TestParserRoundTrip(t *testing.T) { for _, tc := range mtailPrograms { p := newParser(tc.name, strings.NewReader(tc.program), metrics.NewStore()) r := mtailParse(p) if r != 0 || p.root == nil || len(p.errors) > 0 { t.Errorf("1st pass parse errors:\n") for _, e := range p.errors { t.Errorf("\t%s\n", e) } continue } u := Unparser{} output := u.Unparse(p.root) p2 := newParser(tc.name+" 2", strings.NewReader(output), metrics.NewStore()) r = mtailParse(p2) if r != 0 || p2.root == nil || len(p2.errors) > 0 { t.Errorf("2nd pass parse errors:\n") for _, e := range p2.errors { t.Errorf("\t%s\n", e) } continue } u = Unparser{} output2 := u.Unparse(p2.root) diff := pretty.Compare(output2, output) if len(diff) > 0 { t.Errorf("Round trip failed to generate same output.\n%s", diff) } } }
func TestHandlePrometheus(t *testing.T) { for _, tc := range handlePrometheusTests { ms := metrics.NewStore() for _, metric := range tc.metrics { ms.Add(metric) } o := Options{ms, "gunstar"} e, err := New(o) if err != nil { t.Fatalf("couldn't make exporter: %s", err) } response := httptest.NewRecorder() e.HandlePrometheusMetrics(response, &http.Request{}) if response.Code != 200 { t.Errorf("test case %s: response code not 200: %d", tc.name, response.Code) } b, err := ioutil.ReadAll(response.Body) if err != nil { t.Errorf("test case %s: failed to read response: %s", tc.name, err) } diff := pretty.Compare(string(b), tc.expected) if len(diff) > 0 { t.Errorf("test case %s: response not expected:\n%s", tc.name, diff) } } }
func TestCompileAndRun(t *testing.T) { var testProgram = "/$/ {}\n" store := metrics.NewStore() lines := make(chan string) w := watcher.NewFakeWatcher() fs := afero.NewMemMapFs() o := LoaderOptions{store, lines, w, fs, false, false, true} l, err := NewLoader(o) if err != nil { t.Fatalf("couldn't create loader: %s", err) } if err := l.CompileAndRun("Test", strings.NewReader(testProgram)); err != nil { t.Errorf("CompileAndRun returned error: %s", err) } l.handleMu.Lock() if len(l.handles) < 1 { t.Errorf("no vm handles: %v", l.handles) } l.handleMu.Unlock() l.handleMu.Lock() c := l.handles["Test"].done if c == nil { t.Errorf("No done channel in handles: %v", l.handles) } l.handleMu.Unlock() close(lines) <-c { l.handleMu.Lock() defer l.handleMu.Unlock() if len(l.handles) != 0 { t.Errorf("some vm handles: %v", l.handles) } } }
func TestReadTestData(t *testing.T) { f, err := os.Open("reader_test.golden") if err != nil { t.Fatal(err) } defer f.Close() store := metrics.NewStore() ReadTestData(f, "reader_test", store) diff := pretty.Compare(expectedMetrics, store.Metrics) if len(diff) > 0 { t.Errorf("metrics don't match: %s\n", diff) } }
func TestInvalidPrograms(t *testing.T) { for _, tc := range InvalidPrograms { p := newParser(tc.name, strings.NewReader(tc.program), metrics.NewStore()) mtailParse(p) diff := pretty.Compare( strings.Join(tc.errors, "\n"), // want strings.TrimRight(p.errors.Error(), "\n")) // got if len(diff) > 0 { t.Errorf("Incorrect error for '%s'\n%s", tc.name, diff) } } }
func TestExamplePrograms(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") } for _, tc := range exampleProgramTests { w := watcher.NewFakeWatcher() store := metrics.NewStore() o := mtail.Options{Progs: tc.programfile, W: w, Store: store} mtail, err := mtail.New(o) if err != nil { t.Fatalf("create mtail failed: %s", err) } if _, err := mtail.OneShot(tc.logfile, false); err != nil { t.Errorf("Oneshot failed for %s: %s", tc.logfile, err) continue } j, err := os.Open(tc.jsonfile) if err != nil { t.Fatalf("%s: could not open json file: %s", tc.jsonfile, err) } defer j.Close() golden_store := metrics.NewStore() testdata.ReadTestData(j, tc.programfile, golden_store) mtail.Close() diff := pretty.Compare(golden_store, store) if len(diff) > 0 { t.Errorf("%s: metrics don't match:\n%s", tc.programfile, diff) t.Errorf("Store metrics: %#v", store.Metrics) } } }
func TestCompile(t *testing.T) { for _, tc := range programs { m := metrics.NewStore() v, err := Compile(tc.name, strings.NewReader(tc.source), m, false, true) if err != nil { t.Errorf("Compile errors: %q", err) continue } diff := pretty.Compare(tc.prog, v.prog) if len(diff) > 0 { t.Errorf("%s: VM prog doesn't match.\n%s", tc.name, diff) } } }
func TestMetricToCollectd(t *testing.T) { ts, terr := time.Parse("2006/01/02 15:04:05", "2012/07/24 10:14:00") if terr != nil { t.Errorf("time parse error: %s", terr) } ms := metrics.NewStore() scalarMetric := metrics.NewMetric("foo", "prog", metrics.Counter) d, _ := scalarMetric.GetDatum() d.Set(37, ts) ms.Add(scalarMetric) r := FakeSocketWrite(metricToCollectd, scalarMetric) expected := []string{"PUTVAL \"gunstar/mtail-prog/counter-foo\" interval=60 1343124840:37\n"} diff := pretty.Compare(r, expected) if len(diff) > 0 { t.Errorf("String didn't match:\n%s", diff) } dimensionedMetric := metrics.NewMetric("bar", "prog", metrics.Gauge, "label") d, _ = dimensionedMetric.GetDatum("quux") d.Set(37, ts) d, _ = dimensionedMetric.GetDatum("snuh") d.Set(37, ts) ms.ClearMetrics() ms.Add(dimensionedMetric) r = FakeSocketWrite(metricToCollectd, dimensionedMetric) expected = []string{ "PUTVAL \"gunstar/mtail-prog/gauge-bar-label-quux\" interval=60 1343124840:37\n", "PUTVAL \"gunstar/mtail-prog/gauge-bar-label-snuh\" interval=60 1343124840:37\n"} diff = pretty.Compare(r, expected) if len(diff) > 0 { t.Errorf("String didn't match:\n%s", diff) } timingMetric := metrics.NewMetric("foo", "prog", metrics.Timer) d, _ = timingMetric.GetDatum() d.Set(123, ts) ms.Add(timingMetric) r = FakeSocketWrite(metricToCollectd, timingMetric) expected = []string{"PUTVAL \"gunstar/mtail-prog/gauge-foo\" interval=60 1343124840:123\n"} diff = pretty.Compare(r, expected) if len(diff) > 0 { t.Errorf("String didn't match:\n%s", diff) } }
// New creates an Mtail from the supplied Options. func New(o Options) (*Mtail, error) { store := o.Store if store == nil { store = metrics.NewStore() } m := &Mtail{ lines: make(chan string), store: store, webquit: make(chan struct{}), o: o} err := m.InitLoader() if err != nil { return nil, err } m.e, err = exporter.New(exporter.Options{Store: m.store}) if err != nil { return nil, err } return m, nil }
func TestNewLoader(t *testing.T) { w := watcher.NewFakeWatcher() store := metrics.NewStore() inLines := make(chan string) fs := afero.NewMemMapFs() o := LoaderOptions{store, inLines, w, fs, false, false, true} l, err := NewLoader(o) if err != nil { t.Fatalf("couldn't create loader: %s", err) } done := make(chan struct{}) outLines := make(chan string) handle := &vmHandle{outLines, done} l.handleMu.Lock() l.handles["test"] = handle l.handleMu.Unlock() go func() { for _ = range outLines { } close(done) }() close(inLines) <-outLines }
func TestProcessEvents(t *testing.T) { for _, tt := range testProcessEvents { w := watcher.NewFakeWatcher() w.Add(".") store := metrics.NewStore() lines := make(chan string) fs := afero.NewMemMapFs() o := LoaderOptions{store, lines, w, fs, false, false, true} l, err := NewLoader(o) if err != nil { t.Fatalf("couldn't create loader: %s", err) } for i := range tt.events { e := tt.events[i] switch e := e.(type) { case watcher.CreateEvent: if e.Pathname != "notexist.mtail" { _, err := fs.Create(e.Pathname) if err != nil { t.Fatalf("Create failed for %s: %s", e.Pathname, err) } } w.InjectCreate(e.Pathname) case watcher.DeleteEvent: err := fs.Remove(e.Pathname) if err != nil { t.Fatalf("Remove failed for %s: %s", e.Pathname, err) } w.InjectDelete(e.Pathname) case watcher.UpdateEvent: if e.Pathname != "notexist.mtail" { f, err := fs.Create(e.Pathname) if err != nil { t.Fatalf("Couldn't open file %s for test: %s", e.Pathname, err) } _, err = f.WriteString(testProgram) if err != nil { t.Fatalf("Couldn't write file contents: %s", err) } if err = f.Close(); err != nil { t.Fatalf("Close failed: %s", err) } } w.InjectUpdate(e.Pathname) } } w.Close() <-l.watcherDone l.handleMu.RLock() var programs []string for program := range l.handles { programs = append(programs, program) } l.handleMu.RUnlock() l.handleMu.RLock() if diff := pretty.Compare(tt.expectedPrograms, programs); len(diff) > 0 { t.Errorf("%q: loaded programs don't match.\nl.handles: %+#v\n%s", tt.name, l.handles, diff) } l.handleMu.RUnlock() close(lines) } }