go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/config_service/internal/retention/retention_test.go (about) 1 // Copyright 2023 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 retention 16 17 import ( 18 "testing" 19 "time" 20 21 "github.com/golang/mock/gomock" 22 23 "go.chromium.org/luci/common/clock" 24 "go.chromium.org/luci/common/clock/testclock" 25 "go.chromium.org/luci/common/gcloud/gs" 26 "go.chromium.org/luci/config" 27 "go.chromium.org/luci/gae/service/datastore" 28 29 "go.chromium.org/luci/config_service/internal/clients" 30 "go.chromium.org/luci/config_service/internal/model" 31 "go.chromium.org/luci/config_service/testutil" 32 33 . "github.com/smartystreets/goconvey/convey" 34 ) 35 36 func TestRetention(t *testing.T) { 37 t.Parallel() 38 39 Convey("DeleteStaleConfigs", t, func() { 40 ctx := testutil.SetupContext() 41 ctl := gomock.NewController(t) 42 mockGsClient := clients.NewMockGsClient(ctl) 43 ctx = clients.WithGsClient(ctx, mockGsClient) 44 45 cfgset := &model.ConfigSet{ 46 ID: config.MustProjectSet("foo"), 47 LatestRevision: model.RevisionInfo{ID: "latest"}, 48 } 49 now := clock.Get(ctx).(testclock.TestClock).Now() 50 latestCfg := &model.File{ 51 Path: "config.cfg", 52 Revision: datastore.MakeKey(ctx, model.ConfigSetKind, "projects/foo", model.RevisionKind, "latest"), 53 CreateTime: now, 54 GcsURI: gs.MakePath("bucket", "latestCfg_sha256"), 55 } 56 oldCfg1 := &model.File{ 57 Path: "config.cfg", 58 Revision: datastore.MakeKey(ctx, model.ConfigSetKind, "projects/foo", model.RevisionKind, "old1"), 59 CreateTime: now.Add(-configRetention - 1*time.Minute), 60 GcsURI: gs.MakePath("bucket", "oldCfg1_sha256"), 61 } 62 oldCfg2 := &model.File{ 63 Path: "config.cfg", 64 Revision: datastore.MakeKey(ctx, model.ConfigSetKind, "projects/foo", model.RevisionKind, "old2"), 65 CreateTime: now.Add(-configRetention - 2*time.Minute), 66 GcsURI: gs.MakePath("bucket", "oldCfg2_sha256"), 67 } 68 69 anotherCfgset := &model.ConfigSet{ 70 ID: config.MustProjectSet("bar"), 71 LatestRevision: model.RevisionInfo{ID: "latest"}, 72 } 73 barCfg := &model.File{ 74 Path: "config.cfg", 75 Revision: datastore.MakeKey(ctx, model.ConfigSetKind, "projects/bar", model.RevisionKind, "latest"), 76 CreateTime: now, 77 GcsURI: gs.MakePath("bucket", "oldCfg2_sha256"), 78 } 79 80 mockGsClient.EXPECT().Delete(gomock.Any(), gomock.Eq("bucket"), gomock.Eq("oldCfg1_sha256")).Return(nil) 81 // Don't expect oldCfg2's Gcs file to be deleted as it's referred by another in use File entity. 82 mockGsClient.EXPECT().Delete(gomock.Any(), gomock.Eq("bucket"), gomock.Eq("oldCfg2_sha256")).Times(0) 83 So(datastore.Put(ctx, cfgset, latestCfg, oldCfg1, oldCfg2, anotherCfgset, barCfg), ShouldBeNil) 84 85 So(DeleteStaleConfigs(ctx), ShouldBeNil) 86 exists, err := datastore.Exists(ctx, cfgset, latestCfg, oldCfg1, oldCfg2, anotherCfgset, barCfg) 87 So(err, ShouldBeNil) 88 So(exists.Get(0), ShouldBeTrue) // cfgset 89 So(exists.Get(1), ShouldBeTrue) // latestCfg 90 So(exists.Get(2), ShouldBeFalse) // oldCfg1 91 So(exists.Get(3), ShouldBeFalse) // oldCfg2 92 So(exists.Get(4), ShouldBeTrue) // anotherCfgset 93 So(exists.Get(5), ShouldBeTrue) // barCfg 94 }) 95 }