1/* 2Copyright 2018 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package merge_test 18 19import ( 20 "testing" 21 22 "sigs.k8s.io/structured-merge-diff/v4/fieldpath" 23 . "sigs.k8s.io/structured-merge-diff/v4/internal/fixture" 24 "sigs.k8s.io/structured-merge-diff/v4/merge" 25 "sigs.k8s.io/structured-merge-diff/v4/typed" 26) 27 28var leafFieldsParser = func() Parser { 29 parser, err := typed.NewParser(`types: 30- name: leafFields 31 map: 32 fields: 33 - name: numeric 34 type: 35 scalar: numeric 36 - name: string 37 type: 38 scalar: string 39 - name: bool 40 type: 41 scalar: boolean`) 42 if err != nil { 43 panic(err) 44 } 45 return SameVersionParser{T: parser.Type("leafFields")} 46}() 47 48func TestUpdateLeaf(t *testing.T) { 49 tests := map[string]TestCase{ 50 "apply_twice": { 51 Ops: []Operation{ 52 Apply{ 53 Manager: "default", 54 Object: ` 55 numeric: 1 56 string: "string" 57 `, 58 APIVersion: "v1", 59 }, 60 Apply{ 61 Manager: "default", 62 Object: ` 63 numeric: 2 64 string: "string" 65 bool: false 66 `, 67 APIVersion: "v1", 68 }, 69 }, 70 Object: ` 71 numeric: 2 72 string: "string" 73 bool: false 74 `, 75 APIVersion: "v1", 76 Managed: fieldpath.ManagedFields{ 77 "default": fieldpath.NewVersionedSet( 78 _NS( 79 _P("numeric"), _P("string"), _P("bool"), 80 ), 81 "v1", 82 false, 83 ), 84 }, 85 }, 86 "apply_twice_different_versions": { 87 Ops: []Operation{ 88 Apply{ 89 Manager: "default", 90 Object: ` 91 numeric: 1 92 string: "string" 93 `, 94 APIVersion: "v1", 95 }, 96 Apply{ 97 Manager: "default", 98 Object: ` 99 numeric: 2 100 string: "string" 101 bool: false 102 `, 103 APIVersion: "v2", 104 }, 105 }, 106 Object: ` 107 numeric: 2 108 string: "string" 109 bool: false 110 `, 111 APIVersion: "v1", 112 Managed: fieldpath.ManagedFields{ 113 "default": fieldpath.NewVersionedSet( 114 _NS( 115 _P("numeric"), _P("string"), _P("bool"), 116 ), 117 "v2", 118 false, 119 ), 120 }, 121 }, 122 "apply_update_apply_no_conflict": { 123 Ops: []Operation{ 124 Apply{ 125 Manager: "default", 126 APIVersion: "v1", 127 Object: ` 128 numeric: 1 129 string: "string" 130 `, 131 }, 132 Update{ 133 Manager: "controller", 134 APIVersion: "v1", 135 Object: ` 136 numeric: 1 137 string: "string" 138 bool: true 139 `, 140 }, 141 Apply{ 142 Manager: "default", 143 APIVersion: "v1", 144 Object: ` 145 numeric: 2 146 string: "string" 147 `, 148 }, 149 }, 150 Object: ` 151 numeric: 2 152 string: "string" 153 bool: true 154 `, 155 APIVersion: "v1", 156 Managed: fieldpath.ManagedFields{ 157 "default": fieldpath.NewVersionedSet( 158 _NS( 159 _P("numeric"), _P("string"), 160 ), 161 "v1", 162 false, 163 ), 164 "controller": fieldpath.NewVersionedSet( 165 _NS( 166 _P("bool"), 167 ), 168 "v1", 169 false, 170 ), 171 }, 172 }, 173 "apply_update_apply_no_conflict_different_version": { 174 Ops: []Operation{ 175 Apply{ 176 Manager: "default", 177 APIVersion: "v1", 178 Object: ` 179 numeric: 1 180 string: "string" 181 `, 182 }, 183 Update{ 184 Manager: "controller", 185 APIVersion: "v2", 186 Object: ` 187 numeric: 1 188 string: "string" 189 bool: true 190 `, 191 }, 192 Apply{ 193 Manager: "default", 194 APIVersion: "v1", 195 Object: ` 196 numeric: 2 197 string: "string" 198 `, 199 }, 200 }, 201 Object: ` 202 numeric: 2 203 string: "string" 204 bool: true 205 `, 206 APIVersion: "v1", 207 Managed: fieldpath.ManagedFields{ 208 "default": fieldpath.NewVersionedSet( 209 _NS( 210 _P("numeric"), _P("string"), 211 ), 212 "v1", 213 false, 214 ), 215 "controller": fieldpath.NewVersionedSet( 216 _NS( 217 _P("bool"), 218 ), 219 "v2", 220 false, 221 ), 222 }, 223 }, 224 "apply_update_apply_with_conflict": { 225 Ops: []Operation{ 226 Apply{ 227 Manager: "default", 228 APIVersion: "v1", 229 Object: ` 230 numeric: 1 231 string: "string" 232 `, 233 }, 234 Update{ 235 Manager: "controller", 236 APIVersion: "v1", 237 Object: ` 238 numeric: 1 239 string: "controller string" 240 bool: true 241 `, 242 }, 243 Apply{ 244 Manager: "default", 245 APIVersion: "v1", 246 Object: ` 247 numeric: 2 248 string: "user string" 249 `, 250 Conflicts: merge.Conflicts{ 251 merge.Conflict{Manager: "controller", Path: _P("string")}, 252 }, 253 }, 254 ForceApply{ 255 Manager: "default", 256 APIVersion: "v1", 257 Object: ` 258 numeric: 2 259 string: "user string" 260 `, 261 }, 262 }, 263 Object: ` 264 numeric: 2 265 string: "user string" 266 bool: true 267 `, 268 APIVersion: "v1", 269 Managed: fieldpath.ManagedFields{ 270 "default": fieldpath.NewVersionedSet( 271 _NS( 272 _P("numeric"), _P("string"), 273 ), 274 "v1", 275 false, 276 ), 277 "controller": fieldpath.NewVersionedSet( 278 _NS( 279 _P("bool"), 280 ), 281 "v1", 282 false, 283 ), 284 }, 285 }, 286 "apply_update_apply_with_conflict_across_version": { 287 Ops: []Operation{ 288 Apply{ 289 Manager: "default", 290 APIVersion: "v1", 291 Object: ` 292 numeric: 1 293 string: "string" 294 `, 295 }, 296 Update{ 297 Manager: "controller", 298 APIVersion: "v2", 299 Object: ` 300 numeric: 1 301 string: "controller string" 302 bool: true 303 `, 304 }, 305 Apply{ 306 Manager: "default", 307 APIVersion: "v1", 308 Object: ` 309 numeric: 2 310 string: "user string" 311 `, 312 Conflicts: merge.Conflicts{ 313 merge.Conflict{Manager: "controller", Path: _P("string")}, 314 }, 315 }, 316 ForceApply{ 317 Manager: "default", 318 APIVersion: "v1", 319 Object: ` 320 numeric: 2 321 string: "user string" 322 `, 323 }, 324 }, 325 Object: ` 326 numeric: 2 327 string: "user string" 328 bool: true 329 `, 330 APIVersion: "v1", 331 Managed: fieldpath.ManagedFields{ 332 "default": fieldpath.NewVersionedSet( 333 _NS( 334 _P("numeric"), _P("string"), 335 ), 336 "v1", 337 false, 338 ), 339 "controller": fieldpath.NewVersionedSet( 340 _NS( 341 _P("bool"), 342 ), 343 "v2", 344 false, 345 ), 346 }, 347 }, 348 "apply_twice_remove": { 349 Ops: []Operation{ 350 Apply{ 351 Manager: "default", 352 APIVersion: "v1", 353 Object: ` 354 numeric: 1 355 string: "string" 356 bool: false 357 `, 358 }, 359 Apply{ 360 Manager: "default", 361 APIVersion: "v1", 362 Object: ` 363 string: "new string" 364 `, 365 }, 366 }, 367 Object: ` 368 string: "new string" 369 `, 370 APIVersion: "v1", 371 Managed: fieldpath.ManagedFields{ 372 "default": fieldpath.NewVersionedSet( 373 _NS( 374 _P("string"), 375 ), 376 "v1", 377 false, 378 ), 379 }, 380 }, 381 "update_apply_omits": { 382 Ops: []Operation{ 383 Apply{ 384 Manager: "default", 385 APIVersion: "v1", 386 Object: ` 387 numeric: 2 388 `, 389 }, 390 Update{ 391 Manager: "controller", 392 APIVersion: "v1", 393 Object: ` 394 numeric: 1 395 `, 396 }, 397 Apply{ 398 Manager: "default", 399 APIVersion: "v1", 400 Object: ``, 401 }, 402 }, 403 Object: ` 404 numeric: 1 405 `, 406 APIVersion: "v1", 407 Managed: fieldpath.ManagedFields{ 408 "controller": fieldpath.NewVersionedSet( 409 _NS( 410 _P("numeric"), 411 ), 412 "v1", 413 false, 414 ), 415 }, 416 }, 417 "apply_twice_remove_different_version": { 418 Ops: []Operation{ 419 Apply{ 420 Manager: "default", 421 APIVersion: "v1", 422 Object: ` 423 numeric: 1 424 string: "string" 425 bool: false 426 `, 427 }, 428 Apply{ 429 Manager: "default", 430 APIVersion: "v2", 431 Object: ` 432 string: "new string" 433 `, 434 }, 435 }, 436 Object: ` 437 string: "new string" 438 `, 439 APIVersion: "v1", 440 Managed: fieldpath.ManagedFields{ 441 "default": fieldpath.NewVersionedSet( 442 _NS( 443 _P("string"), 444 ), 445 "v2", 446 false, 447 ), 448 }, 449 }, 450 "update_remove_empty_set": { 451 Ops: []Operation{ 452 Apply{ 453 Manager: "default", 454 APIVersion: "v1", 455 Object: ` 456 string: "string" 457 `, 458 }, 459 Update{ 460 Manager: "controller", 461 APIVersion: "v1", 462 Object: ` 463 string: "new string" 464 `, 465 }, 466 }, 467 Object: ` 468 string: "new string" 469 `, 470 APIVersion: "v1", 471 Managed: fieldpath.ManagedFields{ 472 "controller": fieldpath.NewVersionedSet( 473 _NS( 474 _P("string"), 475 ), 476 "v1", 477 false, 478 ), 479 }, 480 }, 481 "apply_remove_empty_set": { 482 Ops: []Operation{ 483 Apply{ 484 Manager: "default", 485 APIVersion: "v1", 486 Object: ` 487 string: "string" 488 `, 489 }, 490 Apply{ 491 Manager: "default", 492 APIVersion: "v1", 493 Object: "", 494 }, 495 }, 496 Object: ` 497 `, 498 APIVersion: "v1", 499 Managed: fieldpath.ManagedFields{}, 500 }, 501 } 502 503 for name, test := range tests { 504 t.Run(name, func(t *testing.T) { 505 if err := test.Test(leafFieldsParser); err != nil { 506 t.Fatal(err) 507 } 508 }) 509 } 510} 511 512func BenchmarkLeafConflictAcrossVersion(b *testing.B) { 513 test := TestCase{ 514 Ops: []Operation{ 515 Apply{ 516 Manager: "default", 517 APIVersion: "v1", 518 Object: ` 519 numeric: 1 520 string: "string" 521 `, 522 }, 523 Update{ 524 Manager: "controller", 525 APIVersion: "v2", 526 Object: ` 527 numeric: 1 528 string: "controller string" 529 bool: true 530 `, 531 }, 532 Apply{ 533 Manager: "default", 534 APIVersion: "v1", 535 Object: ` 536 numeric: 2 537 string: "user string" 538 `, 539 Conflicts: merge.Conflicts{ 540 merge.Conflict{Manager: "controller", Path: _P("string")}, 541 }, 542 }, 543 ForceApply{ 544 Manager: "default", 545 APIVersion: "v1", 546 Object: ` 547 numeric: 2 548 string: "user string" 549 `, 550 }, 551 }, 552 Object: ` 553 numeric: 2 554 string: "user string" 555 bool: true 556 `, 557 APIVersion: "v1", 558 Managed: fieldpath.ManagedFields{ 559 "default": fieldpath.NewVersionedSet( 560 _NS( 561 _P("numeric"), _P("string"), 562 ), 563 "v1", 564 false, 565 ), 566 "controller": fieldpath.NewVersionedSet( 567 _NS( 568 _P("bool"), 569 ), 570 "v2", 571 false, 572 ), 573 }, 574 } 575 576 // Make sure this passes... 577 if err := test.Test(leafFieldsParser); err != nil { 578 b.Fatal(err) 579 } 580 581 test.PreprocessOperations(leafFieldsParser) 582 583 b.ReportAllocs() 584 b.ResetTimer() 585 for n := 0; n < b.N; n++ { 586 if err := test.Bench(leafFieldsParser); err != nil { 587 b.Fatal(err) 588 } 589 } 590} 591