From b9a94b7b453db77be222ced3df72ef095dff0427 Mon Sep 17 00:00:00 2001 From: Seth Vargo Date: Sat, 5 Dec 2020 12:57:26 -0500 Subject: [PATCH] Unify common date types into project Note that this does NOT do anything with dates in HTML, since those dates tend to be formatted for style, not because of an API dependency. --- internal/project/datetime.go | 25 +++++++++++++++++++++++++ internal/project/random.go | 1 - pkg/clients/e2e.go | 3 ++- pkg/controller/admin/events_test.go | 10 +++++----- pkg/controller/codes/issue.go | 5 +++-- pkg/controller/codes/issue_test.go | 3 ++- pkg/controller/issueapi/issue_test.go | 8 +++++--- pkg/controller/issueapi/logic.go | 8 ++++---- pkg/controller/realmadmin/show.go | 3 ++- pkg/database/external_issuer_stats.go | 3 ++- pkg/database/realm_stats.go | 3 ++- pkg/database/realm_user_stats.go | 3 ++- pkg/database/token.go | 13 +++++++------ pkg/database/token_test.go | 3 ++- pkg/database/vercode.go | 2 +- pkg/database/vercode_test.go | 12 ++++++------ pkg/integration/integration_test.go | 3 ++- 17 files changed, 72 insertions(+), 36 deletions(-) create mode 100644 internal/project/datetime.go diff --git a/internal/project/datetime.go b/internal/project/datetime.go new file mode 100644 index 000000000..fd76fcc7c --- /dev/null +++ b/internal/project/datetime.go @@ -0,0 +1,25 @@ +// Copyright 2020 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package project + +const ( + // RFC3339Date formats time as RFC3339 but without a time component (e.g. + // 2020-11-24 for November 24, 20202). + RFC3339Date = "2006-01-02" + + // RFC3339Squish is the RFC3339 datetime but all dashes and timezone + // indicators are removed. This is useful for filenames. + RFC3339Squish = "20060102150405" +) diff --git a/internal/project/random.go b/internal/project/random.go index 4b775cbd2..d036aaaf8 100644 --- a/internal/project/random.go +++ b/internal/project/random.go @@ -12,7 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -// Package project defines global project helpers. package project import ( diff --git a/pkg/clients/e2e.go b/pkg/clients/e2e.go index b75b31ceb..482a928fd 100644 --- a/pkg/clients/e2e.go +++ b/pkg/clients/e2e.go @@ -22,6 +22,7 @@ import ( "net/http" "time" + "github.com/google/exposure-notifications-verification-server/internal/project" "github.com/google/exposure-notifications-verification-server/pkg/api" "github.com/google/exposure-notifications-verification-server/pkg/config" "github.com/google/exposure-notifications-verification-server/pkg/jsonclient" @@ -56,7 +57,7 @@ func RunEndToEnd(ctx context.Context, config *config.E2ETestConfig) error { testType = "likely" iterations++ } - symptomDate := time.Now().UTC().Add(-48 * time.Hour).Format("2006-01-02") + symptomDate := time.Now().UTC().Add(-48 * time.Hour).Format(project.RFC3339Date) adminID := "" revisionToken := "" diff --git a/pkg/controller/admin/events_test.go b/pkg/controller/admin/events_test.go index 32682e754..61ab21ade 100644 --- a/pkg/controller/admin/events_test.go +++ b/pkg/controller/admin/events_test.go @@ -28,7 +28,7 @@ import ( ) // This goes to the value of a -const RFC3339PartialLocal = "2006-01-02T15:04:05" +const rfc3339PartialLocal = "2006-01-02T15:04:05" func TestShowAdminEvents(t *testing.T) { t.Parallel() @@ -98,16 +98,16 @@ func TestShowAdminEvents(t *testing.T) { chromedp.WaitVisible(`body#admin-events-index`, chromedp.ByQuery), // Search from and hour before to and hour after our event - chromedp.SetValue(`#from`, eventTime.Add(-time.Hour).Format(RFC3339PartialLocal), chromedp.ByQuery), - chromedp.SetValue(`#to`, eventTime.Add(time.Hour).Format(RFC3339PartialLocal), chromedp.ByQuery), + chromedp.SetValue(`#from`, eventTime.Add(-time.Hour).Format(rfc3339PartialLocal), chromedp.ByQuery), + chromedp.SetValue(`#to`, eventTime.Add(time.Hour).Format(rfc3339PartialLocal), chromedp.ByQuery), chromedp.Submit(`form#search-form`, chromedp.ByQuery), // Wait for the search result. chromedp.WaitVisible(`#results #event`, chromedp.ByQuery), // Search an hour before the event. - chromedp.SetValue(`#from`, eventTime.Add(-2*time.Hour).Format(RFC3339PartialLocal), chromedp.ByQuery), - chromedp.SetValue(`#to`, eventTime.Add(-time.Hour).Format(RFC3339PartialLocal), chromedp.ByQuery), + chromedp.SetValue(`#from`, eventTime.Add(-2*time.Hour).Format(rfc3339PartialLocal), chromedp.ByQuery), + chromedp.SetValue(`#to`, eventTime.Add(-time.Hour).Format(rfc3339PartialLocal), chromedp.ByQuery), chromedp.Submit(`form#search-form`, chromedp.ByQuery), // Assert no event found diff --git a/pkg/controller/codes/issue.go b/pkg/controller/codes/issue.go index 5f69bd0a6..ae49cd37b 100644 --- a/pkg/controller/codes/issue.go +++ b/pkg/controller/codes/issue.go @@ -20,6 +20,7 @@ import ( "net/http" "time" + "github.com/google/exposure-notifications-verification-server/internal/project" "github.com/google/exposure-notifications-verification-server/pkg/controller" ) @@ -52,8 +53,8 @@ func (c *Controller) HandleIssue() http.Handler { now := time.Now().UTC() pastDaysDuration := -1 * c.serverconfig.AllowedSymptomAge displayAllowedDays := fmt.Sprintf("%.0f", c.serverconfig.AllowedSymptomAge.Hours()/24.0) - m["maxDate"] = now.Format("2006-01-02") - m["minDate"] = now.Add(pastDaysDuration).Format("2006-01-02") + m["maxDate"] = now.Format(project.RFC3339Date) + m["minDate"] = now.Add(pastDaysDuration).Format(project.RFC3339Date) m["maxSymptomDays"] = displayAllowedDays m["duration"] = realm.CodeDuration.Duration.String() m["hasSMSConfig"] = hasSMSConfig diff --git a/pkg/controller/codes/issue_test.go b/pkg/controller/codes/issue_test.go index 1727e0787..a8b375c0c 100644 --- a/pkg/controller/codes/issue_test.go +++ b/pkg/controller/codes/issue_test.go @@ -21,6 +21,7 @@ import ( "github.com/google/exposure-notifications-verification-server/internal/browser" "github.com/google/exposure-notifications-verification-server/internal/envstest" + "github.com/google/exposure-notifications-verification-server/internal/project" "github.com/google/exposure-notifications-verification-server/pkg/api" "github.com/google/exposure-notifications-verification-server/pkg/controller" "github.com/google/exposure-notifications-verification-server/pkg/database" @@ -70,7 +71,7 @@ func TestHandleIssue_IssueCode(t *testing.T) { taskCtx, done := context.WithTimeout(browserCtx, 30*time.Second) defer done() - yesterday := time.Now().Add(-24 * time.Hour).Format("2006-01-02") + yesterday := time.Now().Add(-24 * time.Hour).Format(project.RFC3339Date) var code string if err := chromedp.Run(taskCtx, diff --git a/pkg/controller/issueapi/issue_test.go b/pkg/controller/issueapi/issue_test.go index ff2d3306a..5e640c86f 100644 --- a/pkg/controller/issueapi/issue_test.go +++ b/pkg/controller/issueapi/issue_test.go @@ -17,6 +17,8 @@ package issueapi import ( "testing" "time" + + "github.com/google/exposure-notifications-verification-server/internal/project" ) func TestDateValidation(t *testing.T) { @@ -25,7 +27,7 @@ func TestDateValidation(t *testing.T) { t.Fatalf("error loading utc") } var aug1 time.Time - aug1, err = time.ParseInLocation("2006-01-02", "2020-08-01", utc) + aug1, err = time.ParseInLocation(project.RFC3339Date, "2020-08-01", utc) if err != nil { t.Fatalf("error parsing date") } @@ -47,7 +49,7 @@ func TestDateValidation(t *testing.T) { {"2020-07-29", aug1, -60, true, "2020-07-30"}, } for i, test := range tests { - date, err := time.ParseInLocation("2006-01-02", test.v, utc) + date, err := time.ParseInLocation(project.RFC3339Date, test.v, utc) if err != nil { t.Fatalf("[%d] error parsing date %q", i, test.v) } @@ -61,7 +63,7 @@ func TestDateValidation(t *testing.T) { } else { t.Fatalf("[%d] expected error", i) } - } else if s := newDate.Format("2006-01-02"); s != test.expected { + } else if s := newDate.Format(project.RFC3339Date); s != test.expected { t.Fatalf("[%d] validateDate returned a different date %q != %q", i, s, test.expected) } } diff --git a/pkg/controller/issueapi/logic.go b/pkg/controller/issueapi/logic.go index e2f11ec8c..619e6d365 100644 --- a/pkg/controller/issueapi/logic.go +++ b/pkg/controller/issueapi/logic.go @@ -100,7 +100,7 @@ func (c *Controller) issue(ctx context.Context, request *api.IssueCodeRequest) ( dateSettings := []*dateParseSettings{&onsetSettings, &testSettings} for i, d := range input { if d != "" { - parsed, err := time.Parse("2006-01-02", d) + parsed, err := time.Parse(project.RFC3339Date, d) if err != nil { return &issueResult{ obsBlame: observability.BlameClient, @@ -117,9 +117,9 @@ func (c *Controller) issue(ctx context.Context, request *api.IssueCodeRequest) ( if err != nil { err := fmt.Errorf("%s date must be on/after %v and on/before %v %v", dateSettings[i].Name, - minDate.Format("2006-01-02"), - maxDate.Format("2006-01-02"), - parsed.Format("2006-01-02"), + minDate.Format(project.RFC3339Date), + maxDate.Format(project.RFC3339Date), + parsed.Format(project.RFC3339Date), ) return &issueResult{ obsBlame: observability.BlameClient, diff --git a/pkg/controller/realmadmin/show.go b/pkg/controller/realmadmin/show.go index 5ddf428cb..197a913fa 100644 --- a/pkg/controller/realmadmin/show.go +++ b/pkg/controller/realmadmin/show.go @@ -24,6 +24,7 @@ import ( "time" "github.com/google/exposure-notifications-verification-server/internal/icsv" + "github.com/google/exposure-notifications-verification-server/internal/project" "github.com/google/exposure-notifications-verification-server/pkg/cache" "github.com/google/exposure-notifications-verification-server/pkg/controller" "github.com/google/exposure-notifications-verification-server/pkg/database" @@ -51,7 +52,7 @@ func (c *Controller) HandleShow() http.Handler { var stats icsv.Marshaler var err error - nowFormatted := now.Format("20060102150405") + nowFormatted := now.Format(project.RFC3339Squish) switch r.URL.Query().Get("scope") { case "external": diff --git a/pkg/database/external_issuer_stats.go b/pkg/database/external_issuer_stats.go index beed114cb..222c5388b 100644 --- a/pkg/database/external_issuer_stats.go +++ b/pkg/database/external_issuer_stats.go @@ -24,6 +24,7 @@ import ( "time" "github.com/google/exposure-notifications-verification-server/internal/icsv" + "github.com/google/exposure-notifications-verification-server/internal/project" ) var _ icsv.Marshaler = (ExternalIssuerStats)(nil) @@ -55,7 +56,7 @@ func (s ExternalIssuerStats) MarshalCSV() ([]byte, error) { for i, stat := range s { if err := w.Write([]string{ - stat.Date.Format("2006-01-02"), + stat.Date.Format(project.RFC3339Date), strconv.FormatUint(uint64(stat.RealmID), 10), stat.IssuerID, strconv.FormatUint(uint64(stat.CodesIssued), 10), diff --git a/pkg/database/realm_stats.go b/pkg/database/realm_stats.go index 33c0d848d..e58212cf6 100644 --- a/pkg/database/realm_stats.go +++ b/pkg/database/realm_stats.go @@ -24,6 +24,7 @@ import ( "time" "github.com/google/exposure-notifications-verification-server/internal/icsv" + "github.com/google/exposure-notifications-verification-server/internal/project" ) var _ icsv.Marshaler = (RealmStats)(nil) @@ -56,7 +57,7 @@ func (s RealmStats) MarshalCSV() ([]byte, error) { for i, stat := range s { if err := w.Write([]string{ - stat.Date.Format("2006-01-02"), + stat.Date.Format(project.RFC3339Date), strconv.FormatUint(uint64(stat.CodesIssued), 10), strconv.FormatUint(uint64(stat.CodesClaimed), 10), strconv.FormatUint(uint64(stat.DailyActiveUsers), 10), diff --git a/pkg/database/realm_user_stats.go b/pkg/database/realm_user_stats.go index 592ea24a5..e08f7d67a 100644 --- a/pkg/database/realm_user_stats.go +++ b/pkg/database/realm_user_stats.go @@ -24,6 +24,7 @@ import ( "time" "github.com/google/exposure-notifications-verification-server/internal/icsv" + "github.com/google/exposure-notifications-verification-server/internal/project" ) var _ icsv.Marshaler = (RealmUserStats)(nil) @@ -59,7 +60,7 @@ func (s RealmUserStats) MarshalCSV() ([]byte, error) { for i, stat := range s { if err := w.Write([]string{ - stat.Date.Format("2006-01-02"), + stat.Date.Format(project.RFC3339Date), strconv.FormatUint(uint64(stat.RealmID), 10), strconv.FormatUint(uint64(stat.UserID), 10), stat.Name, diff --git a/pkg/database/token.go b/pkg/database/token.go index 20131d02f..db2b7554c 100644 --- a/pkg/database/token.go +++ b/pkg/database/token.go @@ -23,6 +23,7 @@ import ( "time" "github.com/google/exposure-notifications-server/pkg/timeutils" + "github.com/google/exposure-notifications-verification-server/internal/project" "github.com/google/exposure-notifications-verification-server/pkg/api" "github.com/jinzhu/gorm" ) @@ -67,10 +68,10 @@ func (s *Subject) String() string { parts[0] = s.TestType if s.SymptomDate != nil { - parts[1] = s.SymptomDate.Format("2006-01-02") + parts[1] = s.SymptomDate.Format(project.RFC3339Date) } if s.TestDate != nil { - parts[2] = s.TestDate.Format("2006-01-02") + parts[2] = s.TestDate.Format(project.RFC3339Date) } return strings.Join(parts, ".") @@ -90,7 +91,7 @@ func ParseSubject(sub string) (*Subject, error) { } var symptomDate *time.Time if parts[1] != "" { - parsedDate, err := time.Parse("2006-01-02", parts[1]) + parsedDate, err := time.Parse(project.RFC3339Date, parts[1]) if err != nil { return nil, fmt.Errorf("subject contains invalid symptom date: %w", err) } @@ -99,7 +100,7 @@ func ParseSubject(sub string) (*Subject, error) { var testDate *time.Time if len(parts) == 3 && parts[2] != "" { - parsedDate, err := time.Parse("2006-01-02", parts[2]) + parsedDate, err := time.Parse(project.RFC3339Date, parts[2]) if err != nil { return nil, fmt.Errorf("subject contains invalid test date: %w", err) } @@ -118,7 +119,7 @@ func (t *Token) FormatSymptomDate() string { if t.SymptomDate == nil { return "" } - return t.SymptomDate.Format("2006-01-02") + return t.SymptomDate.Format(project.RFC3339Date) } // FormatTestDate returns YYYY-MM-DD formatted test date, or "" if nil. @@ -126,7 +127,7 @@ func (t *Token) FormatTestDate() string { if t.TestDate == nil { return "" } - return t.TestDate.Format("2006-01-02") + return t.TestDate.Format(project.RFC3339Date) } func (t *Token) Subject() *Subject { diff --git a/pkg/database/token_test.go b/pkg/database/token_test.go index 5913586d3..15b2f1cb8 100644 --- a/pkg/database/token_test.go +++ b/pkg/database/token_test.go @@ -21,6 +21,7 @@ import ( "time" "github.com/google/exposure-notifications-server/pkg/timeutils" + "github.com/google/exposure-notifications-verification-server/internal/project" "github.com/google/exposure-notifications-verification-server/pkg/api" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" @@ -29,7 +30,7 @@ import ( func TestSubject(t *testing.T) { t.Parallel() - testDay, err := time.Parse("2006-01-02", "2020-07-07") + testDay, err := time.Parse(project.RFC3339Date, "2020-07-07") if err != nil { t.Fatalf("test setup error: %v", err) } diff --git a/pkg/database/vercode.go b/pkg/database/vercode.go index 07fab782f..04d3953aa 100644 --- a/pkg/database/vercode.go +++ b/pkg/database/vercode.go @@ -179,7 +179,7 @@ func (v *VerificationCode) FormatSymptomDate() string { if v.SymptomDate == nil { return "" } - return v.SymptomDate.Format("2006-01-02") + return v.SymptomDate.Format(project.RFC3339Date) } // IsCodeExpired checks to see if the actual code provided is the short or long diff --git a/pkg/database/vercode_test.go b/pkg/database/vercode_test.go index 9619713b4..2db93cb89 100644 --- a/pkg/database/vercode_test.go +++ b/pkg/database/vercode_test.go @@ -19,6 +19,7 @@ import ( "testing" "time" + "github.com/google/exposure-notifications-verification-server/internal/project" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" "github.com/google/uuid" @@ -422,9 +423,8 @@ func TestStatDatesOnCreate(t *testing.T) { db, _ := testDatabaseInstance.NewDatabase(t, nil) - fmtString := "2006-01-02" now := time.Now() - nowStr := now.Format(fmtString) + nowStr := now.Format(project.RFC3339Date) maxAge := time.Hour tests := []struct { @@ -469,7 +469,7 @@ func TestStatDatesOnCreate(t *testing.T) { if stats[0].CodesIssued != uint(i+1) { t.Errorf("[%d] expected stat.CodesIssued = %d, expected %d", i, stats[0].CodesIssued, i+1) } - if f := stats[0].Date.Format(fmtString); f != test.statDate { + if f := stats[0].Date.Format(project.RFC3339Date); f != test.statDate { t.Errorf("[%d] expected stat.Date = %s, expected %s", i, f, test.statDate) } } @@ -491,7 +491,7 @@ func TestStatDatesOnCreate(t *testing.T) { if stats[0].CodesIssued != uint(i+1) { t.Errorf("[%d] expected stat.CodesIssued = %d, expected %d", i, stats[0].CodesIssued, i+1) } - if f := stats[0].Date.Format(fmtString); f != test.statDate { + if f := stats[0].Date.Format(project.RFC3339Date); f != test.statDate { t.Errorf("[%d] expected stat.Date = %s, expected %s", i, f, test.statDate) } } @@ -513,7 +513,7 @@ func TestStatDatesOnCreate(t *testing.T) { if stats[0].CodesIssued != uint(i+1) { t.Errorf("[%d] expected stat.CodesIssued = %d, expected %d", i, stats[0].CodesIssued, i+1) } - if f := stats[0].Date.Format(fmtString); f != test.statDate { + if f := stats[0].Date.Format(project.RFC3339Date); f != test.statDate { t.Errorf("[%d] expected stat.Date = %s, expected %s", i, f, test.statDate) } } @@ -535,7 +535,7 @@ func TestStatDatesOnCreate(t *testing.T) { if stats[0].CodesIssued != uint(i+1) { t.Errorf("[%d] expected stat.CodesIssued = %d, expected %d", i, stats[0].CodesIssued, i+1) } - if f := stats[0].Date.Format(fmtString); f != test.statDate { + if f := stats[0].Date.Format(project.RFC3339Date); f != test.statDate { t.Errorf("[%d] expected stat.Date = %s, expected %s", i, f, test.statDate) } } diff --git a/pkg/integration/integration_test.go b/pkg/integration/integration_test.go index b8fc237f5..33b61cb6d 100644 --- a/pkg/integration/integration_test.go +++ b/pkg/integration/integration_test.go @@ -25,6 +25,7 @@ import ( verifyapi "github.com/google/exposure-notifications-server/pkg/api/v1" "github.com/google/exposure-notifications-server/pkg/util" "github.com/google/exposure-notifications-server/pkg/verification" + "github.com/google/exposure-notifications-verification-server/internal/project" "github.com/google/exposure-notifications-verification-server/pkg/api" "github.com/google/exposure-notifications-verification-server/pkg/testsuite" ) @@ -80,7 +81,7 @@ func TestIntegration(t *testing.T) { now := time.Now().UTC() curDayInterval := timeToInterval(now) nextInterval := curDayInterval - symptomDate := time.Now().UTC().Add(-48 * time.Hour).Format("2006-01-02") + symptomDate := time.Now().UTC().Add(-48 * time.Hour).Format(project.RFC3339Date) testType := "confirmed" tzMinOffset := 0