github.com/GoogleCloudPlatform/testgrid@v0.0.174/util/queue/persist_test.go (about) 1 /* 2 Copyright 2022 The TestGrid 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 queue 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/util/gcs" 28 "github.com/GoogleCloudPlatform/testgrid/util/gcs/fake" 29 "github.com/google/go-cmp/cmp" 30 "github.com/sirupsen/logrus" 31 ) 32 33 func TestFixPersistent(t *testing.T) { 34 now := time.Now().Round(time.Second) 35 next := now.Add(time.Minute) 36 later := now.Add(time.Hour) 37 cases := []struct { 38 name string 39 q *Queue 40 currently fake.Object 41 ticks []time.Time 42 fixes map[string]time.Time 43 wantCurrent map[string]time.Time 44 wantBuf string 45 }{ 46 { 47 name: "basic", 48 q: &Queue{}, 49 wantCurrent: map[string]time.Time{}, 50 }, 51 { 52 name: "no load", 53 q: func() *Queue { 54 var q Queue 55 q.Init(logrus.New(), []string{"foo", "bar"}, next) 56 return &q 57 }(), 58 wantCurrent: map[string]time.Time{ 59 "foo": next, 60 "bar": next, 61 }, 62 }, 63 { 64 name: "load empty", 65 q: func() *Queue { 66 var q Queue 67 q.Init(logrus.New(), []string{"foo", "bar"}, next) 68 return &q 69 }(), 70 ticks: []time.Time{now}, 71 wantCurrent: map[string]time.Time{ 72 "foo": next, 73 "bar": next, 74 }, 75 }, 76 { 77 name: "load", 78 q: func() *Queue { 79 var q Queue 80 q.Init(logrus.New(), []string{"keep-next", "bump-to-now"}, next) 81 return &q 82 }(), 83 ticks: []time.Time{now}, 84 currently: fake.Object{ 85 Data: func() string { 86 saved := map[string]time.Time{ 87 "keep-next": later, 88 "bump-to-now": now, 89 "ignore-old": now, 90 } 91 buf, err := json.Marshal(saved) 92 if err != nil { 93 t.Fatalf("Failed to marshal: %v", err) 94 } 95 return string(buf) 96 }(), 97 Attrs: &storage.ReaderObjectAttrs{}, 98 }, 99 wantCurrent: map[string]time.Time{ 100 "keep-next": next, 101 "bump-to-now": now, 102 }, 103 }, 104 { 105 name: "load err", 106 q: func() *Queue { 107 var q Queue 108 q.Init(logrus.New(), []string{"keep-next", "would-bump-to-now-if-read"}, next) 109 return &q 110 }(), 111 ticks: []time.Time{now}, 112 currently: fake.Object{ 113 Data: func() string { 114 saved := map[string]time.Time{ 115 "keep-next": later, 116 "would-bump-to-now-if-read": now, 117 } 118 buf, err := json.Marshal(saved) 119 if err != nil { 120 t.Fatalf("Failed to marshal: %v", err) 121 } 122 return string(buf) 123 }(), 124 Attrs: &storage.ReaderObjectAttrs{}, 125 OpenErr: errors.New("fake open error"), 126 }, 127 wantCurrent: map[string]time.Time{ 128 "keep-next": next, 129 "would-bump-to-now-if-read": next, 130 }, 131 }, 132 { 133 name: "load and save", 134 q: func() *Queue { 135 var q Queue 136 q.Init(logrus.New(), []string{"keep-next", "bump-to-now"}, next) 137 return &q 138 }(), 139 ticks: []time.Time{now, now, now}, 140 currently: fake.Object{ 141 Data: func() string { 142 saved := map[string]time.Time{ 143 "keep-next": later, 144 "bump-to-now": now, 145 "ignore-old": now, 146 } 147 buf, err := json.Marshal(saved) 148 if err != nil { 149 t.Fatalf("Failed to marshal: %v", err) 150 } 151 return string(buf) 152 }(), 153 Attrs: &storage.ReaderObjectAttrs{}, 154 }, 155 wantCurrent: map[string]time.Time{ 156 "keep-next": next, 157 "bump-to-now": now, 158 }, 159 wantBuf: func() string { 160 saved := map[string]time.Time{ 161 "keep-next": next, 162 "bump-to-now": now, 163 } 164 buf, err := json.MarshalIndent(saved, "", " ") 165 if err != nil { 166 t.Fatalf("Failed to marshal: %v", err) 167 } 168 return string(buf) 169 }(), 170 }, 171 } 172 173 path, err := gcs.NewPath("gs://fake-bucket/path/to/whatever") 174 if err != nil { 175 t.Fatalf("NewPath(): %v", err) 176 } 177 178 for _, tc := range cases { 179 t.Run(tc.name, func(t *testing.T) { 180 client := fake.UploadClient{ 181 Uploader: fake.Uploader{}, 182 Client: fake.Client{ 183 Opener: fake.Opener{ 184 Paths: map[gcs.Path]fake.Object{ 185 *path: tc.currently, 186 }, 187 }, 188 }, 189 } 190 ch := make(chan time.Time) 191 fix := FixPersistent(logrus.WithField("name", tc.name), client, *path, ch) 192 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) 193 defer cancel() 194 go func() { 195 for _, tick := range tc.ticks { 196 ch <- tick 197 } 198 cancel() 199 }() 200 if err := fix(ctx, tc.q); !errors.Is(err, context.Canceled) { 201 t.Errorf("fix() returned unexpected error: %v", err) 202 } else { 203 got := tc.q.Current() 204 if diff := cmp.Diff(tc.wantCurrent, got); diff != "" { 205 t.Errorf("fix() got unexpected current diff (-want +got):\n%s", diff) 206 } 207 gotBytes := string(client.Uploader[*path].Buf) 208 if diff := cmp.Diff(tc.wantBuf, gotBytes); diff != "" { 209 t.Errorf("fix() got unexpected byte diff (-want +got):\n%s", diff) 210 } 211 212 } 213 }) 214 } 215 }