package main import ( "bytes" "context" "encoding/csv" "encoding/json" "fmt" "io" "net/http" "net/http/httptest" "net/url" "os" "path" "strconv" "strings" "testing" "time" ) func TestRun(t *testing.T) { ctx, can := context.WithTimeout(context.Background(), time.Second*10) defer can() port := func() int { s := httptest.NewServer(http.HandlerFunc(http.NotFound)) s.Close() u, err := url.Parse(s.URL) if err != nil { t.Fatal(err) } portS := strings.Split(u.Host, ":")[1] port, err := strconv.ParseInt(portS, 10, 32) if err != nil { t.Fatal(err) } return int(port) }() u := fmt.Sprintf("http://localhost:%d", port) cfg := Config{} cfg.DatacenterPattern = renderDatacenterPattern cfg.AssetPattern = renderAssetPattern cfg.EventNamePattern = renderEventNamePattern cfg.Port = port cfg.driver, _ = NewDriver(ctx, "") cfg.slackToMessagePipeline, _ = NewSlackToMessagePipeline(ctx, cfg) cfg.SlackToken = "redacted" cfg.SlackChannels = []string{"C06U1DDBBU4"} go func() { if err := run(ctx, cfg); err != nil && ctx.Err() == nil { t.Fatal(err) } }() for { if resp, err := http.Get(u); err == nil { resp.Body.Close() break } select { case <-ctx.Done(): t.Fatal(ctx.Err()) case <-time.After(time.Millisecond * 50): } } t.Run("POST /api/v1/events/slack", func(t *testing.T) { b, err := os.ReadFile(path.Join("testdata", "slack_events", "opsgenie_alert_3.json")) if err != nil { t.Fatal(err) } resp, err := http.Post(fmt.Sprintf("%s/api/v1/events/slack", u), "application/json", bytes.NewReader(b)) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) t.Fatalf("(%d) %s", resp.StatusCode, b) } }) t.Run("GET /api/v1/messages", func(t *testing.T) { resp, err := http.Get(fmt.Sprintf("%s/api/v1/messages", u)) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) t.Fatalf("(%d) %s", resp.StatusCode, b) } var result struct { Messages []Message } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { t.Fatal(err) } else if len(result.Messages) != 1 { t.Fatal(result.Messages) } else { t.Logf("%+v", result) } }) t.Run("GET /api/v1/eventnames", func(t *testing.T) { resp, err := http.Get(fmt.Sprintf("%s/api/v1/eventnames", u)) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) t.Fatalf("(%d) %s", resp.StatusCode, b) } var result struct { EventNames []string } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { t.Fatal(err) } else if result.EventNames[0] != "Wal Receive Count Alert" { t.Fatal(result.EventNames) } else { t.Logf("%+v", result) } }) t.Run("GET /api/v1/events", func(t *testing.T) { resp, err := http.Get(fmt.Sprintf("%s/api/v1/events", u)) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) t.Fatalf("(%d) %s", resp.StatusCode, b) } var result struct { Events []string } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { t.Fatal(err) } else if result.Events[0] != "11067" { t.Fatal(result.Events) } else { t.Logf("%+v", result) } }) t.Run("GET /api/v1/threads", func(t *testing.T) { resp, err := http.Get(fmt.Sprintf("%s/api/v1/threads", u)) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) t.Fatalf("(%d) %s", resp.StatusCode, b) } var result struct { Threads []string } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { t.Fatal(err) } else if result.Threads[0] != "1712911957.023359" { t.Fatal(result.Threads) } else { t.Logf("%+v", result) } }) t.Run("GET /api/v1/threads/1712911957.023359", func(t *testing.T) { resp, err := http.Get(fmt.Sprintf("%s/api/v1/threads/1712911957.023359", u)) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) t.Fatalf("(%d) %s", resp.StatusCode, b) } var result struct { Thread []Message } if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { t.Fatal(err) } else if len(result.Thread) != 1 { t.Fatal(result.Thread) } else { t.Logf("%+v", result) } }) t.Run("CSV GET /api/v1/threads/1712911957.023359", func(t *testing.T) { req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/v1/threads/1712911957.023359", u), nil) if err != nil { t.Fatal(err) } req.Header.Set("Accept", "text/csv") resp, err := http.DefaultClient.Do(req) if err != nil { t.Fatal(err) } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { b, _ := io.ReadAll(resp.Body) t.Fatalf("(%d) %s", resp.StatusCode, b) } b, _ := io.ReadAll(resp.Body) t.Logf("whole csv: \n%s", b) dec := csv.NewReader(bytes.NewReader(b)) var lastLine []string for { line, err := dec.Read() if err == io.EOF { break } else if err != nil { t.Error("unexpected error while reading csv line:", err) } if lastLine == nil { } else if len(lastLine) != len(line) { t.Errorf("last line had %v elements but this line has %v", len(lastLine), len(line)) } t.Logf("CSV line: %+v", line) lastLine = line } if lastLine == nil { t.Error("no lines found") } }) }