github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/diff/namespace/diff_test.go (about) 1 package namespace 2 3 import ( 4 "testing" 5 6 "github.com/stretchr/testify/require" 7 8 core "github.com/authzed/spicedb/pkg/proto/core/v1" 9 10 ns "github.com/authzed/spicedb/pkg/namespace" 11 ) 12 13 func TestNamespaceDiff(t *testing.T) { 14 testCases := []struct { 15 name string 16 existing *core.NamespaceDefinition 17 updated *core.NamespaceDefinition 18 expectedDeltas []Delta 19 }{ 20 { 21 "added namespace", 22 nil, 23 ns.Namespace( 24 "document", 25 ), 26 []Delta{ 27 {Type: NamespaceAdded}, 28 }, 29 }, 30 { 31 "removed namespace", 32 ns.Namespace( 33 "document", 34 ), 35 nil, 36 []Delta{ 37 {Type: NamespaceRemoved}, 38 }, 39 }, 40 { 41 "added namespace comments", 42 ns.Namespace( 43 "document", 44 ), 45 ns.WithComment( 46 "document", 47 "some cool comment", 48 ), 49 []Delta{ 50 {Type: NamespaceCommentsChanged}, 51 }, 52 }, 53 { 54 "unchanged namespace comments", 55 ns.WithComment( 56 "document", 57 "some cool comment", 58 ), 59 ns.WithComment( 60 "document", 61 "some cool comment", 62 ), 63 []Delta{}, 64 }, 65 { 66 "changed namespace comments", 67 ns.WithComment( 68 "document", 69 "some cool comment!", 70 ), 71 ns.WithComment( 72 "document", 73 "some cool comment", 74 ), 75 []Delta{ 76 {Type: NamespaceCommentsChanged}, 77 }, 78 }, 79 { 80 "added relation", 81 ns.Namespace( 82 "document", 83 ), 84 ns.Namespace( 85 "document", 86 ns.MustRelation("somerel", nil), 87 ), 88 []Delta{ 89 {Type: AddedRelation, RelationName: "somerel"}, 90 }, 91 }, 92 { 93 "remove relation", 94 ns.Namespace( 95 "document", 96 ns.MustRelation("somerel", nil), 97 ), 98 ns.Namespace( 99 "document", 100 ), 101 []Delta{ 102 {Type: RemovedRelation, RelationName: "somerel"}, 103 }, 104 }, 105 { 106 "renamed relation", 107 ns.Namespace( 108 "document", 109 ns.MustRelation("somerel", nil), 110 ), 111 ns.Namespace( 112 "document", 113 ns.MustRelation("somerel2", nil), 114 ), 115 []Delta{ 116 {Type: RemovedRelation, RelationName: "somerel"}, 117 {Type: AddedRelation, RelationName: "somerel2"}, 118 }, 119 }, 120 { 121 "added permission", 122 ns.Namespace( 123 "document", 124 ), 125 ns.Namespace( 126 "document", 127 ns.MustRelation("someperm", ns.Union(ns.ComputedUserset("hiya"))), 128 ), 129 []Delta{ 130 {Type: AddedPermission, RelationName: "someperm"}, 131 }, 132 }, 133 { 134 "remove permission", 135 ns.Namespace( 136 "document", 137 ns.MustRelation("someperm", ns.Union(ns.ComputedUserset("hiya"))), 138 ), 139 ns.Namespace( 140 "document", 141 ), 142 []Delta{ 143 {Type: RemovedPermission, RelationName: "someperm"}, 144 }, 145 }, 146 { 147 "renamed permission", 148 ns.Namespace( 149 "document", 150 ns.MustRelation("someperm", ns.Union(ns.ComputedUserset("hiya"))), 151 ), 152 ns.Namespace( 153 "document", 154 ns.MustRelation("someperm2", ns.Union(ns.ComputedUserset("hiya"))), 155 ), 156 []Delta{ 157 {Type: RemovedPermission, RelationName: "someperm"}, 158 {Type: AddedPermission, RelationName: "someperm2"}, 159 }, 160 }, 161 { 162 "legacy changed relation impl", 163 ns.Namespace( 164 "document", 165 ns.MustRelation( 166 "somerel", 167 nil, 168 ns.AllowedRelation("someothernamespace", "somerel"), 169 ), 170 ), 171 ns.Namespace( 172 "document", 173 ns.MustRelation("somerel", 174 ns.Union( 175 ns.ComputedUserset("owner"), 176 ), 177 ns.AllowedRelation("someothernamespace", "somerel"), 178 ), 179 ), 180 []Delta{ 181 {Type: LegacyChangedRelationImpl, RelationName: "somerel"}, 182 }, 183 }, 184 { 185 "changed permission impl", 186 ns.Namespace( 187 "document", 188 ns.MustRelation("somerel", ns.Union( 189 ns.ComputedUserset("editor"), 190 )), 191 ), 192 ns.Namespace( 193 "document", 194 ns.MustRelation("somerel", ns.Union( 195 ns.ComputedUserset("owner"), 196 )), 197 ), 198 []Delta{ 199 {Type: ChangedPermissionImpl, RelationName: "somerel"}, 200 }, 201 }, 202 { 203 "changed permission comment", 204 ns.Namespace( 205 "document", 206 ns.MustRelationWithComment("somerel", "some comment", ns.Union( 207 ns.ComputedUserset("editor"), 208 )), 209 ), 210 ns.Namespace( 211 "document", 212 ns.MustRelationWithComment("somerel", "some other comment", ns.Union( 213 ns.ComputedUserset("editor"), 214 )), 215 ), 216 []Delta{ 217 {Type: ChangedPermissionComment, RelationName: "somerel"}, 218 }, 219 }, 220 { 221 "changed permission impl and comment", 222 ns.Namespace( 223 "document", 224 ns.MustRelationWithComment("somerel", "some comment", ns.Union( 225 ns.ComputedUserset("editor"), 226 )), 227 ), 228 ns.Namespace( 229 "document", 230 ns.MustRelationWithComment("somerel", "some other comment", ns.Union( 231 ns.ComputedUserset("editor2"), 232 )), 233 ), 234 []Delta{ 235 {Type: ChangedPermissionImpl, RelationName: "somerel"}, 236 {Type: ChangedPermissionComment, RelationName: "somerel"}, 237 }, 238 }, 239 { 240 "no changes", 241 ns.Namespace( 242 "document", 243 ns.MustRelationWithComment("somerel", "some comment", ns.Union( 244 ns.ComputedUserset("editor"), 245 )), 246 ), 247 ns.Namespace( 248 "document", 249 ns.MustRelationWithComment("somerel", "some comment", ns.Union( 250 ns.ComputedUserset("editor"), 251 )), 252 ), 253 []Delta{}, 254 }, 255 { 256 "added direct type", 257 ns.Namespace( 258 "document", 259 ns.MustRelation("somerel", nil), 260 ), 261 ns.Namespace( 262 "document", 263 ns.MustRelation("somerel", nil, ns.AllowedRelation("foo", "bar")), 264 ), 265 []Delta{ 266 { 267 Type: RelationAllowedTypeAdded, 268 RelationName: "somerel", 269 AllowedType: ns.AllowedRelation("foo", "bar"), 270 }, 271 }, 272 }, 273 { 274 "removed direct type", 275 ns.Namespace( 276 "document", 277 ns.MustRelation("somerel", nil, ns.AllowedRelation("foo", "bar")), 278 ), 279 ns.Namespace( 280 "document", 281 ns.MustRelation("somerel", nil), 282 ), 283 []Delta{ 284 { 285 Type: RelationAllowedTypeRemoved, 286 RelationName: "somerel", 287 AllowedType: ns.AllowedRelation("foo", "bar"), 288 }, 289 }, 290 }, 291 { 292 "no changes with types", 293 ns.Namespace( 294 "document", 295 ns.MustRelation("somerel", ns.Union( 296 ns.ComputedUserset("owner"), 297 ), ns.AllowedRelation("foo", "bar")), 298 ), 299 ns.Namespace( 300 "document", 301 ns.MustRelation("somerel", ns.Union( 302 ns.ComputedUserset("owner"), 303 ), ns.AllowedRelation("foo", "bar")), 304 ), 305 []Delta{}, 306 }, 307 { 308 "changed relation comment", 309 ns.Namespace( 310 "document", 311 ns.MustRelationWithComment("somerel", "some comment", ns.Union( 312 ns.ComputedUserset("owner"), 313 ), ns.AllowedRelation("foo", "bar")), 314 ), 315 ns.Namespace( 316 "document", 317 ns.MustRelationWithComment("somerel", "changed comment", ns.Union( 318 ns.ComputedUserset("owner"), 319 ), ns.AllowedRelation("foo", "bar")), 320 ), 321 []Delta{ 322 {Type: ChangedRelationComment, RelationName: "somerel"}, 323 }, 324 }, 325 { 326 "type added and removed", 327 ns.Namespace( 328 "document", 329 ns.MustRelation("somerel", ns.Union( 330 ns.ComputedUserset("owner"), 331 ), ns.AllowedRelation("foo", "bar")), 332 ), 333 ns.Namespace( 334 "document", 335 ns.MustRelation("somerel", ns.Union( 336 ns.ComputedUserset("owner"), 337 ), ns.AllowedRelation("foo2", "bar")), 338 ), 339 []Delta{ 340 { 341 Type: RelationAllowedTypeRemoved, 342 RelationName: "somerel", 343 AllowedType: ns.AllowedRelation("foo", "bar"), 344 }, 345 { 346 Type: RelationAllowedTypeAdded, 347 RelationName: "somerel", 348 AllowedType: ns.AllowedRelation("foo2", "bar"), 349 }, 350 }, 351 }, 352 { 353 "wildcard type added and removed", 354 ns.Namespace( 355 "document", 356 ns.MustRelation("somerel", ns.Union( 357 ns.ComputedUserset("owner"), 358 ), ns.AllowedPublicNamespace("foo")), 359 ), 360 ns.Namespace( 361 "document", 362 ns.MustRelation("somerel", ns.Union( 363 ns.ComputedUserset("owner"), 364 ), ns.AllowedPublicNamespace("foo2")), 365 ), 366 []Delta{ 367 { 368 Type: RelationAllowedTypeRemoved, 369 RelationName: "somerel", 370 AllowedType: ns.AllowedPublicNamespace("foo"), 371 }, 372 { 373 Type: RelationAllowedTypeAdded, 374 RelationName: "somerel", 375 AllowedType: ns.AllowedPublicNamespace("foo2"), 376 }, 377 }, 378 }, 379 { 380 "wildcard type changed", 381 ns.Namespace( 382 "document", 383 ns.MustRelation("somerel", ns.Union( 384 ns.ComputedUserset("owner"), 385 ), ns.AllowedPublicNamespace("foo")), 386 ), 387 ns.Namespace( 388 "document", 389 ns.MustRelation("somerel", ns.Union( 390 ns.ComputedUserset("owner"), 391 ), ns.AllowedRelation("foo", "something")), 392 ), 393 []Delta{ 394 { 395 Type: RelationAllowedTypeRemoved, 396 RelationName: "somerel", 397 AllowedType: ns.AllowedPublicNamespace("foo"), 398 }, 399 { 400 Type: RelationAllowedTypeAdded, 401 RelationName: "somerel", 402 AllowedType: ns.AllowedRelation("foo", "something"), 403 }, 404 }, 405 }, 406 { 407 "wildcard type changed no rewrite", 408 ns.Namespace( 409 "document", 410 ns.MustRelation("somerel", nil, ns.AllowedPublicNamespace("user")), 411 ), 412 ns.Namespace( 413 "document", 414 ns.MustRelation("somerel", nil, ns.AllowedRelation("organization", "user")), 415 ), 416 []Delta{ 417 { 418 Type: RelationAllowedTypeRemoved, 419 RelationName: "somerel", 420 AllowedType: ns.AllowedPublicNamespace("user"), 421 }, 422 { 423 Type: RelationAllowedTypeAdded, 424 RelationName: "somerel", 425 AllowedType: ns.AllowedRelation("organization", "user"), 426 }, 427 }, 428 }, 429 { 430 "added relation and removed permission with same name", 431 ns.Namespace( 432 "document", 433 ns.MustRelation("somerel", ns.Union(ns.ComputedUserset("someotherrel"))), 434 ), 435 ns.Namespace( 436 "document", 437 ns.MustRelation("somerel", nil), 438 ), 439 []Delta{ 440 {Type: AddedRelation, RelationName: "somerel"}, 441 {Type: RemovedPermission, RelationName: "somerel"}, 442 }, 443 }, 444 { 445 "added permission and removed relation with same name", 446 ns.Namespace( 447 "document", 448 ns.MustRelation("somerel", nil), 449 ), 450 ns.Namespace( 451 "document", 452 ns.MustRelation("somerel", ns.Union(ns.ComputedUserset("someotherrel"))), 453 ), 454 []Delta{ 455 {Type: RemovedRelation, RelationName: "somerel"}, 456 {Type: AddedPermission, RelationName: "somerel"}, 457 }, 458 }, 459 { 460 "added required caveat type", 461 ns.Namespace( 462 "document", 463 ns.MustRelation("somerel", nil, ns.AllowedRelation("user", "...")), 464 ), 465 ns.Namespace( 466 "document", 467 ns.MustRelation("somerel", nil, ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat"))), 468 ), 469 []Delta{ 470 { 471 Type: RelationAllowedTypeRemoved, 472 RelationName: "somerel", 473 AllowedType: ns.AllowedRelation("user", "..."), 474 }, 475 { 476 Type: RelationAllowedTypeAdded, 477 RelationName: "somerel", 478 AllowedType: ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat")), 479 }, 480 }, 481 }, 482 { 483 "added optional caveat type", 484 ns.Namespace( 485 "document", 486 ns.MustRelation("somerel", nil, ns.AllowedRelation("user", "...")), 487 ), 488 ns.Namespace( 489 "document", 490 ns.MustRelation("somerel", nil, ns.AllowedRelation("user", "..."), ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat"))), 491 ), 492 []Delta{ 493 { 494 Type: RelationAllowedTypeAdded, 495 RelationName: "somerel", 496 AllowedType: ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat")), 497 }, 498 }, 499 }, 500 { 501 "changed required caveat type", 502 ns.Namespace( 503 "document", 504 ns.MustRelation("somerel", nil, ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat"))), 505 ), 506 ns.Namespace( 507 "document", 508 ns.MustRelation("somerel", nil, ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("anothercaveat"))), 509 ), 510 []Delta{ 511 { 512 Type: RelationAllowedTypeRemoved, 513 RelationName: "somerel", 514 AllowedType: ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat")), 515 }, 516 { 517 Type: RelationAllowedTypeAdded, 518 RelationName: "somerel", 519 AllowedType: ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("anothercaveat")), 520 }, 521 }, 522 }, 523 { 524 "removed required caveat type", 525 ns.Namespace( 526 "document", 527 ns.MustRelation("somerel", nil, ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat"))), 528 ), 529 ns.Namespace( 530 "document", 531 ns.MustRelation("somerel", nil), 532 ), 533 []Delta{ 534 { 535 Type: RelationAllowedTypeRemoved, 536 RelationName: "somerel", 537 AllowedType: ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat")), 538 }, 539 }, 540 }, 541 { 542 "change required caveat type to optional", 543 ns.Namespace( 544 "document", 545 ns.MustRelation("somerel", nil, ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat"))), 546 ), 547 ns.Namespace( 548 "document", 549 ns.MustRelation("somerel", nil, ns.AllowedRelation("user", "..."), ns.AllowedRelationWithCaveat("user", "...", ns.AllowedCaveat("somecaveat"))), 550 ), 551 []Delta{ 552 { 553 Type: RelationAllowedTypeAdded, 554 RelationName: "somerel", 555 AllowedType: ns.AllowedRelation("user", "..."), 556 }, 557 }, 558 }, 559 { 560 "location change does not cause expression change", 561 ns.Namespace( 562 "document", 563 ns.MustRelation("somerel", ns.Union( 564 ns.MustComputesUsersetWithSourcePosition("editor", 1), 565 )), 566 ), 567 ns.Namespace( 568 "document", 569 ns.MustRelation("somerel", ns.Union( 570 ns.MustComputesUsersetWithSourcePosition("editor", 2), 571 )), 572 ), 573 []Delta{}, 574 }, 575 } 576 577 for _, tc := range testCases { 578 tc := tc 579 t.Run(tc.name, func(t *testing.T) { 580 require := require.New(t) 581 diff, err := DiffNamespaces(tc.existing, tc.updated) 582 require.Nil(err) 583 require.Equal(tc.expectedDeltas, diff.Deltas()) 584 }) 585 } 586 }