github.com/GoogleCloudPlatform/testgrid@v0.0.174/pkg/updater/persist_test.go (about) 1 /* 2 Copyright 2022 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package updater 18 19 import ( 20 "context" 21 "encoding/json" 22 "errors" 23 "testing" 24 "time" 25 26 "cloud.google.com/go/storage" 27 "github.com/GoogleCloudPlatform/testgrid/config" 28 configpb "github.com/GoogleCloudPlatform/testgrid/pb/config" 29 "github.com/GoogleCloudPlatform/testgrid/util/gcs" 30 "github.com/GoogleCloudPlatform/testgrid/util/gcs/fake" 31 "github.com/google/go-cmp/cmp" 32 "github.com/sirupsen/logrus" 33 ) 34 35 func TestFixPersistent(t *testing.T) { 36 now := time.Now().Round(time.Second) 37 next := now.Add(time.Minute) 38 later := now.Add(time.Hour) 39 cases := []struct { 40 name string 41 q *config.TestGroupQueue 42 currently fake.Object 43 ticks []time.Time 44 fixes map[string]time.Time 45 wantCurrent map[string]time.Time 46 wantBuf string 47 }{ 48 { 49 name: "basic", 50 q: &config.TestGroupQueue{}, 51 wantCurrent: map[string]time.Time{}, 52 }, 53 { 54 name: "no load", 55 q: func() *config.TestGroupQueue { 56 var q config.TestGroupQueue 57 groups := []*configpb.TestGroup{ 58 { 59 Name: "foo", 60 }, 61 { 62 Name: "bar", 63 }, 64 } 65 q.Init(logrus.New(), groups, next) 66 return &q 67 }(), 68 wantCurrent: map[string]time.Time{ 69 "foo": next, 70 "bar": next, 71 }, 72 }, 73 { 74 name: "load empty", 75 q: func() *config.TestGroupQueue { 76 var q config.TestGroupQueue 77 groups := []*configpb.TestGroup{ 78 { 79 Name: "foo", 80 }, 81 { 82 Name: "bar", 83 }, 84 } 85 q.Init(logrus.New(), groups, next) 86 return &q 87 }(), 88 ticks: []time.Time{now}, 89 wantCurrent: map[string]time.Time{ 90 "foo": next, 91 "bar": next, 92 }, 93 }, 94 { 95 name: "load", 96 q: func() *config.TestGroupQueue { 97 var q config.TestGroupQueue 98 groups := []*configpb.TestGroup{ 99 { 100 Name: "keep-next", 101 }, 102 { 103 Name: "bump-to-now", 104 }, 105 } 106 q.Init(logrus.New(), groups, next) 107 return &q 108 }(), 109 ticks: []time.Time{now}, 110 currently: fake.Object{ 111 Data: func() string { 112 saved := map[string]time.Time{ 113 "keep-next": later, 114 "bump-to-now": now, 115 "ignore-old": now, 116 } 117 buf, err := json.Marshal(saved) 118 if err != nil { 119 t.Fatalf("Failed to marshal: %v", err) 120 } 121 return string(buf) 122 }(), 123 Attrs: &storage.ReaderObjectAttrs{}, 124 }, 125 wantCurrent: map[string]time.Time{ 126 "keep-next": next, 127 "bump-to-now": now, 128 }, 129 }, 130 { 131 name: "load err", 132 q: func() *config.TestGroupQueue { 133 var q config.TestGroupQueue 134 groups := []*configpb.TestGroup{ 135 { 136 Name: "keep-next", 137 }, 138 { 139 Name: "would-bump-to-now-if-read", 140 }, 141 } 142 q.Init(logrus.New(), groups, next) 143 return &q 144 }(), 145 ticks: []time.Time{now}, 146 currently: fake.Object{ 147 Data: func() string { 148 saved := map[string]time.Time{ 149 "keep-next": later, 150 "would-bump-to-now-if-read": now, 151 } 152 buf, err := json.Marshal(saved) 153 if err != nil { 154 t.Fatalf("Failed to marshal: %v", err) 155 } 156 return string(buf) 157 }(), 158 Attrs: &storage.ReaderObjectAttrs{}, 159 OpenErr: errors.New("fake open error"), 160 }, 161 wantCurrent: map[string]time.Time{ 162 "keep-next": next, 163 "would-bump-to-now-if-read": next, 164 }, 165 }, 166 { 167 name: "load and save", 168 q: func() *config.TestGroupQueue { 169 var q config.TestGroupQueue 170 groups := []*configpb.TestGroup{ 171 { 172 Name: "keep-next", 173 }, 174 { 175 Name: "bump-to-now", 176 }, 177 } 178 q.Init(logrus.New(), groups, next) 179 return &q 180 }(), 181 ticks: []time.Time{now, now, now}, 182 currently: fake.Object{ 183 Data: func() string { 184 saved := map[string]time.Time{ 185 "keep-next": later, 186 "bump-to-now": now, 187 "ignore-old": now, 188 } 189 buf, err := json.Marshal(saved) 190 if err != nil { 191 t.Fatalf("Failed to marshal: %v", err) 192 } 193 return string(buf) 194 }(), 195 Attrs: &storage.ReaderObjectAttrs{}, 196 }, 197 wantCurrent: map[string]time.Time{ 198 "keep-next": next, 199 "bump-to-now": now, 200 }, 201 wantBuf: func() string { 202 saved := map[string]time.Time{ 203 "keep-next": next, 204 "bump-to-now": now, 205 } 206 buf, err := json.MarshalIndent(saved, "", " ") 207 if err != nil { 208 t.Fatalf("Failed to marshal: %v", err) 209 } 210 return string(buf) 211 }(), 212 }, 213 } 214 215 path, err := gcs.NewPath("gs://fake-bucket/path/to/whatever") 216 if err != nil { 217 t.Fatalf("NewPath(): %v", err) 218 } 219 220 for _, tc := range cases { 221 t.Run(tc.name, func(t *testing.T) { 222 client := fake.UploadClient{ 223 Uploader: fake.Uploader{}, 224 Client: fake.Client{ 225 Opener: fake.Opener{ 226 Paths: map[gcs.Path]fake.Object{ 227 *path: tc.currently, 228 }, 229 }, 230 }, 231 } 232 ch := make(chan time.Time) 233 fix := FixPersistent(logrus.WithField("name", tc.name), client, *path, ch) 234 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 235 defer cancel() 236 go func() { 237 for _, tick := range tc.ticks { 238 ch <- tick 239 } 240 cancel() 241 }() 242 if err := fix(ctx, nil, tc.q, nil); !errors.Is(err, context.Canceled) { 243 t.Errorf("fix() returned unexpected error: %v", err) 244 } else { 245 got := tc.q.Current() 246 if diff := cmp.Diff(tc.wantCurrent, got); diff != "" { 247 t.Errorf("fix() got unexpected current diff (-want +got):\n%s", diff) 248 } 249 gotBytes := string(client.Uploader[*path].Buf) 250 if diff := cmp.Diff(tc.wantBuf, gotBytes); diff != "" { 251 t.Errorf("fix() got unexpected byte diff (-want +got):\n%s", diff) 252 } 253 254 } 255 }) 256 } 257 }