vitess.io/vitess@v0.16.2/go/mysql/mysql56_gtid_set_test.go (about) 1 /* 2 Copyright 2019 The Vitess 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 mysql 18 19 import ( 20 "fmt" 21 "reflect" 22 "strings" 23 "testing" 24 25 "github.com/stretchr/testify/assert" 26 "github.com/stretchr/testify/require" 27 ) 28 29 func TestSortSIDList(t *testing.T) { 30 input := []SID{ 31 {1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 32 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16}, 33 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 34 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 35 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 36 {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 37 } 38 want := []SID{ 39 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 40 {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 41 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 42 {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16}, 43 {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, 44 {1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}, 45 } 46 sortSIDs(input) 47 assert.True(t, reflect.DeepEqual(input, want), "got %#v, want %#v", input, want) 48 } 49 50 func TestParseMysql56GTIDSet(t *testing.T) { 51 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 52 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 255} 53 54 table := map[string]Mysql56GTIDSet{ 55 // Empty 56 "": {}, 57 // Simple case 58 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5": { 59 sid1: []interval{{1, 5}}, 60 }, 61 // Capital hex chars 62 "00010203-0405-0607-0809-0A0B0C0D0E0F:1-5": { 63 sid1: []interval{{1, 5}}, 64 }, 65 // Interval with same start and end 66 "00010203-0405-0607-0809-0a0b0c0d0e0f:12": { 67 sid1: []interval{{12, 12}}, 68 }, 69 // Multiple intervals 70 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:10-20": { 71 sid1: []interval{{1, 5}, {10, 20}}, 72 }, 73 // Multiple intervals, out of order 74 "00010203-0405-0607-0809-0a0b0c0d0e0f:10-20:1-5": { 75 sid1: []interval{{1, 5}, {10, 20}}, 76 }, 77 // Intervals with end < start are discarded by MySQL 5.6 78 "00010203-0405-0607-0809-0a0b0c0d0e0f:8-7": {}, 79 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:8-7:10-20": { 80 sid1: []interval{{1, 5}, {10, 20}}, 81 }, 82 // Same repeating SIDs 83 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5,00010203-0405-0607-0809-0a0b0c0d0e0f:10-20": { 84 sid1: []interval{{1, 5}, {10, 20}}, 85 }, 86 // Same repeating SIDs, backwards order 87 "00010203-0405-0607-0809-0a0b0c0d0e0f:10-20,00010203-0405-0607-0809-0a0b0c0d0e0f:1-5": { 88 sid1: []interval{{1, 5}, {10, 20}}, 89 }, 90 // Multiple SIDs 91 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:10-20,00010203-0405-0607-0809-0a0b0c0d0eff:1-5:50": { 92 sid1: []interval{{1, 5}, {10, 20}}, 93 sid2: []interval{{1, 5}, {50, 50}}, 94 }, 95 // Multiple SIDs with space around the comma 96 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:10-20, 00010203-0405-0607-0809-0a0b0c0d0eff:1-5:50": { 97 sid1: []interval{{1, 5}, {10, 20}}, 98 sid2: []interval{{1, 5}, {50, 50}}, 99 }, 100 } 101 102 for input, want := range table { 103 t.Run(input, func(t *testing.T) { 104 got, err := ParseMysql56GTIDSet(input) 105 require.NoError(t, err) 106 assert.Equal(t, want, got) 107 }) 108 } 109 } 110 111 func TestParseMysql56GTIDSetInvalid(t *testing.T) { 112 table := []string{ 113 // No intervals 114 "00010203-0405-0607-0809-0a0b0c0d0e0f", 115 // Invalid SID 116 "00010203-0405-060X-0809-0a0b0c0d0e0f:1-5", 117 // Invalid intervals 118 "00010203-0405-0607-0809-0a0b0c0d0e0f:0-5", 119 "00010203-0405-0607-0809-0a0b0c0d0e0f:-5", 120 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-2-3", 121 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-", 122 } 123 124 for _, input := range table { 125 _, err := ParseMysql56GTIDSet(input) 126 assert.Error(t, err, "parseMysql56GTIDSet(%#v) expected error, got none", err) 127 } 128 } 129 130 func TestMysql56GTIDSetString(t *testing.T) { 131 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 132 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 255} 133 134 table := map[string]Mysql56GTIDSet{ 135 // Simple case 136 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5": { 137 sid1: []interval{{1, 5}}, 138 }, 139 // Interval with same start and end 140 "00010203-0405-0607-0809-0a0b0c0d0e0f:12": { 141 sid1: []interval{{12, 12}}, 142 }, 143 // Multiple intervals 144 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:10-20": { 145 sid1: []interval{{1, 5}, {10, 20}}, 146 }, 147 // Multiple SIDs 148 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:10-20,00010203-0405-0607-0809-0a0b0c0d0eff:1-5:50": { 149 sid1: []interval{{1, 5}, {10, 20}}, 150 sid2: []interval{{1, 5}, {50, 50}}, 151 }, 152 } 153 154 for want, input := range table { 155 got := strings.ToLower(input.String()) 156 assert.Equal(t, want, got, "%#v.String() = %#v, want %#v", input, got, want) 157 158 } 159 } 160 161 func TestMysql56GTIDSetFlavor(t *testing.T) { 162 input := Mysql56GTIDSet{} 163 if got, want := input.Flavor(), "MySQL56"; got != want { 164 t.Errorf("%#v.Flavor() = %#v, want %#v", input, got, want) 165 } 166 } 167 168 func TestMysql56GTIDSetContainsGTID(t *testing.T) { 169 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 170 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} 171 sid3 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17} 172 173 set := Mysql56GTIDSet{ 174 sid1: []interval{{20, 30}, {35, 40}}, 175 sid2: []interval{{1, 5}, {50, 50}}, 176 } 177 178 table := map[GTID]bool{ 179 fakeGTID{}: false, 180 181 Mysql56GTID{sid1, 1}: false, 182 Mysql56GTID{sid1, 19}: false, 183 Mysql56GTID{sid1, 20}: true, 184 Mysql56GTID{sid1, 23}: true, 185 Mysql56GTID{sid1, 30}: true, 186 Mysql56GTID{sid1, 31}: false, 187 188 Mysql56GTID{sid2, 1}: true, 189 Mysql56GTID{sid2, 10}: false, 190 Mysql56GTID{sid2, 50}: true, 191 Mysql56GTID{sid2, 51}: false, 192 193 Mysql56GTID{sid3, 1}: false, 194 } 195 196 for input, want := range table { 197 if got := set.ContainsGTID(input); got != want { 198 t.Errorf("ContainsGTID(%#v) = %#v, want %#v", input, got, want) 199 } 200 } 201 } 202 203 func TestMysql56GTIDSetContains(t *testing.T) { 204 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 205 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} 206 sid3 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17} 207 208 // The set to test against. 209 set := Mysql56GTIDSet{ 210 sid1: []interval{{20, 30}, {35, 40}}, 211 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 212 } 213 214 // Test cases that should return Contains() = true. 215 contained := []Mysql56GTIDSet{ 216 // The set should contain itself. 217 set, 218 // Every set contains the empty set. 219 {}, 220 221 // Simple case 222 {sid1: []interval{{25, 30}}}, 223 // Multiple intervals 224 {sid2: []interval{{1, 2}, {4, 5}, {60, 70}}}, 225 // Multiple SIDs 226 { 227 sid1: []interval{{25, 30}, {35, 37}}, 228 sid2: []interval{{1, 5}}, 229 }, 230 } 231 232 for _, other := range contained { 233 assert.True(t, set.Contains(other), "Contains(%#v) = false, want true", other) 234 235 } 236 237 // Test cases that should return Contains() = false. 238 notContained := []GTIDSet{ 239 // Wrong flavor is not contained. 240 fakeGTID{}, 241 242 // Simple cases 243 Mysql56GTIDSet{sid1: []interval{{1, 5}}}, 244 Mysql56GTIDSet{sid1: []interval{{10, 19}}}, 245 // Overlapping intervals 246 Mysql56GTIDSet{sid1: []interval{{10, 20}}}, 247 Mysql56GTIDSet{sid1: []interval{{10, 25}}}, 248 Mysql56GTIDSet{sid1: []interval{{25, 31}}}, 249 Mysql56GTIDSet{sid1: []interval{{30, 31}}}, 250 // Multiple intervals 251 Mysql56GTIDSet{sid1: []interval{{20, 30}, {34, 34}}}, 252 // Multiple SIDs 253 Mysql56GTIDSet{ 254 sid1: []interval{{20, 30}, {36, 36}}, 255 sid2: []interval{{3, 5}, {55, 60}}, 256 }, 257 // SID is missing entirely 258 Mysql56GTIDSet{sid3: []interval{{1, 5}}}, 259 } 260 261 for _, other := range notContained { 262 if set.Contains(other) { 263 t.Errorf("Contains(%#v) = true, want false", other) 264 } 265 } 266 } 267 268 func TestMysql56GTIDSetContains2(t *testing.T) { 269 set1, err := ParseMysql56GTIDSet("16b1039f-22b6-11ed-b765-0a43f95f28a3:1-243") 270 require.NoError(t, err) 271 set2, err := ParseMysql56GTIDSet("16b1039f-22b6-11ed-b765-0a43f95f28a3:1-615") 272 require.NoError(t, err) 273 set3, err := ParseMysql56GTIDSet("16b1039f-22b6-11ed-b765-0a43f95f28a3:1-632") 274 require.NoError(t, err) 275 set4, err := ParseMysql56GTIDSet("16b1039f-22b6-11ed-b765-0a43f95f28a3:20-664") 276 require.NoError(t, err) 277 set5, err := ParseMysql56GTIDSet("16b1039f-22b6-11ed-b765-0a43f95f28a3:20-243") 278 require.NoError(t, err) 279 280 compareSet, err := ParseMysql56GTIDSet("16b1039f-22b6-11ed-b765-0a43f95f28a3:1-615") 281 require.NoError(t, err) 282 283 assert.True(t, compareSet.Contains(set1)) 284 assert.True(t, compareSet.Contains(set2)) 285 assert.False(t, compareSet.Contains(set3)) 286 assert.False(t, compareSet.Contains(set4)) 287 assert.True(t, compareSet.Contains(set5)) 288 } 289 290 func TestMysql56GTIDSetEqual(t *testing.T) { 291 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 292 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} 293 sid3 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17} 294 295 // The set to test against. 296 set := Mysql56GTIDSet{ 297 sid1: []interval{{20, 30}, {35, 40}}, 298 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 299 } 300 301 // Test cases that should return Equal() = true. 302 equal := []Mysql56GTIDSet{ 303 // Same underlying map instance 304 set, 305 // Different instance, same data 306 { 307 sid1: []interval{{20, 30}, {35, 40}}, 308 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 309 }, 310 } 311 312 for _, other := range equal { 313 assert.True(t, set.Equal(other), "%#v.Equal(%#v) = false, want true", set, other) 314 // Equality should be transitive. 315 assert.True(t, other.Equal(set), "%#v.Equal(%#v) = false, want true", other, set) 316 317 } 318 319 // Test cases that should return Equal() = false. 320 notEqual := []GTIDSet{ 321 // Wrong flavor is not equal. 322 fakeGTID{}, 323 // Empty set 324 Mysql56GTIDSet{}, 325 // Interval changed 326 Mysql56GTIDSet{ 327 sid1: []interval{{20, 31}, {35, 40}}, 328 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 329 }, 330 // Interval added 331 Mysql56GTIDSet{ 332 sid1: []interval{{20, 30}, {32, 33}, {35, 40}}, 333 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 334 }, 335 // Interval removed 336 Mysql56GTIDSet{ 337 sid1: []interval{{20, 30}, {35, 40}}, 338 sid2: []interval{{1, 5}, {60, 70}}, 339 }, 340 // Different SID, same intervals 341 Mysql56GTIDSet{ 342 sid1: []interval{{20, 30}, {35, 40}}, 343 sid3: []interval{{1, 5}, {50, 50}, {60, 70}}, 344 }, 345 // SID added 346 Mysql56GTIDSet{ 347 sid1: []interval{{20, 30}, {35, 40}}, 348 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 349 sid3: []interval{{1, 5}}, 350 }, 351 // SID removed 352 Mysql56GTIDSet{ 353 sid1: []interval{{20, 30}, {35, 40}}, 354 }, 355 } 356 357 for _, other := range notEqual { 358 if set.Equal(other) { 359 t.Errorf("%#v.Equal(%#v) = true, want false", set, other) 360 } 361 // Equality should be transitive. 362 if other.Equal(set) { 363 t.Errorf("%#v.Equal(%#v) = true, want false", other, set) 364 } 365 } 366 } 367 368 func TestMysql56GTIDSetAddGTID(t *testing.T) { 369 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 370 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} 371 sid3 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17} 372 373 // The set to test against. 374 set := Mysql56GTIDSet{ 375 sid1: []interval{{20, 30}, {35, 40}, {42, 45}}, 376 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 377 } 378 379 table := map[GTID]Mysql56GTIDSet{ 380 // Adding wrong flavor is a no-op. 381 fakeGTID{}: set, 382 383 // Adding GTIDs that are already in the set 384 Mysql56GTID{Server: sid1, Sequence: 20}: { 385 sid1: []interval{{20, 30}, {35, 40}, {42, 45}}, 386 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 387 }, 388 Mysql56GTID{Server: sid1, Sequence: 30}: { 389 sid1: []interval{{20, 30}, {35, 40}, {42, 45}}, 390 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 391 }, 392 Mysql56GTID{Server: sid1, Sequence: 25}: { 393 sid1: []interval{{20, 30}, {35, 40}, {42, 45}}, 394 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 395 }, 396 // New interval beginning 397 Mysql56GTID{Server: sid1, Sequence: 1}: { 398 sid1: []interval{{1, 1}, {20, 30}, {35, 40}, {42, 45}}, 399 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 400 }, 401 // New interval middle 402 Mysql56GTID{Server: sid1, Sequence: 32}: { 403 sid1: []interval{{20, 30}, {32, 32}, {35, 40}, {42, 45}}, 404 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 405 }, 406 // New interval end 407 Mysql56GTID{Server: sid1, Sequence: 50}: { 408 sid1: []interval{{20, 30}, {35, 40}, {42, 45}, {50, 50}}, 409 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 410 }, 411 // Extend interval start 412 Mysql56GTID{Server: sid2, Sequence: 49}: { 413 sid1: []interval{{20, 30}, {35, 40}, {42, 45}}, 414 sid2: []interval{{1, 5}, {49, 50}, {60, 70}}, 415 }, 416 // Extend interval end 417 Mysql56GTID{Server: sid2, Sequence: 51}: { 418 sid1: []interval{{20, 30}, {35, 40}, {42, 45}}, 419 sid2: []interval{{1, 5}, {50, 51}, {60, 70}}, 420 }, 421 // Merge intervals 422 Mysql56GTID{Server: sid1, Sequence: 41}: { 423 sid1: []interval{{20, 30}, {35, 45}}, 424 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 425 }, 426 // Different SID 427 Mysql56GTID{Server: sid3, Sequence: 1}: { 428 sid1: []interval{{20, 30}, {35, 40}, {42, 45}}, 429 sid2: []interval{{1, 5}, {50, 50}, {60, 70}}, 430 sid3: []interval{{1, 1}}, 431 }, 432 } 433 434 for input, want := range table { 435 if got := set.AddGTID(input); !got.Equal(want) { 436 t.Errorf("AddGTID(%#v) = %#v, want %#v", input, got, want) 437 } 438 } 439 } 440 441 func TestMysql56GTIDSetUnion(t *testing.T) { 442 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 443 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} 444 sid3 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17} 445 446 set1 := Mysql56GTIDSet{ 447 sid1: []interval{{20, 30}, {35, 40}, {42, 45}}, 448 sid2: []interval{{1, 5}, {20, 50}, {60, 70}}, 449 } 450 451 set2 := Mysql56GTIDSet{ 452 sid1: []interval{{20, 31}, {35, 37}, {41, 46}}, 453 sid2: []interval{{3, 6}, {22, 49}, {67, 72}}, 454 sid3: []interval{{1, 45}}, 455 } 456 457 got := set1.Union(set2) 458 459 want := Mysql56GTIDSet{ 460 sid1: []interval{{20, 31}, {35, 46}}, 461 sid2: []interval{{1, 6}, {20, 50}, {60, 72}}, 462 sid3: []interval{{1, 45}}, 463 } 464 assert.True(t, got.Equal(want), "set1: %#v, set1.Union(%#v) = %#v, want %#v", set1, set2, got, want) 465 466 } 467 468 func TestMysql56GTIDSetDifference(t *testing.T) { 469 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 470 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} 471 sid3 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 17} 472 sid4 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 18} 473 sid5 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 19} 474 475 set1 := Mysql56GTIDSet{ 476 sid1: []interval{{20, 30}, {35, 39}, {40, 53}, {55, 75}}, 477 sid2: []interval{{1, 7}, {20, 50}, {60, 70}}, 478 sid4: []interval{{1, 30}}, 479 sid5: []interval{{1, 7}, {20, 30}}, 480 } 481 482 set2 := Mysql56GTIDSet{ 483 sid1: []interval{{20, 30}, {35, 37}, {50, 60}}, 484 sid2: []interval{{3, 5}, {22, 25}, {32, 37}, {67, 70}}, 485 sid3: []interval{{1, 45}}, 486 sid5: []interval{{2, 6}, {15, 40}}, 487 } 488 489 got := set1.Difference(set2) 490 491 want := Mysql56GTIDSet{ 492 sid1: []interval{{38, 39}, {40, 49}, {61, 75}}, 493 sid2: []interval{{1, 2}, {6, 7}, {20, 21}, {26, 31}, {38, 50}, {60, 66}}, 494 sid4: []interval{{1, 30}}, 495 sid5: []interval{{1, 1}, {7, 7}}, 496 } 497 assert.True(t, got.Equal(want), "got %#v; want %#v", got, want) 498 499 sid10 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 500 sid11 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 501 set10 := Mysql56GTIDSet{ 502 sid10: []interval{{1, 30}}, 503 } 504 set11 := Mysql56GTIDSet{ 505 sid11: []interval{{1, 30}}, 506 } 507 got = set10.Difference(set11) 508 want = Mysql56GTIDSet{} 509 assert.True(t, got.Equal(want), "got %#v; want %#v", got, want) 510 511 } 512 513 func TestMysql56GTIDSetSIDBlock(t *testing.T) { 514 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 515 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16} 516 517 input := Mysql56GTIDSet{ 518 sid1: []interval{{20, 30}, {35, 40}}, 519 sid2: []interval{{1, 5}}, 520 } 521 want := []byte{ 522 // n_sids 523 2, 0, 0, 0, 0, 0, 0, 0, 524 // sid1 525 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 526 // sid1: n_intervals 527 2, 0, 0, 0, 0, 0, 0, 0, 528 // sid1: interval 1 start 529 20, 0, 0, 0, 0, 0, 0, 0, 530 // sid1: interval 1 end 531 31, 0, 0, 0, 0, 0, 0, 0, 532 // sid1: interval 2 start 533 35, 0, 0, 0, 0, 0, 0, 0, 534 // sid1: interval 2 end 535 41, 0, 0, 0, 0, 0, 0, 0, 536 // sid2 537 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 538 // sid2: n_intervals 539 1, 0, 0, 0, 0, 0, 0, 0, 540 // sid2: interval 1 start 541 1, 0, 0, 0, 0, 0, 0, 0, 542 // sid2: interval 1 end 543 6, 0, 0, 0, 0, 0, 0, 0, 544 } 545 got := input.SIDBlock() 546 assert.True(t, reflect.DeepEqual(got, want), "%#v.SIDBlock() = %#v, want %#v", input, got, want) 547 548 // Testing the conversion back. 549 set, err := NewMysql56GTIDSetFromSIDBlock(want) 550 require.NoError(t, err, "Reconstructing Mysql56GTIDSet from SID block failed: %v", err) 551 assert.True(t, reflect.DeepEqual(set, input), "NewMysql56GTIDSetFromSIDBlock(%#v) = %#v, want %#v", want, set, input) 552 553 } 554 555 func TestMySQL56GTIDSetLast(t *testing.T) { 556 sid1 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} 557 sid2 := SID{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 255} 558 559 table := map[string]Mysql56GTIDSet{ 560 // Simple case 561 "00010203-0405-0607-0809-0a0b0c0d0e0f:5": { 562 sid1: []interval{{1, 5}}, 563 }, 564 "00010203-0405-0607-0809-0a0b0c0d0e0f:3": { 565 sid1: []interval{{end: 3}}, 566 }, 567 // Interval with same start and end 568 "00010203-0405-0607-0809-0a0b0c0d0e0f:12": { 569 sid1: []interval{{12, 12}}, 570 }, 571 // Multiple intervals 572 "00010203-0405-0607-0809-0a0b0c0d0e0f:20": { 573 sid1: []interval{{1, 5}, {10, 20}}, 574 }, 575 // Multiple SIDs 576 "00010203-0405-0607-0809-0a0b0c0d0eff:50": { 577 sid1: []interval{{1, 5}, {10, 20}}, 578 sid2: []interval{{1, 5}, {50, 50}}, 579 }, 580 } 581 582 for want, input := range table { 583 got := strings.ToLower(input.Last()) 584 assert.Equal(t, want, got) 585 } 586 } 587 588 func TestSubtract(t *testing.T) { 589 tests := []struct { 590 name string 591 lhs string 592 rhs string 593 difference string 594 wantErr string 595 }{ 596 { 597 name: "Extra GTID set on left side", 598 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8,8bc65cca-3fe4-11ed-bbfb-091034d48b3e:1", 599 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 600 difference: "8bc65cca-3fe4-11ed-bbfb-091034d48b3e:1", 601 }, { 602 name: "Extra GTID set on right side", 603 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 604 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8,8bc65cca-3fe4-11ed-bbfb-091034d48b3e:1", 605 difference: "", 606 }, { 607 name: "Empty left side", 608 lhs: "", 609 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 610 difference: "", 611 }, { 612 name: "Empty right side", 613 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8,8bc65cca-3fe4-11ed-bbfb-091034d48b3e:1", 614 rhs: "", 615 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8,8bc65cca-3fe4-11ed-bbfb-091034d48b3e:1", 616 }, { 617 name: "Equal sets", 618 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8,8bc65cca-3fe4-11ed-bbfb-091034d48b3e:1", 619 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8,8bc65cca-3fe4-11ed-bbfb-091034d48b3e:1", 620 difference: "", 621 }, { 622 name: "subtract prefix", 623 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 624 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-3", 625 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:4-8", 626 }, { 627 name: "subtract mid", 628 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 629 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:2-3", 630 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1:4-8", 631 }, { 632 name: "subtract suffix", 633 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 634 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:7-8", 635 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-6", 636 }, { 637 name: "subtract complex range 1", 638 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8:12-17", 639 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:7-8", 640 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-6:12-17", 641 }, { 642 name: "subtract complex range 2", 643 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8:12-17", 644 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:12-13", 645 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8:14-17", 646 }, { 647 name: "subtract complex range 3", 648 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8:12-17", 649 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:7-13", 650 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-6:14-17", 651 }, { 652 name: "subtract repeating uuid", 653 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8,8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:12-17", 654 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:7-13", 655 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-6:14-17", 656 }, { 657 name: "subtract repeating uuid in descending order", 658 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:12-17,8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 659 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:7-13", 660 difference: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-6:14-17", 661 }, { 662 name: "parsing error in left set", 663 lhs: "incorrect set", 664 rhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 665 wantErr: `invalid MySQL 5.6 GTID set ("incorrect set"): expected uuid:interval`, 666 }, { 667 name: "parsing error in right set", 668 lhs: "8bc65c84-3fe4-11ed-a912-257f0fcdd6c9:1-8", 669 rhs: "incorrect set", 670 wantErr: `invalid MySQL 5.6 GTID set ("incorrect set"): expected uuid:interval`, 671 }, 672 } 673 for _, tt := range tests { 674 t.Run(fmt.Sprintf("%s: %s-%s", tt.name, tt.lhs, tt.rhs), func(t *testing.T) { 675 got, err := Subtract(tt.lhs, tt.rhs) 676 if tt.wantErr != "" { 677 assert.EqualError(t, err, tt.wantErr) 678 } else { 679 assert.NoError(t, err) 680 assert.Equal(t, tt.difference, got) 681 } 682 }) 683 } 684 } 685 686 func BenchmarkMySQL56GTIDParsing(b *testing.B) { 687 var Inputs = []string{ 688 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5", 689 "00010203-0405-0607-0809-0a0b0c0d0e0f:12", 690 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:10-20", 691 "00010203-0405-0607-0809-0a0b0c0d0e0f:10-20:1-5", 692 "00010203-0405-0607-0809-0a0b0c0d0e0f:8-7", 693 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:8-7:10-20", 694 "00010203-0405-0607-0809-0a0b0c0d0e0f:1-5:10-20,00010203-0405-0607-0809-0a0b0c0d0eff:1-5:50", 695 "8aabbf4f-5074-11ed-b225-aa23ce7e3ba2:1-20443,a6f1bf40-5073-11ed-9c0f-12a3889dc912:1-343402", 696 } 697 698 b.ReportAllocs() 699 b.ResetTimer() 700 701 for n := 0; n < b.N; n++ { 702 for _, input := range Inputs { 703 _, _ = ParseMysql56GTIDSet(input) 704 } 705 } 706 }