golang.org/x/build@v0.0.0-20240506185731-218518f32b70/maintner/netsource_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package maintner 6 7 import ( 8 "context" 9 "fmt" 10 "reflect" 11 "testing" 12 ) 13 14 func TestSumSegSize(t *testing.T) { 15 tests := []struct { 16 in []fileSeg 17 want int64 18 }{ 19 { 20 in: []fileSeg{fileSeg{size: 1}}, 21 want: 1, 22 }, 23 { 24 in: []fileSeg{fileSeg{size: 1}, fileSeg{size: 100}}, 25 want: 101, 26 }, 27 { 28 in: nil, 29 want: 0, 30 }, 31 } 32 for i, tt := range tests { 33 got := sumSegSize(tt.in) 34 if got != tt.want { 35 t.Errorf("%d. sumSegSize = %v; want %v", i, got, tt.want) 36 } 37 } 38 } 39 40 func TestSumCommonPrefixSize(t *testing.T) { 41 tests := []struct { 42 a, b []fileSeg 43 summer func(file string, n int64) string 44 want int64 45 }{ 46 { 47 a: []fileSeg{fileSeg{size: 1, sha224: "abab"}}, 48 b: []fileSeg{fileSeg{size: 1, sha224: "abab"}}, 49 want: 1, 50 }, 51 { 52 a: []fileSeg{fileSeg{size: 1, sha224: "abab"}}, 53 b: []fileSeg{fileSeg{size: 1, sha224: "eeee"}}, 54 want: 0, 55 }, 56 { 57 a: []fileSeg{ 58 fileSeg{size: 100, sha224: "abab"}, 59 fileSeg{size: 100, sha224: "abab", file: "a.mutlog"}, 60 }, 61 b: []fileSeg{ 62 fileSeg{size: 100, sha224: "abab"}, 63 fileSeg{size: 50, sha224: "cccc"}, 64 }, 65 summer: func(file string, n int64) string { 66 if file == "a.mutlog" && n == 50 { 67 return "cccc" 68 } 69 return "xxx" 70 }, 71 want: 150, 72 }, 73 { 74 a: []fileSeg{ 75 fileSeg{size: 100, sha224: "abab"}, 76 fileSeg{size: 50, sha224: "cccc"}, 77 }, 78 b: []fileSeg{ 79 fileSeg{size: 100, sha224: "abab"}, 80 fileSeg{size: 100, sha224: "abab", file: "b.mutlog"}, 81 }, 82 summer: func(file string, n int64) string { 83 if file == "b.mutlog" && n == 50 { 84 return "cccc" 85 } 86 return "xxx" 87 }, 88 want: 150, 89 }, 90 } 91 for i, tt := range tests { 92 summer := tt.summer 93 if summer == nil { 94 summer = func(file string, n int64) string { 95 t.Errorf("%d. unexpected call to prefix summer for file=%q, n=%v", i, file, n) 96 return "" 97 } 98 } 99 ns := &netMutSource{ 100 testHookFilePrefixSum224: summer, 101 } 102 got := ns.sumCommonPrefixSize(tt.a, tt.b) 103 if got != tt.want { 104 t.Errorf("%d. sumCommonPrefixSize = %v; want %v", i, got, tt.want) 105 } 106 } 107 } 108 109 func TestTrimLeadingSegBytes(t *testing.T) { 110 tests := []struct { 111 in []fileSeg 112 trim int64 113 want []fileSeg 114 }{ 115 { 116 in: []fileSeg{fileSeg{size: 100}, fileSeg{size: 50}}, 117 trim: 0, 118 want: []fileSeg{fileSeg{size: 100}, fileSeg{size: 50}}, 119 }, 120 { 121 in: []fileSeg{fileSeg{size: 100}, fileSeg{size: 50}}, 122 trim: 150, 123 want: nil, 124 }, 125 { 126 in: []fileSeg{fileSeg{size: 100}, fileSeg{size: 50}}, 127 trim: 100, 128 want: []fileSeg{fileSeg{size: 50}}, 129 }, 130 { 131 in: []fileSeg{fileSeg{size: 100}, fileSeg{size: 50}}, 132 trim: 25, 133 want: []fileSeg{fileSeg{size: 100, skip: 25}, fileSeg{size: 50}}, 134 }, 135 } 136 for i, tt := range tests { 137 copyIn := append([]fileSeg(nil), tt.in...) 138 got := trimLeadingSegBytes(tt.in, tt.trim) 139 if !reflect.DeepEqual(tt.in, copyIn) { 140 t.Fatalf("%d. trimLeadingSegBytes modified its input", i) 141 } 142 if !reflect.DeepEqual(got, tt.want) { 143 t.Fatalf("%d. trim = %+v; want %+v", i, got, tt.want) 144 } 145 } 146 } 147 148 func TestGetNewSegments(t *testing.T) { 149 type testCase struct { 150 name string 151 lastSegs []fileSeg 152 serverSegs [][]LogSegmentJSON 153 154 // prefixSum is the prefix sum to use if called. 155 // If empty, prefixSum calls are errors. 156 prefixSum string 157 158 want []fileSeg 159 wantSplit bool 160 wantSumCommon int64 161 wantUnchanged bool 162 } 163 tests := []testCase{ 164 { 165 name: "first_download", 166 serverSegs: [][]LogSegmentJSON{ 167 []LogSegmentJSON{ 168 {Number: 1, Size: 100, SHA224: "abc"}, 169 {Number: 2, Size: 200, SHA224: "def"}, 170 }, 171 }, 172 want: []fileSeg{ 173 {seg: 1, size: 100, sha224: "abc", file: "/fake/0001.mutlog"}, 174 {seg: 2, size: 200, sha224: "def", file: "/fake/0002.mutlog"}, 175 }, 176 }, 177 { 178 name: "incremental_download_growseg", // from first_download, segment 2 grows a bit 179 lastSegs: []fileSeg{ 180 {seg: 1, size: 100, sha224: "abc", file: "/fake/0001.mutlog"}, 181 {seg: 2, size: 200, sha224: "def", file: "/fake/0002.mutlog"}, 182 }, 183 prefixSum: "def", 184 serverSegs: [][]LogSegmentJSON{ 185 []LogSegmentJSON{ 186 {Number: 1, Size: 100, SHA224: "abc"}, 187 {Number: 2, Size: 205, SHA224: "defdef"}, 188 }, 189 }, 190 want: []fileSeg{ 191 {seg: 2, size: 205, sha224: "defdef", skip: 200, file: "/fake/0002.mutlog"}, 192 }, 193 }, 194 { 195 name: "incremental_download_growseg_and_newseg", // from first_download, segment 2 grows, and segment 3 appears. 196 lastSegs: []fileSeg{ 197 {seg: 1, size: 100, sha224: "abc", file: "/fake/0001.mutlog"}, 198 {seg: 2, size: 200, sha224: "def", file: "/fake/0002.mutlog"}, 199 }, 200 prefixSum: "def", 201 serverSegs: [][]LogSegmentJSON{ 202 []LogSegmentJSON{ 203 {Number: 1, Size: 100, SHA224: "abc"}, 204 {Number: 2, Size: 250, SHA224: "defdef"}, 205 {Number: 3, Size: 300, SHA224: "fff"}, 206 }, 207 }, 208 want: []fileSeg{ 209 {seg: 2, size: 250, sha224: "defdef", skip: 200, file: "/fake/0002.mutlog"}, 210 {seg: 3, size: 300, sha224: "fff", skip: 0, file: "/fake/0003.mutlog"}, 211 }, 212 }, 213 { 214 name: "incremental_download_newseg", // from first_download, segment 3 appears. 215 lastSegs: []fileSeg{ 216 {seg: 1, size: 100, sha224: "abc", file: "/fake/0001.mutlog"}, 217 {seg: 2, size: 200, sha224: "def", file: "/fake/0002.mutlog"}, 218 }, 219 serverSegs: [][]LogSegmentJSON{ 220 []LogSegmentJSON{ 221 {Number: 1, Size: 100, SHA224: "abc"}, 222 {Number: 2, Size: 200, SHA224: "def"}, 223 {Number: 3, Size: 300, SHA224: "fff"}, 224 }, 225 }, 226 want: []fileSeg{ 227 {seg: 3, size: 300, sha224: "fff", skip: 0, file: "/fake/0003.mutlog"}, 228 }, 229 }, 230 { 231 name: "faulty_server_returns_no_new_data", 232 lastSegs: []fileSeg{ 233 {seg: 1, size: 101, sha224: "abc", file: "/fake/0001.mutlog"}, 234 }, 235 serverSegs: [][]LogSegmentJSON{ 236 []LogSegmentJSON{ 237 {Number: 1, Size: 101, SHA224: "abc"}, // Same as lastSegs, results in unchanged error. 238 }, 239 []LogSegmentJSON{ 240 {Number: 1, Size: 101, SHA224: "abc"}, 241 {Number: 2, Size: 102, SHA224: "def"}, 242 }, 243 }, 244 wantUnchanged: true, 245 }, 246 { 247 name: "split_error_diff_first_seg_same_size", 248 lastSegs: []fileSeg{ 249 {seg: 1, size: 101, sha224: "abc", file: "/fake/0001.mutlog"}, 250 }, 251 serverSegs: [][]LogSegmentJSON{ 252 []LogSegmentJSON{ 253 {Number: 1, Size: 101, SHA224: "def"}, 254 }, 255 }, 256 wantSplit: true, 257 }, 258 { 259 name: "split_error_diff_first_seg_and_longer", 260 lastSegs: []fileSeg{ 261 {seg: 1, size: 101, sha224: "abc", file: "/fake/0001.mutlog"}, 262 }, 263 serverSegs: [][]LogSegmentJSON{ 264 []LogSegmentJSON{ 265 {Number: 1, Size: 102, SHA224: "def"}, 266 }, 267 }, 268 prefixSum: "ffffffffff", // no match 269 wantSplit: true, 270 }, 271 { 272 name: "split_error_diff_first_seg_and_shorter", 273 lastSegs: []fileSeg{ 274 {seg: 1, size: 101, sha224: "abc", file: "/fake/0001.mutlog"}, 275 }, 276 serverSegs: [][]LogSegmentJSON{ 277 []LogSegmentJSON{ 278 {Number: 1, Size: 50, SHA224: "def"}, 279 }, 280 }, 281 prefixSum: "ffffffffff", // no match 282 wantSplit: true, 283 }, 284 { 285 name: "split_error_same_first_seg_but_shorter", 286 lastSegs: []fileSeg{ 287 {seg: 1, size: 101, sha224: "abc", file: "/fake/0001.mutlog"}, 288 }, 289 serverSegs: [][]LogSegmentJSON{ 290 []LogSegmentJSON{ 291 {Number: 1, Size: 50, SHA224: "def"}, 292 }, 293 }, 294 prefixSum: "def", // match 295 wantSplit: true, 296 wantSumCommon: 50, 297 }, 298 { 299 name: "split_error_diff_final_seg", 300 lastSegs: []fileSeg{ 301 {seg: 1, size: 100, sha224: "abc", file: "/fake/0001.mutlog"}, 302 {seg: 2, size: 2, sha224: "def", file: "/fake/0002.mutlog"}, 303 }, 304 serverSegs: [][]LogSegmentJSON{ 305 []LogSegmentJSON{ 306 {Number: 1, Size: 100, SHA224: "abc"}, 307 {Number: 2, Size: 4, SHA224: "fff"}, 308 }, 309 }, 310 prefixSum: "not_def", 311 wantSplit: true, 312 wantSumCommon: 100, 313 }, 314 } 315 for _, tt := range tests { 316 t.Run(tt.name, func(t *testing.T) { 317 serverSegCalls := 0 318 syncSegCalls := 0 319 ns := &netMutSource{ 320 last: tt.lastSegs, 321 testHookGetServerSegments: func(_ context.Context, waitSizeNot int64) (segs []LogSegmentJSON, err error) { 322 serverSegCalls++ 323 if serverSegCalls%2 == 1 { 324 return nil, fetchError{PossiblyRetryable: true, Err: fmt.Errorf("fake error to simulate the internet saying 'not this time' every now and then")} 325 } 326 if len(tt.serverSegs) == 0 { 327 return nil, nil 328 } 329 segs = tt.serverSegs[0] 330 if len(tt.serverSegs) > 1 { 331 tt.serverSegs = tt.serverSegs[1:] 332 } 333 return segs, nil 334 }, 335 testHookSyncSeg: func(_ context.Context, seg LogSegmentJSON) (fileSeg, []byte, error) { 336 syncSegCalls++ 337 if syncSegCalls%3 == 1 { 338 return fileSeg{}, nil, fetchError{PossiblyRetryable: true, Err: fmt.Errorf("fake error to simulate the internet saying 'not this time' every now and then")} 339 } 340 return fileSeg{ 341 seg: seg.Number, 342 size: seg.Size, 343 sha224: seg.SHA224, 344 file: fmt.Sprintf("/fake/%04d.mutlog", seg.Number), 345 }, nil, nil 346 }, 347 testHookOnSplit: func(sumCommon int64) { 348 if got, want := sumCommon, tt.wantSumCommon; got != want { 349 t.Errorf("sumCommon = %v; want %v", got, want) 350 } 351 }, 352 testHookFilePrefixSum224: func(file string, n int64) string { 353 if tt.prefixSum != "" { 354 return tt.prefixSum 355 } 356 t.Errorf("unexpected call to filePrefixSum224(%q, %d)", file, n) 357 return "XXXX" 358 }, 359 } 360 got, err := ns.getNewSegments(context.Background()) 361 if tt.wantSplit { 362 if err != ErrSplit { 363 t.Fatalf("wanted ErrSplit; got %+v, %v", got, err) 364 } 365 // Success. 366 return 367 } 368 if tt.wantUnchanged { 369 if err == nil || err.Error() != "maintner.netsource: maintnerd server returned unchanged log segments" { 370 t.Fatalf("wanted unchanged; got %+v, %v", got, err) 371 } 372 // Success. 373 return 374 } 375 if err != nil { 376 t.Fatal(err) 377 } 378 if !reflect.DeepEqual(got, tt.want) { 379 t.Errorf("mismatch\n got: %+v\nwant: %+v\n", got, tt.want) 380 } 381 }) 382 } 383 }