From 546637280cd9bbfaca1b412b0c7794b1056c42d7 Mon Sep 17 00:00:00 2001 From: yuu Date: Mon, 27 May 2024 10:48:37 +0700 Subject: [PATCH 1/4] chore: status will default to 'scheduled' if the timestamp is in the future --- backend/incident_writer.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/incident_writer.go b/backend/incident_writer.go index f3278ba..4402a45 100644 --- a/backend/incident_writer.go +++ b/backend/incident_writer.go @@ -28,13 +28,18 @@ func (w *IncidentWriter) Write(ctx context.Context, incident Incident) error { return fmt.Errorf("failed to parse timestamp: %w", err) } + incidentStatus := incident.Status + if timestamp.After(time.Now()) { + incidentStatus = IncidentStatusScheduled + } + _, err = conn.ExecContext(ctx, "INSERT INTO incident_data (monitor_id, title, description, timestamp, severity, status, created_by) VALUES (?, ?, ?, ?, ?, ?, ?)", incident.MonitorID, incident.Title, incident.Description, timestamp, incident.Severity, - incident.Status, + incidentStatus, incident.CreatedBy, ) if err != nil { From f022a779c29ed6a4ee7639a2735b27ac282bc752 Mon Sep 17 00:00:00 2001 From: yuu Date: Mon, 27 May 2024 15:02:00 +0700 Subject: [PATCH 2/4] chore: change timestamp data type --- backend/incident.go | 18 +++++++++++------- backend/incident_test.go | 11 ++++------- backend/incident_writer.go | 9 ++------- 3 files changed, 17 insertions(+), 21 deletions(-) diff --git a/backend/incident.go b/backend/incident.go index 4946e63..8368ffc 100644 --- a/backend/incident.go +++ b/backend/incident.go @@ -1,7 +1,6 @@ package main import ( - "fmt" "time" ) @@ -44,24 +43,29 @@ type Incident struct { MonitorID string `json:"monitor_id"` Title string `json:"title"` Description string `json:"description"` - Timestamp string `json:"timestamp"` + Timestamp time.Time `json:"timestamp"` Severity IncidentSeverity `json:"severity"` Status IncidentStatus `json:"status"` CreatedBy string `json:"created_by"` } func (i Incident) Validate() error { - _, err := time.Parse(time.RFC3339, i.Timestamp) - if err != nil { - return err + err := NewValidationError() + + if i.Timestamp.IsZero() { + err.AddIssue("timestamp", "shouldn't be zero") } if !i.Severity.IsValid() { - return fmt.Errorf("invalid incident severity") + err.AddIssue("severity", "invalid") } if !i.Status.IsValid() { - return fmt.Errorf("invalid incident status") + err.AddIssue("status", "invalid") + } + + if err.HasIssues() { + return err } return nil diff --git a/backend/incident_test.go b/backend/incident_test.go index 981b9e7..c3a3e23 100644 --- a/backend/incident_test.go +++ b/backend/incident_test.go @@ -3,6 +3,7 @@ package main_test import ( main "semyi" "testing" + "time" ) func TestIncidentValidate(t *testing.T) { @@ -10,7 +11,7 @@ func TestIncidentValidate(t *testing.T) { MonitorID: "a84c2c59-748c-48d0-b628-4a73b1c3a8d7", Title: "test", Description: "description test", - Timestamp: "2024-05-26T15:04:05+07:00", + Timestamp: time.Date(2000, 7, 24, 4, 30, 15, 0, time.UTC), Severity: main.IncidentSeverityError, Status: main.IncidentStatusInvestigating, } @@ -18,12 +19,8 @@ func TestIncidentValidate(t *testing.T) { t.Run("Should return error if payload is invalid", func(t *testing.T) { t.Run("Timestamp", func(t *testing.T) { validPayloadCopy := validPayload - mockTimestamps := []string{ - "2024-05-26T15:04:05", - "2024-05-26", - "15:04:05", - "arbitary", - "2024-05-26 15:04:05", + mockTimestamps := []time.Time{ + time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC), } for _, timestamp := range mockTimestamps { diff --git a/backend/incident_writer.go b/backend/incident_writer.go index 4402a45..0bd7a43 100644 --- a/backend/incident_writer.go +++ b/backend/incident_writer.go @@ -23,13 +23,8 @@ func (w *IncidentWriter) Write(ctx context.Context, incident Incident) error { return fmt.Errorf("failed to get database connection: %w", err) } - timestamp, err := time.Parse(time.RFC3339, incident.Timestamp) - if err != nil { - return fmt.Errorf("failed to parse timestamp: %w", err) - } - incidentStatus := incident.Status - if timestamp.After(time.Now()) { + if incident.Timestamp.After(time.Now()) { incidentStatus = IncidentStatusScheduled } @@ -37,7 +32,7 @@ func (w *IncidentWriter) Write(ctx context.Context, incident Incident) error { incident.MonitorID, incident.Title, incident.Description, - timestamp, + incident.Timestamp, incident.Severity, incidentStatus, incident.CreatedBy, From 2fd6626659a94c0883a22e88b62c6cdb07476680 Mon Sep 17 00:00:00 2001 From: yuu Date: Mon, 27 May 2024 15:04:03 +0700 Subject: [PATCH 3/4] refactor: use custom validation error struct --- backend/incident_test.go | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/backend/incident_test.go b/backend/incident_test.go index c3a3e23..18f8282 100644 --- a/backend/incident_test.go +++ b/backend/incident_test.go @@ -1,6 +1,7 @@ package main_test import ( + "errors" main "semyi" "testing" "time" @@ -30,6 +31,11 @@ func TestIncidentValidate(t *testing.T) { if err == nil { t.Error("expect error, got nil") } + + var expectError *main.ValidationError + if !errors.As(err, &expectError) { + t.Errorf("expect error: %T, but got : %T", expectError, err) + } } }) t.Run("severity", func(t *testing.T) { @@ -43,6 +49,11 @@ func TestIncidentValidate(t *testing.T) { if err == nil { t.Error("expect error, got nil") } + + var expectError *main.ValidationError + if !errors.As(err, &expectError) { + t.Errorf("expect error: %T, but got : %T", expectError, err) + } } }) t.Run("status", func(t *testing.T) { @@ -56,6 +67,11 @@ func TestIncidentValidate(t *testing.T) { if err == nil { t.Error("expect error, got nil") } + + var expectError *main.ValidationError + if !errors.As(err, &expectError) { + t.Errorf("expect error: %T, but got : %T", expectError, err) + } } }) }) From 5f24f28188dce5593279e5cc4a9ed957a05f2d37 Mon Sep 17 00:00:00 2001 From: yuu Date: Mon, 27 May 2024 15:04:19 +0700 Subject: [PATCH 4/4] chore: optional API_KEY --- backend/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/main.go b/backend/main.go index 94deacc..da158d7 100644 --- a/backend/main.go +++ b/backend/main.go @@ -55,7 +55,7 @@ func main() { apiKey, ok := os.LookupEnv("API_KEY") if !ok { - log.Fatal().Msg("API_KEY is required") + log.Warn().Msg("API_KEY is not set") } if os.Getenv("ENV") == "" {