From 6b5bcf8d66ad28a0f1e492409c47adac9159e5d1 Mon Sep 17 00:00:00 2001 From: Andrew Phelps Date: Mon, 23 Sep 2024 12:30:44 -0400 Subject: [PATCH] a/snapasserts: add tests for validation set conflicts due to components Also, made the error strings for components contain the full identifier that includes both the snap and component names. --- asserts/snapasserts/validation_sets.go | 4 +- asserts/snapasserts/validation_sets_test.go | 177 ++++++++++++++++++++ 2 files changed, 180 insertions(+), 1 deletion(-) diff --git a/asserts/snapasserts/validation_sets.go b/asserts/snapasserts/validation_sets.go index a98e4ebf602..06a6691385a 100644 --- a/asserts/snapasserts/validation_sets.go +++ b/asserts/snapasserts/validation_sets.go @@ -376,12 +376,14 @@ func constraintsConflicts(c constraints) *conflictsError { } containerType := "snap" + name := c.name if c.compRef != nil { containerType = "component" + name = c.compRef.String() } return &conflictsError{ - name: c.name, + name: name, containerType: containerType, revisions: byRev, } diff --git a/asserts/snapasserts/validation_sets_test.go b/asserts/snapasserts/validation_sets_test.go index 41c10434cfa..dee3b476e1a 100644 --- a/asserts/snapasserts/validation_sets_test.go +++ b/asserts/snapasserts/validation_sets_test.go @@ -25,6 +25,7 @@ import ( "math/rand" "sort" "strconv" + "strings" . "gopkg.in/check.v1" @@ -1710,6 +1711,182 @@ func (s *validationSetsSuite) TestRevisionsConflict(c *C) { c.Assert(err, testutil.ErrorIs, &snapasserts.ValidationSetsConflictError{}) } +func (s *validationSetsSuite) TestComponentConflicts(c *C) { + type test struct { + summary string + sets []*asserts.ValidationSet + message string + } + + cases := []test{{ + summary: "component revision conflict", + sets: []*asserts.ValidationSet{assertstest.FakeAssertion( + map[string]interface{}{ + "type": "validation-set", + "authority-id": "account-id", + "series": "16", + "account-id": "account-id", + "name": "one", + "sequence": "1", + "snaps": []interface{}{ + map[string]interface{}{ + "name": "snap-a", + "id": snaptest.AssertedSnapID("snap-a"), + "presence": "required", + "revision": "10", + "components": map[string]interface{}{ + "comp-2": map[string]interface{}{ + "presence": "optional", + "revision": "3", + }, + }, + }, + }, + }).(*asserts.ValidationSet), assertstest.FakeAssertion( + map[string]interface{}{ + "type": "validation-set", + "authority-id": "account-id", + "series": "16", + "account-id": "account-id", + "name": "two", + "sequence": "1", + "snaps": []interface{}{ + map[string]interface{}{ + "name": "snap-a", + "id": snaptest.AssertedSnapID("snap-a"), + "presence": "required", + "revision": "10", + "components": map[string]interface{}{ + "comp-2": map[string]interface{}{ + "presence": "required", + "revision": "2", + }, + }, + }, + }, + }).(*asserts.ValidationSet), + }, + message: `cannot constrain component "snap-a+comp-2" at different revisions 2 (account-id/two), 3 (account-id/one)`, + }, { + summary: "component presence conflict", + sets: []*asserts.ValidationSet{assertstest.FakeAssertion( + map[string]interface{}{ + "type": "validation-set", + "authority-id": "account-id", + "series": "16", + "account-id": "account-id", + "name": "one", + "sequence": "1", + "snaps": []interface{}{ + map[string]interface{}{ + "name": "snap-a", + "id": snaptest.AssertedSnapID("snap-a"), + "presence": "optional", + "components": map[string]interface{}{ + "comp-2": map[string]interface{}{ + "presence": "invalid", + }, + }, + }, + }, + }).(*asserts.ValidationSet), assertstest.FakeAssertion( + map[string]interface{}{ + "type": "validation-set", + "authority-id": "account-id", + "series": "16", + "account-id": "account-id", + "name": "two", + "sequence": "1", + "snaps": []interface{}{ + map[string]interface{}{ + "name": "snap-a", + "id": snaptest.AssertedSnapID("snap-a"), + "presence": "optional", + "components": map[string]interface{}{ + "comp-2": map[string]interface{}{ + "presence": "required", + }, + }, + }, + }, + }).(*asserts.ValidationSet), + }, + message: `cannot constrain component "snap-a+comp-2" as both invalid (account-id/one) and required at any revision (account-id/two)`, + }, { + summary: "component presence conflict and snap presence conflict", + sets: []*asserts.ValidationSet{assertstest.FakeAssertion( + map[string]interface{}{ + "type": "validation-set", + "authority-id": "account-id", + "series": "16", + "account-id": "account-id", + "name": "one", + "sequence": "1", + "snaps": []interface{}{ + map[string]interface{}{ + "name": "snap-a", + "id": snaptest.AssertedSnapID("snap-a"), + "presence": "required", + "components": map[string]interface{}{ + "comp-2": map[string]interface{}{ + "presence": "invalid", + }, + }, + }, + }, + }).(*asserts.ValidationSet), assertstest.FakeAssertion( + map[string]interface{}{ + "type": "validation-set", + "authority-id": "account-id", + "series": "16", + "account-id": "account-id", + "name": "two", + "sequence": "1", + "snaps": []interface{}{ + map[string]interface{}{ + "name": "snap-a", + "id": snaptest.AssertedSnapID("snap-a"), + "presence": "optional", + "components": map[string]interface{}{ + "comp-2": map[string]interface{}{ + "presence": "required", + }, + }, + }, + }, + }).(*asserts.ValidationSet), assertstest.FakeAssertion( + map[string]interface{}{ + "type": "validation-set", + "authority-id": "account-id", + "series": "16", + "account-id": "account-id", + "name": "three", + "sequence": "1", + "snaps": []interface{}{ + map[string]interface{}{ + "name": "snap-a", + "id": snaptest.AssertedSnapID("snap-a"), + "presence": "invalid", + }, + }, + }).(*asserts.ValidationSet), + }, + message: `cannot constrain component "snap-a+comp-2" as both invalid (account-id/one) and required at any revision (account-id/two)`, + }} + + for _, tc := range cases { + prefix := fmt.Sprintf("test case: %s", tc.summary) + + valsets := snapasserts.NewValidationSets() + for _, set := range tc.sets { + c.Check(valsets.Add(set), IsNil, Commentf(prefix)) + } + + err := valsets.Conflict() + c.Check(strings.Count(err.Error(), tc.message), Equals, 1, Commentf(prefix)) + } +} + func (s *validationSetsSuite) TestValidationSetsConflictErrorIs(c *C) { err := &snapasserts.ValidationSetsConflictError{}