github.com/david-imola/snapd@v0.0.0-20210611180407-2de8ddeece6d/asserts/snapasserts/validation_sets_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package snapasserts_test 21 22 import ( 23 "fmt" 24 "sort" 25 26 . "gopkg.in/check.v1" 27 28 "github.com/snapcore/snapd/asserts" 29 "github.com/snapcore/snapd/asserts/assertstest" 30 "github.com/snapcore/snapd/asserts/snapasserts" 31 "github.com/snapcore/snapd/snap" 32 ) 33 34 type validationSetsSuite struct{} 35 36 var _ = Suite(&validationSetsSuite{}) 37 38 func (s *validationSetsSuite) TestAddFromSameSequence(c *C) { 39 mySnapAt7Valset := assertstest.FakeAssertion(map[string]interface{}{ 40 "type": "validation-set", 41 "authority-id": "account-id", 42 "series": "16", 43 "account-id": "account-id", 44 "name": "my-snap-ctl", 45 "sequence": "1", 46 "snaps": []interface{}{ 47 map[string]interface{}{ 48 "name": "my-snap", 49 "id": "mysnapididididididididididididid", 50 "presence": "required", 51 "revision": "7", 52 }, 53 }, 54 }).(*asserts.ValidationSet) 55 56 mySnapAt8Valset := assertstest.FakeAssertion(map[string]interface{}{ 57 "type": "validation-set", 58 "authority-id": "account-id", 59 "series": "16", 60 "account-id": "account-id", 61 "name": "my-snap-ctl", 62 "sequence": "2", 63 "snaps": []interface{}{ 64 map[string]interface{}{ 65 "name": "my-snap", 66 "id": "mysnapididididididididididididid", 67 "presence": "required", 68 "revision": "8", 69 }, 70 }, 71 }).(*asserts.ValidationSet) 72 73 valsets := snapasserts.NewValidationSets() 74 err := valsets.Add(mySnapAt7Valset) 75 c.Assert(err, IsNil) 76 err = valsets.Add(mySnapAt8Valset) 77 c.Check(err, ErrorMatches, `cannot add a second validation-set under "account-id/my-snap-ctl"`) 78 } 79 80 func (s *validationSetsSuite) TestIntersections(c *C) { 81 mySnapAt7Valset := assertstest.FakeAssertion(map[string]interface{}{ 82 "type": "validation-set", 83 "authority-id": "account-id", 84 "series": "16", 85 "account-id": "account-id", 86 "name": "my-snap-ctl", 87 "sequence": "1", 88 "snaps": []interface{}{ 89 map[string]interface{}{ 90 "name": "my-snap", 91 "id": "mysnapididididididididididididid", 92 "presence": "required", 93 "revision": "7", 94 }, 95 }, 96 }).(*asserts.ValidationSet) 97 98 mySnapAt7Valset2 := assertstest.FakeAssertion(map[string]interface{}{ 99 "type": "validation-set", 100 "authority-id": "account-id", 101 "series": "16", 102 "account-id": "account-id", 103 "name": "my-snap-ctl2", 104 "sequence": "2", 105 "snaps": []interface{}{ 106 map[string]interface{}{ 107 "name": "my-snap", 108 "id": "mysnapididididididididididididid", 109 "presence": "required", 110 "revision": "7", 111 }, 112 }, 113 }).(*asserts.ValidationSet) 114 115 mySnapAt8Valset := assertstest.FakeAssertion(map[string]interface{}{ 116 "type": "validation-set", 117 "authority-id": "account-id", 118 "series": "16", 119 "account-id": "account-id", 120 "name": "my-snap-ctl-other", 121 "sequence": "1", 122 "snaps": []interface{}{ 123 map[string]interface{}{ 124 "name": "my-snap", 125 "id": "mysnapididididididididididididid", 126 "presence": "required", 127 "revision": "8", 128 }, 129 }, 130 }).(*asserts.ValidationSet) 131 132 mySnapAt8OptValset := assertstest.FakeAssertion(map[string]interface{}{ 133 "type": "validation-set", 134 "authority-id": "account-id", 135 "series": "16", 136 "account-id": "account-id", 137 "name": "my-snap-ctl-opt", 138 "sequence": "1", 139 "snaps": []interface{}{ 140 map[string]interface{}{ 141 "name": "my-snap", 142 "id": "mysnapididididididididididididid", 143 "presence": "optional", 144 "revision": "8", 145 }, 146 }, 147 }).(*asserts.ValidationSet) 148 149 mySnapInvalidValset := assertstest.FakeAssertion(map[string]interface{}{ 150 "type": "validation-set", 151 "authority-id": "account-id", 152 "series": "16", 153 "account-id": "account-id", 154 "name": "my-snap-ctl-inv", 155 "sequence": "1", 156 "snaps": []interface{}{ 157 map[string]interface{}{ 158 "name": "my-snap", 159 "id": "mysnapididididididididididididid", 160 "presence": "invalid", 161 }, 162 }, 163 }).(*asserts.ValidationSet) 164 165 mySnapAt7OptValset := assertstest.FakeAssertion(map[string]interface{}{ 166 "type": "validation-set", 167 "authority-id": "account-id", 168 "series": "16", 169 "account-id": "account-id", 170 "name": "my-snap-ctl-opt2", 171 "sequence": "1", 172 "snaps": []interface{}{ 173 map[string]interface{}{ 174 "name": "my-snap", 175 "id": "mysnapididididididididididididid", 176 "presence": "optional", 177 "revision": "7", 178 }, 179 }, 180 }).(*asserts.ValidationSet) 181 182 mySnapReqValset := assertstest.FakeAssertion(map[string]interface{}{ 183 "type": "validation-set", 184 "authority-id": "account-id", 185 "series": "16", 186 "account-id": "account-id", 187 "name": "my-snap-ctl-req-only", 188 "sequence": "1", 189 "snaps": []interface{}{ 190 map[string]interface{}{ 191 "name": "my-snap", 192 "id": "mysnapididididididididididididid", 193 "presence": "required", 194 }, 195 }, 196 }).(*asserts.ValidationSet) 197 198 mySnapOptValset := assertstest.FakeAssertion(map[string]interface{}{ 199 "type": "validation-set", 200 "authority-id": "account-id", 201 "series": "16", 202 "account-id": "account-id", 203 "name": "my-snap-ctl-opt-only", 204 "sequence": "1", 205 "snaps": []interface{}{ 206 map[string]interface{}{ 207 "name": "my-snap", 208 "id": "mysnapididididididididididididid", 209 "presence": "optional", 210 }, 211 }, 212 }).(*asserts.ValidationSet) 213 214 tests := []struct { 215 sets []*asserts.ValidationSet 216 conflictErr string 217 }{ 218 {[]*asserts.ValidationSet{mySnapAt7Valset}, ""}, 219 {[]*asserts.ValidationSet{mySnapAt7Valset, mySnapAt7Valset2}, ""}, 220 {[]*asserts.ValidationSet{mySnapAt7Valset, mySnapAt8Valset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" at different revisions 7 \(account-id/my-snap-ctl\), 8 \(account-id/my-snap-ctl-other\)`}, 221 {[]*asserts.ValidationSet{mySnapAt8Valset, mySnapAt8OptValset}, ""}, 222 {[]*asserts.ValidationSet{mySnapAt7Valset, mySnapAt8OptValset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" at different revisions 7 \(account-id/my-snap-ctl\), 8 \(account-id/my-snap-ctl-opt\)`}, 223 {[]*asserts.ValidationSet{mySnapAt7Valset, mySnapInvalidValset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" as both invalid \(account-id/my-snap-ctl-inv\) and required at revision 7 \(account-id/my-snap-ctl\)`}, 224 {[]*asserts.ValidationSet{mySnapInvalidValset, mySnapAt7Valset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" as both invalid \(account-id/my-snap-ctl-inv\) and required at revision 7 \(account-id/my-snap-ctl\)`}, 225 {[]*asserts.ValidationSet{mySnapAt8OptValset, mySnapInvalidValset}, ""}, 226 {[]*asserts.ValidationSet{mySnapInvalidValset, mySnapAt8OptValset}, ""}, 227 {[]*asserts.ValidationSet{mySnapAt7OptValset, mySnapAt8OptValset}, ""}, // no conflict but interpreted as invalid 228 {[]*asserts.ValidationSet{mySnapAt7OptValset, mySnapAt8OptValset, mySnapAt7Valset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" at different revisions 7 \(account-id/my-snap-ctl,account-id/my-snap-ctl-opt2\), 8 \(account-id/my-snap-ctl-opt\)`}, 229 {[]*asserts.ValidationSet{mySnapAt8OptValset, mySnapInvalidValset, mySnapAt7Valset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" as both invalid \(account-id/my-snap-ctl-inv\) and required at different revisions 7 \(account-id/my-snap-ctl\), 8 \(account-id/my-snap-ctl-opt\)`}, 230 {[]*asserts.ValidationSet{mySnapAt7Valset, mySnapReqValset}, ""}, 231 {[]*asserts.ValidationSet{mySnapReqValset, mySnapAt7Valset}, ""}, 232 {[]*asserts.ValidationSet{mySnapAt8OptValset, mySnapReqValset}, ""}, 233 {[]*asserts.ValidationSet{mySnapAt8OptValset, mySnapReqValset, mySnapAt7OptValset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" at different revisions 7 \(account-id/my-snap-ctl-opt2\), 8 \(account-id/my-snap-ctl-opt\) or required at any revision \(account-id/my-snap-ctl-req-only\)`}, 234 {[]*asserts.ValidationSet{mySnapAt8OptValset, mySnapAt7OptValset, mySnapReqValset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" at different revisions 7 \(account-id/my-snap-ctl-opt2\), 8 \(account-id/my-snap-ctl-opt\) or required at any revision \(account-id/my-snap-ctl-req-only\)`}, 235 {[]*asserts.ValidationSet{mySnapReqValset, mySnapInvalidValset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" as both invalid \(account-id/my-snap-ctl-inv\) and required at any revision \(account-id/my-snap-ctl-req-only\)`}, 236 {[]*asserts.ValidationSet{mySnapInvalidValset, mySnapReqValset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" as both invalid \(account-id/my-snap-ctl-inv\) and required at any revision \(account-id/my-snap-ctl-req-only\)`}, 237 {[]*asserts.ValidationSet{mySnapAt7Valset, mySnapAt8Valset, mySnapOptValset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" at different revisions 7 \(account-id/my-snap-ctl\), 8 \(account-id/my-snap-ctl-other\)`}, 238 {[]*asserts.ValidationSet{mySnapAt7Valset, mySnapOptValset}, ""}, 239 {[]*asserts.ValidationSet{mySnapOptValset, mySnapAt7Valset}, ""}, 240 {[]*asserts.ValidationSet{mySnapAt8OptValset, mySnapOptValset}, ""}, 241 {[]*asserts.ValidationSet{mySnapAt8OptValset, mySnapOptValset, mySnapAt7OptValset}, ""}, // no conflict but interpreted as invalid 242 {[]*asserts.ValidationSet{mySnapInvalidValset, mySnapOptValset}, ""}, 243 {[]*asserts.ValidationSet{mySnapOptValset, mySnapInvalidValset}, ""}, 244 {[]*asserts.ValidationSet{mySnapAt7Valset, mySnapAt8Valset, mySnapReqValset, mySnapInvalidValset}, `(?ms)validation sets are in conflict:.*cannot constrain snap "my-snap" as both invalid \(account-id/my-snap-ctl-inv\) and required at different revisions 7 \(account-id/my-snap-ctl\), 8 \(account-id/my-snap-ctl-other\) or at any revision \(account-id/my-snap-ctl-req-only\)`}, 245 } 246 247 for _, t := range tests { 248 valsets := snapasserts.NewValidationSets() 249 cSets := make(map[string]*asserts.ValidationSet) 250 for _, valset := range t.sets { 251 err := valsets.Add(valset) 252 c.Assert(err, IsNil) 253 // mySnapOptValset never influcens an outcome 254 if valset != mySnapOptValset { 255 cSets[fmt.Sprintf("%s/%s", valset.AccountID(), valset.Name())] = valset 256 } 257 } 258 err := valsets.Conflict() 259 if t.conflictErr == "" { 260 c.Check(err, IsNil) 261 } else { 262 c.Check(err, ErrorMatches, t.conflictErr) 263 ce := err.(*snapasserts.ValidationSetsConflictError) 264 c.Check(ce.Sets, DeepEquals, cSets) 265 } 266 } 267 } 268 269 func (s *validationSetsSuite) TestCheckInstalledSnapsNoValidationSets(c *C) { 270 valsets := snapasserts.NewValidationSets() 271 snaps := []*snapasserts.InstalledSnap{ 272 snapasserts.NewInstalledSnap("snap-a", "mysnapaaaaaaaaaaaaaaaaaaaaaaaaaa", snap.R(1)), 273 } 274 err := valsets.CheckInstalledSnaps(snaps) 275 c.Assert(err, IsNil) 276 } 277 278 func (s *validationSetsSuite) TestCheckInstalledSnaps(c *C) { 279 // require: snapB rev 3, snapC rev 2. 280 // invalid: snapA 281 vs1 := assertstest.FakeAssertion(map[string]interface{}{ 282 "type": "validation-set", 283 "authority-id": "acme", 284 "series": "16", 285 "account-id": "acme", 286 "name": "fooname", 287 "sequence": "1", 288 "snaps": []interface{}{ 289 map[string]interface{}{ 290 "name": "snap-a", 291 "id": "mysnapaaaaaaaaaaaaaaaaaaaaaaaaaa", 292 "presence": "invalid", 293 }, 294 map[string]interface{}{ 295 "name": "snap-b", 296 "id": "mysnapbbbbbbbbbbbbbbbbbbbbbbbbbb", 297 "revision": "3", 298 "presence": "required", 299 }, 300 map[string]interface{}{ 301 "name": "snap-c", 302 "id": "mysnapcccccccccccccccccccccccccc", 303 "revision": "2", 304 "presence": "optional", 305 }, 306 }, 307 }).(*asserts.ValidationSet) 308 309 // require: snapD any rev 310 // optional: snapE any rev 311 vs2 := assertstest.FakeAssertion(map[string]interface{}{ 312 "type": "validation-set", 313 "authority-id": "acme", 314 "series": "16", 315 "account-id": "acme", 316 "name": "barname", 317 "sequence": "3", 318 "snaps": []interface{}{ 319 map[string]interface{}{ 320 "name": "snap-d", 321 "id": "mysnapdddddddddddddddddddddddddd", 322 "presence": "required", 323 }, 324 map[string]interface{}{ 325 "name": "snap-e", 326 "id": "mysnapeeeeeeeeeeeeeeeeeeeeeeeeee", 327 "presence": "optional", 328 }, 329 }, 330 }).(*asserts.ValidationSet) 331 332 // optional: snapE any rev 333 // note: since it only has an optional snap, acme/bazname is not expected 334 // not be invalid by any of the checks. 335 vs3 := assertstest.FakeAssertion(map[string]interface{}{ 336 "type": "validation-set", 337 "authority-id": "acme", 338 "series": "16", 339 "account-id": "acme", 340 "name": "bazname", 341 "sequence": "2", 342 "snaps": []interface{}{ 343 map[string]interface{}{ 344 "name": "snap-e", 345 "id": "mysnapeeeeeeeeeeeeeeeeeeeeeeeeee", 346 "presence": "optional", 347 }, 348 }, 349 }).(*asserts.ValidationSet) 350 351 // invalid: snapA 352 vs4 := assertstest.FakeAssertion(map[string]interface{}{ 353 "type": "validation-set", 354 "authority-id": "acme", 355 "series": "16", 356 "account-id": "acme", 357 "name": "booname", 358 "sequence": "1", 359 "snaps": []interface{}{ 360 map[string]interface{}{ 361 "name": "snap-a", 362 "id": "mysnapaaaaaaaaaaaaaaaaaaaaaaaaaa", 363 "presence": "invalid", 364 }, 365 }, 366 }).(*asserts.ValidationSet) 367 368 valsets := snapasserts.NewValidationSets() 369 c.Assert(valsets.Add(vs1), IsNil) 370 c.Assert(valsets.Add(vs2), IsNil) 371 c.Assert(valsets.Add(vs3), IsNil) 372 c.Assert(valsets.Add(vs4), IsNil) 373 374 snapA := snapasserts.NewInstalledSnap("snap-a", "mysnapaaaaaaaaaaaaaaaaaaaaaaaaaa", snap.R(1)) 375 snapAlocal := snapasserts.NewInstalledSnap("snap-a", "", snap.R("x2")) 376 snapB := snapasserts.NewInstalledSnap("snap-b", "mysnapbbbbbbbbbbbbbbbbbbbbbbbbbb", snap.R(3)) 377 snapBinvRev := snapasserts.NewInstalledSnap("snap-b", "mysnapbbbbbbbbbbbbbbbbbbbbbbbbbb", snap.R(8)) 378 snapBlocal := snapasserts.NewInstalledSnap("snap-b", "", snap.R("x3")) 379 snapC := snapasserts.NewInstalledSnap("snap-c", "mysnapcccccccccccccccccccccccccc", snap.R(2)) 380 snapCinvRev := snapasserts.NewInstalledSnap("snap-c", "mysnapcccccccccccccccccccccccccc", snap.R(99)) 381 snapD := snapasserts.NewInstalledSnap("snap-d", "mysnapdddddddddddddddddddddddddd", snap.R(2)) 382 snapDrev99 := snapasserts.NewInstalledSnap("snap-d", "mysnapdddddddddddddddddddddddddd", snap.R(99)) 383 snapDlocal := snapasserts.NewInstalledSnap("snap-d", "", snap.R("x3")) 384 snapE := snapasserts.NewInstalledSnap("snap-e", "mysnapeeeeeeeeeeeeeeeeeeeeeeeeee", snap.R(2)) 385 // extra snap, not referenced by any validation set 386 snapZ := snapasserts.NewInstalledSnap("snap-z", "mysnapzzzzzzzzzzzzzzzzzzzzzzzzzz", snap.R(1)) 387 388 tests := []struct { 389 snaps []*snapasserts.InstalledSnap 390 expectedInvalid map[string][]string 391 expectedMissing map[string][]string 392 expectedWrongRev map[string]map[snap.Revision][]string 393 }{ 394 { 395 // required snaps not installed 396 snaps: nil, 397 expectedMissing: map[string][]string{ 398 "snap-b": {"acme/fooname"}, 399 "snap-d": {"acme/barname"}, 400 }, 401 }, 402 { 403 // required snaps not installed 404 snaps: []*snapasserts.InstalledSnap{ 405 snapZ, 406 }, 407 expectedMissing: map[string][]string{ 408 "snap-b": {"acme/fooname"}, 409 "snap-d": {"acme/barname"}, 410 }, 411 }, 412 { 413 snaps: []*snapasserts.InstalledSnap{ 414 // covered by acme/fooname validation-set 415 snapB, 416 // covered by acme/barname validation-set. snap-e not installed but optional 417 snapDrev99}, 418 // ale fine 419 }, 420 { 421 snaps: []*snapasserts.InstalledSnap{ 422 // covered by acme/fooname validation-set and acme/booname, snap-a presence is invalid 423 snapA, 424 snapB, 425 // covered by acme/barname validation-set. snap-e not installed but optional 426 snapDrev99}, 427 expectedInvalid: map[string][]string{ 428 "snap-a": {"acme/booname", "acme/fooname"}, 429 }, 430 }, 431 { 432 snaps: []*snapasserts.InstalledSnap{ 433 // covered by acme/fooname and acme/booname validation-sets, snapB missing, snap-a presence is invalid 434 snapA, 435 // covered by acme/barname validation-set. snap-e not installed but optional 436 snapDrev99}, 437 expectedInvalid: map[string][]string{ 438 "snap-a": {"acme/booname", "acme/fooname"}, 439 }, 440 expectedMissing: map[string][]string{ 441 "snap-b": {"acme/fooname"}, 442 }, 443 }, 444 { 445 snaps: []*snapasserts.InstalledSnap{ 446 // covered by acme/fooname validation-set 447 snapB, 448 snapC, 449 // covered by acme/barname validation-set. snap-e not installed but optional 450 snapD}, 451 // ale fine 452 }, 453 { 454 snaps: []*snapasserts.InstalledSnap{ 455 // covered by acme/fooname validation-set, snap-c optional but wrong revision 456 snapB, 457 snapCinvRev, 458 // covered by acme/barname validation-set. snap-e not installed but optional 459 snapD}, 460 expectedWrongRev: map[string]map[snap.Revision][]string{ 461 "snap-c": { 462 snap.R(2): {"acme/fooname"}, 463 }, 464 }, 465 }, 466 { 467 snaps: []*snapasserts.InstalledSnap{ 468 // covered by acme/fooname validation-set but wrong revision 469 snapBinvRev, 470 // covered by acme/barname validation-set. 471 snapD}, 472 expectedWrongRev: map[string]map[snap.Revision][]string{ 473 "snap-b": { 474 snap.R(3): {"acme/fooname"}, 475 }, 476 }, 477 }, 478 { 479 snaps: []*snapasserts.InstalledSnap{ 480 // covered by acme/fooname validation-set 481 snapB, 482 // covered by acme/barname validation-set. snap-d not installed. 483 snapE}, 484 expectedMissing: map[string][]string{ 485 "snap-d": {"acme/barname"}, 486 }, 487 }, 488 { 489 snaps: []*snapasserts.InstalledSnap{ 490 // required snaps from acme/fooname are not installed. 491 // covered by acme/barname validation-set 492 snapDrev99, 493 snapE}, 494 expectedMissing: map[string][]string{ 495 "snap-b": {"acme/fooname"}, 496 }, 497 }, 498 { 499 snaps: []*snapasserts.InstalledSnap{ 500 // covered by acme/fooname validation-set, required missing. 501 snapC, 502 // covered by acme/barname validation-set, required missing. 503 snapE}, 504 expectedMissing: map[string][]string{ 505 "snap-b": {"acme/fooname"}, 506 "snap-d": {"acme/barname"}, 507 }, 508 }, 509 // local snaps 510 { 511 snaps: []*snapasserts.InstalledSnap{ 512 // covered by acme/fooname validation-set. 513 snapB, 514 // covered by acme/barname validation-set, local snap-d. 515 snapDlocal}, 516 // all fine 517 }, 518 { 519 snaps: []*snapasserts.InstalledSnap{ 520 // covered by acme/fooname validation-set, snap-a is invalid. 521 snapAlocal, 522 snapB, 523 // covered by acme/barname validation-set. 524 snapD}, 525 expectedInvalid: map[string][]string{ 526 "snap-a": {"acme/booname", "acme/fooname"}, 527 }, 528 }, 529 { 530 snaps: []*snapasserts.InstalledSnap{ 531 // covered by acme/fooname validation-set, snap-b is wrong rev (local). 532 snapBlocal, 533 // covered by acme/barname validation-set. 534 snapD}, 535 expectedWrongRev: map[string]map[snap.Revision][]string{ 536 "snap-b": { 537 snap.R(3): {"acme/fooname"}, 538 }, 539 }, 540 }, 541 } 542 543 checkSets := func(snapsToValidationSets map[string][]string, vs map[string]*asserts.ValidationSet) { 544 for _, vsetKeys := range snapsToValidationSets { 545 for _, key := range vsetKeys { 546 vset, ok := vs[key] 547 c.Assert(ok, Equals, true) 548 c.Assert(vset.AccountID()+"/"+vset.Name(), Equals, key) 549 } 550 } 551 } 552 553 for i, tc := range tests { 554 err := valsets.CheckInstalledSnaps(tc.snaps) 555 if err == nil { 556 c.Assert(tc.expectedInvalid, IsNil) 557 c.Assert(tc.expectedMissing, IsNil) 558 c.Assert(tc.expectedWrongRev, IsNil) 559 continue 560 } 561 verr, ok := err.(*snapasserts.ValidationSetsValidationError) 562 c.Assert(ok, Equals, true, Commentf("#%d", i)) 563 c.Assert(tc.expectedInvalid, DeepEquals, verr.InvalidSnaps, Commentf("#%d", i)) 564 c.Assert(tc.expectedMissing, DeepEquals, verr.MissingSnaps, Commentf("#%d", i)) 565 c.Assert(tc.expectedWrongRev, DeepEquals, verr.WrongRevisionSnaps, Commentf("#%d", i)) 566 checkSets(verr.InvalidSnaps, verr.Sets) 567 } 568 } 569 570 func (s *validationSetsSuite) TestCheckInstalledSnapsErrorFormat(c *C) { 571 vs1 := assertstest.FakeAssertion(map[string]interface{}{ 572 "type": "validation-set", 573 "authority-id": "acme", 574 "series": "16", 575 "account-id": "acme", 576 "name": "fooname", 577 "sequence": "1", 578 "snaps": []interface{}{ 579 map[string]interface{}{ 580 "name": "snap-a", 581 "id": "mysnapaaaaaaaaaaaaaaaaaaaaaaaaaa", 582 "presence": "invalid", 583 }, 584 map[string]interface{}{ 585 "name": "snap-b", 586 "id": "mysnapbbbbbbbbbbbbbbbbbbbbbbbbbb", 587 "revision": "3", 588 "presence": "required", 589 }, 590 }, 591 }).(*asserts.ValidationSet) 592 vs2 := assertstest.FakeAssertion(map[string]interface{}{ 593 "type": "validation-set", 594 "authority-id": "acme", 595 "series": "16", 596 "account-id": "acme", 597 "name": "barname", 598 "sequence": "2", 599 "snaps": []interface{}{ 600 map[string]interface{}{ 601 "name": "snap-b", 602 "id": "mysnapbbbbbbbbbbbbbbbbbbbbbbbbbb", 603 "revision": "5", 604 "presence": "required", 605 }, 606 }, 607 }).(*asserts.ValidationSet) 608 609 valsets := snapasserts.NewValidationSets() 610 c.Assert(valsets.Add(vs1), IsNil) 611 c.Assert(valsets.Add(vs2), IsNil) 612 613 snapA := snapasserts.NewInstalledSnap("snap-a", "mysnapaaaaaaaaaaaaaaaaaaaaaaaaaa", snap.R(1)) 614 snapBlocal := snapasserts.NewInstalledSnap("snap-b", "", snap.R("x3")) 615 616 tests := []struct { 617 snaps []*snapasserts.InstalledSnap 618 errorMsg string 619 }{ 620 { 621 nil, 622 "validation sets assertions are not met:\n" + 623 "- missing required snaps:\n" + 624 " - snap-b \\(required by sets acme/barname,acme/fooname\\)", 625 }, 626 { 627 []*snapasserts.InstalledSnap{snapA}, 628 "validation sets assertions are not met:\n" + 629 "- missing required snaps:\n" + 630 " - snap-b \\(required by sets acme/barname,acme/fooname\\)\n" + 631 "- invalid snaps:\n" + 632 " - snap-a \\(invalid for sets acme/fooname\\)", 633 }, 634 { 635 []*snapasserts.InstalledSnap{snapBlocal}, 636 "validation sets assertions are not met:\n" + 637 "- snaps at wrong revisions:\n" + 638 " - snap-b \\(required at revision 3 by sets acme/fooname, at revision 5 by sets acme/barname\\)", 639 }, 640 } 641 642 for i, tc := range tests { 643 err := valsets.CheckInstalledSnaps(tc.snaps) 644 c.Assert(err, NotNil, Commentf("#%d", i)) 645 c.Assert(err, ErrorMatches, tc.errorMsg, Commentf("#%d: ", i)) 646 } 647 } 648 649 func (s *validationSetsSuite) TestSortByRevision(c *C) { 650 revs := []snap.Revision{snap.R(10), snap.R(4), snap.R(5), snap.R(-1)} 651 652 sort.Sort(snapasserts.ByRevision(revs)) 653 c.Assert(revs, DeepEquals, []snap.Revision{snap.R(-1), snap.R(4), snap.R(5), snap.R(10)}) 654 }