package alerting import ( "strings" "testing" "github.com/stretchr/testify/assert" ) var ( metricExample = `{ "version":"test", "incident":{ "incident_id":"12345", "scoping_project_id":"12345", "scoping_project_number":12345, "url":"http://www.example.com", "started_at":0, "ended_at":0, "state":"OPEN", "summary":"Test Incident", "apigee_url":"http://www.example.com", "observed_value":"1.0", "resource":{ "type":"example_resource", "labels":{"example":"label"} }, "resource_type_display_name":"Example Resource Type", "resource_id":"12345", "resource_display_name":"Example Resource", "resource_name":"projects/12345/example_resources/12345", "metric":{ "type":"test.googleapis.com/metric", "displayName":"Test Metric", "labels":{"example":"label"} }, "metadata":{ "system_labels":{"example":"label"}, "user_labels":{"example":"label"} }, "policy_name":"projects/12345/alertPolicies/12345", "policy_user_labels":{"example":"label"}, "documentation":"Test documentation", "condition":{ "name":"projects/12345/alertPolicies/12345/conditions/12345", "displayName":"Example condition", "conditionThreshold":{ "filter":"metric.type=\"test.googleapis.com/metric\" resource.type=\"example_resource\"", "comparison":"COMPARISON_GT", "thresholdValue":0.5, "duration":"0s", "trigger":{"count":1} } }, "condition_name":"Example condition", "threshold_value":"0.5"} }` metricIncidentOpen = `{ "incident": { "condition": { "conditionMonitoringQueryLanguage": { "duration": "300s", "query": "fetch prometheus_target\n| metric 'prometheus.googleapis.com/gotk_reconcile_condition/gauge'\n| filter\n resource.project_id = 'ret-edge-vfdqa1gj666jpo8b61oa9'\n &&\n (metric.status == 'False' && metric.status != 'Deleted'\n && metric.type == 'Ready' && metric.kind!~'HelmChart')\n| group_by 1m,\n [value_gotk_reconcile_condition_max: max(value.gotk_reconcile_condition)]\n| every 1m\n| filter val() != 0\n| group_by\n [metric.exported_namespace, metric.name, metric.kind, resource.project_id,\n resource.cluster],\n [value_gotk_reconcile_condition_max_max:\n max(value_gotk_reconcile_condition_max)]\n| condition val() == 1" }, "displayName": "PFJ Flux Reconcile Failures", "name": "projects/ret-edge-stage1-foreman/alertPolicies/15678640162913868409/conditions/15678640162913867352" }, "condition_name": "PFJ Flux Reconcile Failures", "documentation": { "content": "Debugging steps can be found [here](https://docs.edge-infra.dev/runbooks/customer-alerts/alerts/#flux-resource-failures)", "mime_type": "text/markdown" }, "ended_at": null, "incident_id": "0.mk9kdylxogso", "metadata": { "system_labels": {}, "user_labels": {} }, "metric": { "displayName": "", "labels": { "exported_namespace": "flux-system", "kind": "HelmRelease", "name": "store" }, "type": "" }, "policy_name": "PFJ Flux Resource Failures", "policy_user_labels": { "managed-by-cnrm": "true" }, "resource": { "labels": { "cluster": "s09570-ptc-qa-lab_v2", "project_id": "ret-edge-vfdqa1gj666jpo8b61oa9" }, "type": "timeseries_query" }, "resource_id": "", "resource_name": "ret-edge-vfdqa1gj666jpo8b61oa9 labels {project_id=ret-edge-vfdqa1gj666jpo8b61oa9, cluster=s09570-ptc-qa-lab_v2}", "resource_type_display_name": "", "scoping_project_id": "ret-edge-stage1-foreman", "scoping_project_number": 450891108899, "started_at": 1657649627, "state": "open", "summary": "PFJ Flux Resource Failures PFJ Flux Reconcile Failures alert for ret-edge-vfdqa1gj666jpo8b61oa9 labels {project_id=ret-edge-vfdqa1gj666jpo8b61oa9, cluster=s09570-ptc-qa-lab_v2} with metric labels {exported_namespace=flux-system, kind=HelmRelease, name=store} started.", "url": "https://console.cloud.google.com/monitoring/alerting/incidents/0.mk9kdylxogso?project=ret-edge-stage1-foreman" }, "version": "1.2" }` metricIncidentClosed = `{ "incident": { "condition": { "conditionMonitoringQueryLanguage": { "duration": "300s", "query": "fetch prometheus_target\n| metric 'prometheus.googleapis.com/gotk_reconcile_condition/gauge'\n| filter\n resource.project_id =~ 'ret-edge-g0k2qwvckmu1j1vkhg0hl|ret-edge-gbwujre2kp8rhmd1rw70l'\n &&\n (metric.status == 'False' && metric.status != 'Deleted'\n && metric.type == 'Ready' && metric.kind!~'HelmChart')\n| group_by 1m,\n [value_gotk_reconcile_condition_max: max(value.gotk_reconcile_condition)]\n| every 1m\n| filter val() != 0\n| group_by\n [metric.exported_namespace, metric.name, metric.kind, resource.project_id,\n resource.cluster],\n [value_gotk_reconcile_condition_max_max:\n max(value_gotk_reconcile_condition_max)]\n| condition val() == 1" }, "displayName": "RBS Flux Reconcile Failures", "name": "projects/ret-edge-stage1-foreman/alertPolicies/14331101202040885318/conditions/14331101202040888963" }, "condition_name": "RBS Flux Reconcile Failures", "documentation": { "content": "Debugging steps can be found [here](https://docs.edge-infra.dev/runbooks/customer-alerts/alerts/#flux-resource-failures)", "mime_type": "text/markdown" }, "ended_at": 1657650903, "incident_id": "0.mk9dmg7m8ohy", "metadata": { "system_labels": {}, "user_labels": {} }, "metric": { "displayName": "", "labels": { "exported_namespace": "edge-flux", "kind": "Bucket", "name": "xmv77jmg1erz-cluster-sync" }, "type": "" }, "policy_name": "RBS Flux Resource Failures", "policy_user_labels": { "managed-by-cnrm": "true" }, "resource": { "labels": { "cluster": "Store 9915", "project_id": "ret-edge-gbwujre2kp8rhmd1rw70l" }, "type": "timeseries_query" }, "resource_id": "", "resource_name": "ret-edge-gbwujre2kp8rhmd1rw70l labels {project_id=ret-edge-gbwujre2kp8rhmd1rw70l, cluster=Store 9915}", "resource_type_display_name": "", "scoping_project_id": "ret-edge-stage1-foreman", "scoping_project_number": 611910449365, "started_at": 1657631855, "state": "closed", "summary": "RBS Flux Resource Failures RBS Flux Reconcile Failures alert for ret-edge-gbwujre2kp8rhmd1rw70l labels {project_id=ret-edge-gbwujre2kp8rhmd1rw70l, cluster=Store 9915} with metric labels {exported_namespace=edge-flux, kind=Bucket, name=xmv77jmg1erz-cluster-sync} resolved.", "url": "https://console.cloud.google.com/monitoring/alerting/incidents/0.mk9dmg7m8ohy?project=ret-edge-stage1-foreman" }, "version": "1.2" }` ) func TestUnmarshal(t *testing.T) { testCases := []struct { description string incident string expectError bool }{ // todo - add more cases { "open metric incident", metricIncidentOpen, false, }, { "closed metric incident", metricIncidentClosed, false, }, { "test incident, sent when testing connection", metricExample, true, }, } for _, tc := range testCases { // remove whitespace so it's easier to compare results incTrimmed := strings.ReplaceAll(tc.incident, "\n", "") incTrimmed = strings.ReplaceAll(incTrimmed, "\t", "") incTrimmed = strings.ReplaceAll(incTrimmed, " ", "") data := []byte(incTrimmed) i, err := Unmarshal(data) if tc.expectError { assert.Error(t, err, tc.description) } else { assert.NoError(t, err, tc.description) actualData, err := Marshall(i) assert.NoError(t, err) expectedComparibleForm := strings.TrimSpace(string(data)) actualComparibleForm := strings.TrimSpace(string(actualData)) assert.Equal(t, expectedComparibleForm, actualComparibleForm) } } }