go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/tq/internal/testutil/dbtest.go (about) 1 // Copyright 2020 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package testutil 16 17 import ( 18 "context" 19 "testing" 20 "time" 21 22 "go.chromium.org/luci/server/tq/internal/db" 23 "go.chromium.org/luci/server/tq/internal/partition" 24 "go.chromium.org/luci/server/tq/internal/reminder" 25 26 . "github.com/smartystreets/goconvey/convey" 27 ) 28 29 // RunDBAcceptance tests a database implementation. 30 // 31 // Sadly, GoConvey-reported error lines are borked because it doesn't search 32 // stack in files other than "*_test.go" and "*_tests.go", which this file 33 // can't be as it is in a different package. 34 // However, you can run tests for your database via $ go test 35 // and examine stacktraces for actual true line nimber. 36 // Or, you can copy this file to your package during debugging. 37 func RunDBAcceptance(ctx context.Context, db db.DB, t *testing.T) { 38 t.Parallel() 39 40 epoch := time.Date(2020, time.February, 3, 4, 5, 6, 0, time.UTC) 41 42 // Test uses keySpaceBytes=1, meaning [0..256) keyspace. 43 mkReminder := func(id int64, freshUntil time.Time, payload string) *reminder.Reminder { 44 var payloadBytes []byte 45 if payload != "" { // prefer nil instead of []byte{} 46 payloadBytes = []byte(payload) 47 } 48 low, _ := partition.FromInts(id, id+1).QueryBounds(1) 49 return &reminder.Reminder{ 50 ID: low, 51 FreshUntil: freshUntil, 52 RawPayload: payloadBytes, 53 } 54 } 55 56 Convey("Test DB "+db.Kind(), t, func() { 57 Convey("Save & Delete", func() { 58 r := mkReminder(1, epoch, "payload") 59 So(db.SaveReminder(ctx, r), ShouldBeNil) 60 So(db.DeleteReminder(ctx, r), ShouldBeNil) 61 Convey("Delete non-existing is a noop", func() { 62 So(db.DeleteReminder(ctx, r), ShouldBeNil) 63 }) 64 }) 65 66 Convey("FetchRemindersMeta", func() { 67 So(db.SaveReminder(ctx, mkReminder(254, epoch.Add(time.Second), "254")), ShouldBeNil) 68 So(db.SaveReminder(ctx, mkReminder(100, epoch.Add(time.Minute), "pay")), ShouldBeNil) 69 So(db.SaveReminder(ctx, mkReminder(255, epoch.Add(time.Hour), "load")), ShouldBeNil) 70 71 Convey("All + sorted", func() { 72 res, err := db.FetchRemindersMeta(ctx, "00", "g", 5) 73 So(err, ShouldBeNil) 74 So(res, ShouldResemble, []*reminder.Reminder{ 75 mkReminder(100, epoch.Add(time.Minute), ""), 76 mkReminder(254, epoch.Add(time.Second), ""), 77 mkReminder(255, epoch.Add(time.Hour), ""), 78 }) 79 }) 80 81 Convey("Limit", func() { 82 res, err := db.FetchRemindersMeta(ctx, "00", "g", 2) 83 So(err, ShouldBeNil) 84 So(res, ShouldResemble, []*reminder.Reminder{ 85 mkReminder(100, epoch.Add(time.Minute), ""), 86 mkReminder(254, epoch.Add(time.Second), ""), 87 }) 88 }) 89 90 Convey("Obey partition", func() { 91 res, err := db.FetchRemindersMeta(ctx, "00", "ee", 5) 92 So(err, ShouldBeNil) 93 So(res, ShouldResemble, []*reminder.Reminder{ 94 mkReminder(100, epoch.Add(time.Minute), ""), 95 }) 96 }) 97 }) 98 99 Convey("FetchReminderRawPayloads", func() { 100 all := []*reminder.Reminder{ 101 mkReminder(100, epoch.Add(time.Minute), "pay"), 102 mkReminder(254, epoch.Add(time.Second), "254"), 103 mkReminder(255, epoch.Add(time.Hour), "load"), 104 } 105 meta := make([]*reminder.Reminder, len(all)) 106 for i, r := range all { 107 meta[i] = &reminder.Reminder{ID: r.ID, FreshUntil: r.FreshUntil} 108 So(db.SaveReminder(ctx, r), ShouldBeNil) 109 } 110 111 Convey("All", func() { 112 res, err := db.FetchReminderRawPayloads(ctx, meta) 113 So(err, ShouldBeNil) 114 So(res, ShouldResemble, all) 115 Convey("Re-use objects", func() { 116 So(meta, ShouldResemble, all) 117 }) 118 }) 119 120 Convey("Some", func() { 121 second := &reminder.Reminder{ID: meta[1].ID, FreshUntil: meta[1].FreshUntil} 122 So(db.DeleteReminder(ctx, second), ShouldBeNil) 123 res, err := db.FetchReminderRawPayloads(ctx, meta) 124 So(err, ShouldBeNil) 125 So(res, ShouldResemble, []*reminder.Reminder{all[0], all[2]}) 126 Convey("Re-use objects", func() { 127 So(meta[0], ShouldResemble, all[0]) 128 So(meta[2], ShouldResemble, all[2]) 129 }) 130 }) 131 }) 132 }) 133 }