Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/cli. OpenStatus CLI www.openstatus.dev
Something went wrong. Try again.
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580package terraform
import ( "strings" "testing"
monitorv1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/monitor/v1" notificationv1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/notification/v1" status_pagev1 "buf.build/gen/go/openstatus/api/protocolbuffers/go/openstatus/status_page/v1")
func TestGenerateProviderFile(t *testing.T) { content := string(GenerateProviderFile()) mustContain(t, content, `source = "openstatusHQ/openstatus"`) mustContain(t, content, `version = "~> 0.2"`) mustContain(t, content, `provider "openstatus" {}`) mustContain(t, content, `OPENSTATUS_API_TOKEN`)}
func TestGenerateMonitorsFile_HTTP(t *testing.T) { m := &monitorv1.HTTPMonitor{} m.SetId("123") m.SetName("API Health") m.SetUrl("https://api.example.com/health") m.SetPeriodicity(monitorv1.Periodicity_PERIODICITY_5M) m.SetMethod(monitorv1.HTTPMethod_HTTP_METHOD_POST) m.SetTimeout(45000) m.SetRetry(3) m.SetFollowRedirects(true) m.SetActive(true) m.SetRegions([]monitorv1.Region{monitorv1.Region_REGION_FLY_IAD})
data := &WorkspaceData{HTTPMonitors: []*monitorv1.HTTPMonitor{m}} gen := NewGenerator(data) content := string(gen.GenerateMonitorsFile().Bytes())
mustContain(t, content, `resource "openstatus_http_monitor" "api_health"`) mustContain(t, content, `name = "API Health"`) mustContain(t, content, `periodicity = "5m"`) mustContain(t, content, `method = "POST"`) mustContain(t, content, `active = true`) mustContain(t, content, `"fly-iad"`) // timeout, retry, follow_redirects should be omitted at defaults mustNotContain(t, content, "timeout") mustNotContain(t, content, "retry") mustNotContain(t, content, "follow_redirects")}
func TestGenerateMonitorsFile_DNS(t *testing.T) { m := &monitorv1.DNSMonitor{} m.SetId("456") m.SetName("DNS Check") m.SetUri("example.com") m.SetPeriodicity(monitorv1.Periodicity_PERIODICITY_10M) m.SetActive(true)
a := &monitorv1.RecordAssertion{} a.SetRecord("A") a.SetTarget("93.184.216.34") a.SetComparator(monitorv1.RecordComparator_RECORD_COMPARATOR_EQUAL) m.SetRecordAssertions([]*monitorv1.RecordAssertion{a})
data := &WorkspaceData{DNSMonitors: []*monitorv1.DNSMonitor{m}} gen := NewGenerator(data) content := string(gen.GenerateMonitorsFile().Bytes())
mustContain(t, content, `resource "openstatus_dns_monitor" "dns_check"`) mustContain(t, content, `record_assertions`) mustContain(t, content, `record = "A"`) mustContain(t, content, `target = "93.184.216.34"`)}
func TestGenerateNotificationsFile_Slack(t *testing.T) { n := ¬ificationv1.Notification{} n.SetId("789") n.SetName("Slack Alerts") n.SetProvider(notificationv1.NotificationProvider_NOTIFICATION_PROVIDER_SLACK) n.SetMonitorIds([]string{"123"})
nd := ¬ificationv1.NotificationData{} sd := ¬ificationv1.SlackData{} sd.SetWebhookUrl("https://hooks.slack.com/xxx") nd.SetSlack(sd) n.SetData(nd)
data := &WorkspaceData{Notifications: []*notificationv1.Notification{n}} gen := NewGenerator(data) content := string(gen.GenerateNotificationsFile().Bytes())
mustContain(t, content, `resource "openstatus_notification" "slack_alerts"`) mustContain(t, content, `provider_type = "slack"`) mustContain(t, content, `"123"`) mustContain(t, content, `webhook_url`)}
func TestGenerateStatusPagesFile(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("My Status Page") page.SetSlug("my-status")
comp := &status_pagev1.PageComponent{} comp.SetId("c1") comp.SetPageId("p1") comp.SetName("API") comp.SetType(status_pagev1.PageComponentType_PAGE_COMPONENT_TYPE_STATIC) comp.SetOrder(1)
data := &WorkspaceData{ StatusPages: []StatusPageData{ {Page: page, Components: []*status_pagev1.PageComponent{comp}}, }, } gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `resource "openstatus_status_page" "my_status_page"`) mustContain(t, content, `title = "My Status Page"`) mustContain(t, content, `slug = "my-status"`) mustContain(t, content, `resource "openstatus_status_page_component" "api"`) mustContain(t, content, `openstatus_status_page.my_status_page.id`)}
func TestGenerateImportsFile(t *testing.T) { m := &monitorv1.HTTPMonitor{} m.SetId("123") m.SetName("API")
page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Page")
comp := &status_pagev1.PageComponent{} comp.SetId("c1") comp.SetPageId("p1") comp.SetName("Comp") comp.SetType(status_pagev1.PageComponentType_PAGE_COMPONENT_TYPE_STATIC)
data := &WorkspaceData{ HTTPMonitors: []*monitorv1.HTTPMonitor{m}, StatusPages: []StatusPageData{{Page: page, Components: []*status_pagev1.PageComponent{comp}}}, } gen := NewGenerator(data) content := string(gen.GenerateImportsFile().Bytes())
mustContain(t, content, `openstatus_http_monitor.api`) mustContain(t, content, `id = "123"`) mustContain(t, content, `id = "p1/c1"`)}
func TestEmptyWorkspace(t *testing.T) { data := &WorkspaceData{} gen := NewGenerator(data)
if gen.TotalResourceCount() != 0 { t.Errorf("TotalResourceCount() = %d, want 0", gen.TotalResourceCount()) } if gen.HasMonitors() { t.Error("HasMonitors() should be false") } if gen.HasNotifications() { t.Error("HasNotifications() should be false") } if gen.HasStatusPages() { t.Error("HasStatusPages() should be false") }}
func TestCrossReferenceMonitorInComponent(t *testing.T) { m := &monitorv1.HTTPMonitor{} m.SetId("mon-1") m.SetName("API Monitor")
page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Page")
comp := &status_pagev1.PageComponent{} comp.SetId("c1") comp.SetPageId("p1") comp.SetName("API Comp") comp.SetType(status_pagev1.PageComponentType_PAGE_COMPONENT_TYPE_MONITOR) comp.SetMonitorId("mon-1")
data := &WorkspaceData{ HTTPMonitors: []*monitorv1.HTTPMonitor{m}, StatusPages: []StatusPageData{{Page: page, Components: []*status_pagev1.PageComponent{comp}}}, } gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `openstatus_http_monitor.api_monitor.id`)}
func TestCrossReferenceFallbackToString(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Page")
comp := &status_pagev1.PageComponent{} comp.SetId("c1") comp.SetPageId("p1") comp.SetName("Unknown Monitor Comp") comp.SetType(status_pagev1.PageComponentType_PAGE_COMPONENT_TYPE_MONITOR) comp.SetMonitorId("nonexistent-id")
data := &WorkspaceData{ StatusPages: []StatusPageData{{Page: page, Components: []*status_pagev1.PageComponent{comp}}}, } gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `monitor_id = "nonexistent-id"`)}
func TestGenerateNotificationsFile_MsTeams(t *testing.T) { n := ¬ificationv1.Notification{} n.SetId("1") n.SetName("Teams Alerts")
nd := ¬ificationv1.NotificationData{} td := ¬ificationv1.MsTeamsData{} td.SetWebhookUrl("https://prod.example.com/webhook") nd.SetMsTeams(td) n.SetData(nd)
data := &WorkspaceData{Notifications: []*notificationv1.Notification{n}} gen := NewGenerator(data) content := string(gen.GenerateNotificationsFile().Bytes())
mustContain(t, content, `resource "openstatus_notification" "teams_alerts"`) mustContain(t, content, `provider_type = "ms_teams"`) mustContain(t, content, "ms_teams {") mustContain(t, content, `webhook_url = "https://prod.example.com/webhook"`)}
func TestGenerateNotificationsFile_WebhookHeaders(t *testing.T) { n := ¬ificationv1.Notification{} n.SetId("1") n.SetName("Webhook")
nd := ¬ificationv1.NotificationData{} wd := ¬ificationv1.WebhookData{} wd.SetEndpoint("https://example.com/hook") h1 := ¬ificationv1.WebhookHeader{} h1.SetKey("Authorization") h1.SetValue("Bearer xyz") h2 := ¬ificationv1.WebhookHeader{} h2.SetKey("X-Source") h2.SetValue("openstatus") wd.SetHeaders([]*notificationv1.WebhookHeader{h1, h2}) nd.SetWebhook(wd) n.SetData(nd)
data := &WorkspaceData{Notifications: []*notificationv1.Notification{n}} gen := NewGenerator(data) content := string(gen.GenerateNotificationsFile().Bytes())
mustContain(t, content, `headers = [`) mustContain(t, content, `key = "Authorization"`) mustContain(t, content, `value = "Bearer xyz"`) mustContain(t, content, `key = "X-Source"`) mustNotContain(t, content, "headers {")}
func TestGenerateNotificationsFile_MonitorIdsTraversal(t *testing.T) { m := &monitorv1.HTTPMonitor{} m.SetId("mon-known") m.SetName("API")
n := ¬ificationv1.Notification{} n.SetId("n1") n.SetName("Slack") n.SetMonitorIds([]string{"mon-unknown", "mon-known"})
nd := ¬ificationv1.NotificationData{} sd := ¬ificationv1.SlackData{} sd.SetWebhookUrl("https://hooks.example.com/xxx") nd.SetSlack(sd) n.SetData(nd)
data := &WorkspaceData{ HTTPMonitors: []*monitorv1.HTTPMonitor{m}, Notifications: []*notificationv1.Notification{n}, } gen := NewGenerator(data) content := string(gen.GenerateNotificationsFile().Bytes())
mustContain(t, content, "openstatus_http_monitor.api.id") mustContain(t, content, `"mon-unknown"`) idx := strings.Index(content, "monitor_ids") if idx == -1 { t.Fatalf("monitor_ids not found in output:\n%s", content) } line := content[idx : strings.Index(content[idx:], "\n")+idx] if strings.Index(line, "openstatus_http_monitor.api.id") > strings.Index(line, `"mon-unknown"`) { t.Errorf("expected sorted order (mon-known first, mon-unknown second), got: %s", line) }}
func TestGenerateNotificationsFile_UnknownProviderSkipped(t *testing.T) { n := ¬ificationv1.Notification{} n.SetId("n1") n.SetName("Mystery")
data := &WorkspaceData{Notifications: []*notificationv1.Notification{n}} gen := NewGenerator(data) nContent := string(gen.GenerateNotificationsFile().Bytes()) importsContent := string(gen.GenerateImportsFile().Bytes())
if nContent != "" { t.Errorf("expected empty notifications file for skipped resource, got:\n%s", nContent) } mustNotContain(t, importsContent, "openstatus_notification.mystery") mustNotContain(t, importsContent, `id = "n1"`)}
func TestGenerateMonitorsFile_HTTP_OpenTelemetry(t *testing.T) { ot := &monitorv1.OpenTelemetryConfig{} ot.SetEndpoint("https://otel.example.com/v1/metrics") h := &monitorv1.Headers{} h.SetKey("X-Api-Key") h.SetValue("secret") ot.SetHeaders([]*monitorv1.Headers{h})
m := &monitorv1.HTTPMonitor{} m.SetId("1") m.SetName("API") m.SetUrl("https://api.example.com") m.SetPeriodicity(monitorv1.Periodicity_PERIODICITY_5M) m.SetActive(true) m.SetOpenTelemetry(ot)
data := &WorkspaceData{HTTPMonitors: []*monitorv1.HTTPMonitor{m}} gen := NewGenerator(data) content := string(gen.GenerateMonitorsFile().Bytes())
mustContain(t, content, "open_telemetry {") mustContain(t, content, `endpoint = "https://otel.example.com/v1/metrics"`) mustContain(t, content, `key = "X-Api-Key"`) mustContain(t, content, `value = "secret"`)}
func TestGenerateMonitorsFile_TCP_OpenTelemetry(t *testing.T) { ot := &monitorv1.OpenTelemetryConfig{} ot.SetEndpoint("https://otel.example.com/v1/metrics")
m := &monitorv1.TCPMonitor{} m.SetId("1") m.SetName("TCP") m.SetUri("example.com:443") m.SetPeriodicity(monitorv1.Periodicity_PERIODICITY_5M) m.SetActive(true) m.SetOpenTelemetry(ot)
data := &WorkspaceData{TCPMonitors: []*monitorv1.TCPMonitor{m}} gen := NewGenerator(data) content := string(gen.GenerateMonitorsFile().Bytes())
mustContain(t, content, "open_telemetry {") mustContain(t, content, `endpoint = "https://otel.example.com/v1/metrics"`)}
func TestGenerateMonitorsFile_DNS_OpenTelemetry(t *testing.T) { ot := &monitorv1.OpenTelemetryConfig{} ot.SetEndpoint("https://otel.example.com/v1/metrics")
m := &monitorv1.DNSMonitor{} m.SetId("1") m.SetName("DNS") m.SetUri("example.com") m.SetPeriodicity(monitorv1.Periodicity_PERIODICITY_5M) m.SetActive(true) m.SetOpenTelemetry(ot)
data := &WorkspaceData{DNSMonitors: []*monitorv1.DNSMonitor{m}} gen := NewGenerator(data) content := string(gen.GenerateMonitorsFile().Bytes())
mustContain(t, content, "open_telemetry {") mustContain(t, content, `endpoint = "https://otel.example.com/v1/metrics"`)}
func TestGenerateMonitorsFile_OpenTelemetry_SkippedWhenEmpty(t *testing.T) { m := &monitorv1.HTTPMonitor{} m.SetId("1") m.SetName("API") m.SetUrl("https://api.example.com") m.SetPeriodicity(monitorv1.Periodicity_PERIODICITY_5M) m.SetActive(true) m.SetOpenTelemetry(&monitorv1.OpenTelemetryConfig{})
data := &WorkspaceData{HTTPMonitors: []*monitorv1.HTTPMonitor{m}} gen := NewGenerator(data) content := string(gen.GenerateMonitorsFile().Bytes())
mustNotContain(t, content, "open_telemetry")}
func TestGenerateMonitorsFile_RegionsSorted(t *testing.T) { m := &monitorv1.HTTPMonitor{} m.SetId("1") m.SetName("API") m.SetUrl("https://api.example.com") m.SetPeriodicity(monitorv1.Periodicity_PERIODICITY_5M) m.SetActive(true) m.SetRegions([]monitorv1.Region{ monitorv1.Region_REGION_FLY_SYD, monitorv1.Region_REGION_FLY_AMS, monitorv1.Region_REGION_FLY_IAD, })
data := &WorkspaceData{HTTPMonitors: []*monitorv1.HTTPMonitor{m}} gen := NewGenerator(data) content := string(gen.GenerateMonitorsFile().Bytes())
mustContain(t, content, `["fly-ams", "fly-iad", "fly-syd"]`)}
func TestGenerateStatusPagesFile_ComponentGroupDefaultOpen(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Page") page.SetSlug("page")
grpOpen := &status_pagev1.PageComponentGroup{} grpOpen.SetId("g1") grpOpen.SetPageId("p1") grpOpen.SetName("Infrastructure") grpOpen.SetDefaultOpen(true)
grpClosed := &status_pagev1.PageComponentGroup{} grpClosed.SetId("g2") grpClosed.SetPageId("p1") grpClosed.SetName("Other")
data := &WorkspaceData{ StatusPages: []StatusPageData{{ Page: page, Groups: []*status_pagev1.PageComponentGroup{grpOpen, grpClosed}, }}, } gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `resource "openstatus_status_page_component_group" "infrastructure"`) mustContain(t, content, `default_open = true`) mustContain(t, content, `resource "openstatus_status_page_component_group" "other"`)
otherStart := strings.Index(content, `"other"`) if otherStart == -1 { t.Fatalf("expected 'other' resource not found") } otherBlock := content[otherStart:] if strings.Contains(otherBlock[:strings.Index(otherBlock, "}")], "default_open") { t.Errorf("default_open should not be emitted for the 'other' group, got:\n%s", otherBlock) }}
func TestGenerateStatusPagesFile_IPAccess(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Internal") page.SetSlug("internal") page.SetAccessType(status_pagev1.PageAccessType_PAGE_ACCESS_TYPE_IP_RESTRICTED) page.SetAllowedIpRanges("10.0.0.0/8,192.168.0.0/16")
data := &WorkspaceData{StatusPages: []StatusPageData{{Page: page}}} gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `access_type = "ip"`) mustContain(t, content, `allowed_ip_ranges = "10.0.0.0/8,192.168.0.0/16"`) mustNotContain(t, content, "REPLACE_ME")}
func TestGenerateStatusPagesFile_IPAccessEmptyFallback(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Internal") page.SetSlug("internal") page.SetAccessType(status_pagev1.PageAccessType_PAGE_ACCESS_TYPE_IP_RESTRICTED)
data := &WorkspaceData{StatusPages: []StatusPageData{{Page: page}}} gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `access_type = "ip"`) mustContain(t, content, `allowed_ip_ranges = "REPLACE_ME"`) mustContain(t, content, "# TODO:")}
func TestGenerateStatusPagesFile_EmailDomainAccess(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Internal") page.SetSlug("internal") page.SetAccessType(status_pagev1.PageAccessType_PAGE_ACCESS_TYPE_AUTHENTICATED) page.SetAuthEmailDomains([]string{"example.com", "acme.com"})
data := &WorkspaceData{StatusPages: []StatusPageData{{Page: page}}} gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `access_type = "email-domain"`) mustContain(t, content, `auth_email_domains = ["acme.com", "example.com"]`) mustNotContain(t, content, "REPLACE_ME")}
func TestGenerateStatusPagesFile_EmailDomainEmptyFallback(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Internal") page.SetSlug("internal") page.SetAccessType(status_pagev1.PageAccessType_PAGE_ACCESS_TYPE_AUTHENTICATED)
data := &WorkspaceData{StatusPages: []StatusPageData{{Page: page}}} gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `access_type = "email-domain"`) mustContain(t, content, `auth_email_domains = ["REPLACE_ME"]`) mustContain(t, content, "# TODO:")}
func TestGenerateStatusPagesFile_ThemeLocaleAllowIndex(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Themed") page.SetSlug("themed") page.SetTheme(status_pagev1.PageTheme_PAGE_THEME_DARK) page.SetDefaultLocale(status_pagev1.Locale_LOCALE_FR) page.SetLocales([]status_pagev1.Locale{ status_pagev1.Locale_LOCALE_FR, status_pagev1.Locale_LOCALE_EN, }) page.SetAllowIndex(true)
data := &WorkspaceData{StatusPages: []StatusPageData{{Page: page}}} gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustContain(t, content, `theme = "dark"`) mustContain(t, content, `default_locale = "fr"`) mustContain(t, content, `locales = ["en", "fr"]`) mustContain(t, content, `allow_index = true`)}
func TestGenerateStatusPagesFile_DefaultsOmitted(t *testing.T) { page := &status_pagev1.StatusPage{} page.SetId("p1") page.SetTitle("Plain") page.SetSlug("plain") page.SetTheme(status_pagev1.PageTheme_PAGE_THEME_SYSTEM) page.SetDefaultLocale(status_pagev1.Locale_LOCALE_EN)
data := &WorkspaceData{StatusPages: []StatusPageData{{Page: page}}} gen := NewGenerator(data) content := string(gen.GenerateStatusPagesFile().Bytes())
mustNotContain(t, content, "theme") mustNotContain(t, content, "default_locale") mustNotContain(t, content, "locales") mustNotContain(t, content, "allow_index")}
func mustContain(t *testing.T, content, substr string) { t.Helper() if !strings.Contains(content, substr) { t.Errorf("expected output to contain %q, got:\n%s", substr, content) }}
func mustNotContain(t *testing.T, content, substr string) { t.Helper() if strings.Contains(content, substr) { t.Errorf("expected output NOT to contain %q, got:\n%s", substr, content) }}