diff --git a/pkg/controller/appsync/controller.go b/pkg/controller/appsync/appsync.go similarity index 100% rename from pkg/controller/appsync/controller.go rename to pkg/controller/appsync/appsync.go diff --git a/pkg/controller/appsync/appsync_test.go b/pkg/controller/appsync/appsync_test.go index 79ff6651d..b3ba2bef8 100644 --- a/pkg/controller/appsync/appsync_test.go +++ b/pkg/controller/appsync/appsync_test.go @@ -17,6 +17,7 @@ package appsync import ( "testing" + "github.com/google/exposure-notifications-verification-server/pkg/config" "github.com/google/exposure-notifications-verification-server/pkg/database" ) @@ -27,3 +28,15 @@ func TestMain(m *testing.M) { defer testDatabaseInstance.MustClose() m.Run() } + +func TestNew(t *testing.T) { + t.Parallel() + + cfg := &config.AppSyncConfig{ + AppSyncURL: "totally invalid" + string(rune(0x7f)), + } + + if _, err := New(cfg, nil, nil); err == nil { + t.Errorf("expected error") + } +} diff --git a/pkg/controller/appsync/controller_test.go b/pkg/controller/appsync/controller_test.go deleted file mode 100644 index 9887c0962..000000000 --- a/pkg/controller/appsync/controller_test.go +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright 2021 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 appsync - -import ( - "testing" - - "github.com/google/exposure-notifications-verification-server/pkg/config" -) - -func TestNew(t *testing.T) { - t.Parallel() - - cfg := &config.AppSyncConfig{ - AppSyncURL: "totally invalid" + string(rune(0x7f)), - } - - if _, err := New(cfg, nil, nil); err == nil { - t.Errorf("expected error") - } -} diff --git a/pkg/controller/appsync/handle_sync_test.go b/pkg/controller/appsync/handle_sync_test.go index 1480de173..ff70d1369 100644 --- a/pkg/controller/appsync/handle_sync_test.go +++ b/pkg/controller/appsync/handle_sync_test.go @@ -60,34 +60,7 @@ func TestHandleSync(t *testing.T) { t.Fatal(err) } - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - - c.HandleSync().ServeHTTP(w, r) - }) - - t.Run("too_early", func(t *testing.T) { - t.Parallel() - - db, _ := testDatabaseInstance.NewDatabase(t, nil) - - c, err := New(cfg, db, h) - if err != nil { - t.Fatal(err) - } - - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleSync().ServeHTTP(w, r) if got, want := w.Code, http.StatusOK; got != want { @@ -117,13 +90,7 @@ func TestHandleSync(t *testing.T) { t.Fatal(err) } - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleSync().ServeHTTP(w, r) if got, want := w.Code, http.StatusInternalServerError; got != want { @@ -142,16 +109,9 @@ func TestHandleSync(t *testing.T) { t.Fatal(err) } - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleSync().ServeHTTP(w, r) - if got, want := w.Code, http.StatusInternalServerError; got != want { t.Errorf("Expected %d to be %d", got, want) } diff --git a/pkg/controller/cleanup/handle_cleanup_test.go b/pkg/controller/cleanup/handle_cleanup_test.go index 29ab13ff4..d50871de3 100644 --- a/pkg/controller/cleanup/handle_cleanup_test.go +++ b/pkg/controller/cleanup/handle_cleanup_test.go @@ -16,11 +16,11 @@ package cleanup import ( "net/http" - "net/http/httptest" "testing" "time" "github.com/google/exposure-notifications-server/pkg/keys" + "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/config" "github.com/google/exposure-notifications-verification-server/pkg/database" @@ -75,14 +75,7 @@ func TestHandleCleanup(t *testing.T) { t.Fatal(err) } - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleCleanup().ServeHTTP(w, r) apps, _, err := realm.ListAuthorizedApps(db, nil) @@ -109,23 +102,20 @@ func TestHandleCleanup(t *testing.T) { Code: "12345678", LongCode: "12345678901122334455", TestType: "confirmed", - ExpiresAt: time.Now().UTC().Add(2 * time.Second), - LongExpiresAt: time.Now().UTC().Add(2 * time.Second), + ExpiresAt: time.Now().UTC().Add(24 * time.Hour), + LongExpiresAt: time.Now().UTC().Add(24 * time.Hour), } if err := db.SaveVerificationCode(code, realm); err != nil { t.Fatal(err) } - - time.Sleep(5 * time.Second) - - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { + if err := db.RawDB().Model(code).UpdateColumns(&database.VerificationCode{ + ExpiresAt: time.Now().UTC().Add(-24 * time.Hour), + LongExpiresAt: time.Now().UTC().Add(-24 * time.Hour), + }).Error; err != nil { t.Fatal(err) } - r = r.Clone(ctx) - - w := httptest.NewRecorder() + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleCleanup().ServeHTTP(w, r) var codes []*database.VerificationCode @@ -155,17 +145,13 @@ func TestHandleCleanup(t *testing.T) { if err := db.RawDB().Save(token).Error; err != nil { t.Fatal(err) } - - time.Sleep(5 * time.Second) - - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { + if err := db.RawDB().Model(token).UpdateColumns(&database.Token{ + ExpiresAt: time.Now().UTC().Add(-24 * time.Hour), + }).Error; err != nil { t.Fatal(err) } - r = r.Clone(ctx) - - w := httptest.NewRecorder() + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleCleanup().ServeHTTP(w, r) var tokens []*database.Token @@ -206,14 +192,7 @@ func TestHandleCleanup(t *testing.T) { t.Fatal(err) } - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleCleanup().ServeHTTP(w, r) apps, _, err := realm.ListMobileApps(db, nil) @@ -237,14 +216,7 @@ func TestHandleCleanup(t *testing.T) { t.Fatal(err) } - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleCleanup().ServeHTTP(w, r) audits, _, err := db.ListAudits(nil) @@ -275,14 +247,7 @@ func TestHandleCleanup(t *testing.T) { t.Fatal(err) } - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleCleanup().ServeHTTP(w, r) users, _, err := db.ListUsers(nil) diff --git a/pkg/controller/rotation/handle_token_rotate_test.go b/pkg/controller/rotation/handle_token_rotate_test.go index 13ebc613c..86b10f6c2 100644 --- a/pkg/controller/rotation/handle_token_rotate_test.go +++ b/pkg/controller/rotation/handle_token_rotate_test.go @@ -16,7 +16,6 @@ package rotation import ( "net/http" - "net/http/httptest" "testing" "time" @@ -62,21 +61,13 @@ func TestHandleRotate(t *testing.T) { // Rotating should create a new key since none exists. { - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleRotate().ServeHTTP(w, r) keys, err := db.ListTokenSigningKeys() if err != nil { t.Fatal(err) } - if got, want := len(keys), 1; got != want { t.Errorf("got %d keys, expected %d", got, want) } @@ -94,21 +85,13 @@ func TestHandleRotate(t *testing.T) { t.Fatal(err) } - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleRotate().ServeHTTP(w, r) keys, err := db.ListTokenSigningKeys() if err != nil { t.Fatal(err) } - if got, want := len(keys), 2; got != want { t.Errorf("got %d keys, expected %d", got, want) } @@ -117,21 +100,13 @@ func TestHandleRotate(t *testing.T) { // Rotating again should not create a new key (not enough time has elapsed // since TokenSigningKeyMaxAge). { - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleRotate().ServeHTTP(w, r) keys, err := db.ListTokenSigningKeys() if err != nil { t.Fatal(err) } - if got, want := len(keys), 2; got != want { t.Errorf("got %d keys, expected %d", got, want) } @@ -154,13 +129,7 @@ func TestHandleRotate(t *testing.T) { c := New(cfg, db, keyManagerSigner, h) - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleRotate().ServeHTTP(w, r) if got, want := w.Code, http.StatusOK; got != want { @@ -181,14 +150,8 @@ func TestHandleRotate(t *testing.T) { db.SetRawDB(envstest.NewFailingDatabase()) c := New(cfg, db, keyManagerSigner, h) - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleRotate().ServeHTTP(w, r) if got, want := w.Code, http.StatusInternalServerError; got != want { diff --git a/pkg/controller/rotation/handle_verification_rotate_test.go b/pkg/controller/rotation/handle_verification_rotate_test.go index a5ce58961..500c538f7 100644 --- a/pkg/controller/rotation/handle_verification_rotate_test.go +++ b/pkg/controller/rotation/handle_verification_rotate_test.go @@ -17,7 +17,6 @@ package rotation import ( "context" "net/http" - "net/http/httptest" "testing" "time" @@ -27,6 +26,7 @@ import ( "github.com/google/exposure-notifications-verification-server/pkg/config" "github.com/google/exposure-notifications-verification-server/pkg/database" "github.com/google/exposure-notifications-verification-server/pkg/render" + "github.com/jinzhu/gorm" ) func TestHandleVerificationRotation(t *testing.T) { @@ -72,10 +72,10 @@ func TestHandleVerificationRotation(t *testing.T) { t.Fatal(err) } // Initial state - 1 active signing key. - checkKeys(t, db, realm, 1, 0) + keys := checkKeys(t, db, realm, 1, 0) - // Wait the max age, and run the test. - time.Sleep(cfg.VerificationSigningKeyMaxAge + time.Second) + // Set the keys as old to trigger rotation. + expireKeys(t, db, keys) invokeRotate(ctx, t, c) // There should be 2 keys on the realm now, the older one should still be the active one. checkKeys(t, db, realm, 2, 1) @@ -87,7 +87,7 @@ func TestHandleVerificationRotation(t *testing.T) { checkKeys(t, db, realm, 2, 0) // Wait long enough for original key to be deleted. - time.Sleep(cfg.VerificationActivationDelay + time.Second) + expireKeys(t, db, keys) invokeRotate(ctx, t, c) // Original key should be destroyed, only 1 key and it's active now. checkKeys(t, db, realm, 1, 0) @@ -106,13 +106,7 @@ func TestHandleVerificationRotation(t *testing.T) { c := New(cfg, db, keyManagerSigner, h) - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleVerificationRotate().ServeHTTP(w, r) if got, want := w.Code, http.StatusOK; got != want { @@ -139,14 +133,7 @@ func TestHandleVerificationRotation(t *testing.T) { } c := New(cfg, db, keyManagerSigner, h) - r, err := http.NewRequest(http.MethodGet, "/", nil) - if err != nil { - t.Fatal(err) - } - r = r.Clone(ctx) - - w := httptest.NewRecorder() - + w, r := envstest.BuildJSONRequest(ctx, t, http.MethodGet, "/", nil) c.HandleVerificationRotate().ServeHTTP(w, r) if got, want := w.Code, http.StatusInternalServerError; got != want { @@ -155,7 +142,7 @@ func TestHandleVerificationRotation(t *testing.T) { }) } -func checkKeys(tb testing.TB, db *database.Database, realm *database.Realm, count, active int) { +func checkKeys(tb testing.TB, db *database.Database, realm *database.Realm, count, active int) []*database.SigningKey { tb.Helper() keys, err := realm.ListSigningKeys(db) @@ -169,18 +156,27 @@ func checkKeys(tb testing.TB, db *database.Database, realm *database.Realm, coun if !keys[active].Active { tb.Fatalf("expected active key (%v) is not active", active) } -} -func invokeRotate(ctx context.Context, tb testing.TB, c *Controller) { - tb.Helper() + return keys +} - r, err := http.NewRequestWithContext(ctx, http.MethodGet, "/", nil) - if err != nil { - tb.Fatal(err) +func expireKeys(tb testing.TB, db *database.Database, keys []*database.SigningKey) { + for _, key := range keys { + if err := db.RawDB().Model(key).UpdateColumns(&database.SigningKey{ + Model: gorm.Model{ + CreatedAt: time.Now().UTC().Add(-720 * time.Hour), + UpdatedAt: time.Now().UTC().Add(-720 * time.Hour), + }, + }).Error; err != nil { + tb.Fatal(err) + } } +} - w := httptest.NewRecorder() +func invokeRotate(ctx context.Context, tb testing.TB, c *Controller) { + tb.Helper() + w, r := envstest.BuildJSONRequest(ctx, tb, http.MethodGet, "/", nil) c.HandleVerificationRotate().ServeHTTP(w, r) if w.Code != http.StatusOK {