1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: Apache-2.0
10 check "gopkg.in/check.v1"
13 type VocabularySuite struct {
17 var _ = check.Suite(&VocabularySuite{})
19 func (s *VocabularySuite) SetUpTest(c *check.C) {
20 s.testVoc = &Vocabulary{
21 reservedTagKeys: map[string]bool{
25 Tags: map[string]VocabularyTag{
28 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
29 Values: map[string]VocabularyTagValue{
31 Labels: []VocabularyLabel{{Label: "Human"}, {Label: "Homo sapiens"}},
34 Labels: []VocabularyLabel{{Label: "Elephant"}, {Label: "Loxodonta"}},
40 Labels: []VocabularyLabel{{Label: "Importance"}, {Label: "Priority"}},
41 Values: map[string]VocabularyTagValue{
43 Labels: []VocabularyLabel{{Label: "Low"}, {Label: "Low priority"}},
46 Labels: []VocabularyLabel{{Label: "Medium"}, {Label: "Medium priority"}},
49 Labels: []VocabularyLabel{{Label: "High"}, {Label: "High priority"}},
55 Labels: []VocabularyLabel{{Label: "Comment"}},
59 err := s.testVoc.validate()
60 c.Assert(err, check.IsNil)
63 func (s *VocabularySuite) TestCheck(c *check.C) {
71 {"Known key, known value", false, `{"IDTAGANIMALS":"IDVALANIMAL1"}`, true},
72 {"Unknown non-alias key on non-strict vocabulary", false, `{"foo":"bar"}`, true},
73 {"Known non-strict key, unknown non-alias value", false, `{"IDTAGANIMALS":"IDVALANIMAL3"}`, true},
74 {"Undefined but reserved key on strict vocabulary", true, `{"reservedKey":"bar"}`, true},
75 {"Known key, list of known values", false, `{"IDTAGANIMALS":["IDVALANIMAL1","IDVALANIMAL2"]}`, true},
76 {"Known non-strict key, list of unknown non-alias values", false, `{"IDTAGCOMMENT":["hello world","lorem ipsum"]}`, true},
78 {"Known first key & value; known 2nd key, unknown 2nd value", false, `{"IDTAGANIMALS":"IDVALANIMAL1", "IDTAGIMPORTANCE": "blah blah"}`, false},
79 {"Unknown non-alias key on strict vocabulary", true, `{"foo":"bar"}`, false},
80 {"Known non-strict key, known value alias", false, `{"IDTAGANIMALS":"Loxodonta"}`, false},
81 {"Known strict key, unknown non-alias value", false, `{"IDTAGIMPORTANCE":"Unimportant"}`, false},
82 {"Known strict key, known value alias", false, `{"IDTAGIMPORTANCE":"High"}`, false},
83 {"Known strict key, list of known alias values", false, `{"IDTAGIMPORTANCE":["Unimportant","High"]}`, false},
84 {"Known strict key, list of unknown non-alias values", false, `{"IDTAGIMPORTANCE":["foo","bar"]}`, false},
86 for _, tt := range tests {
87 c.Log(c.TestName()+" ", tt.name)
88 s.testVoc.StrictTags = tt.strictVoc
90 var data map[string]interface{}
91 err := json.Unmarshal([]byte(tt.props), &data)
92 c.Assert(err, check.IsNil)
93 err = s.testVoc.Check(data)
95 c.Assert(err, check.IsNil)
97 c.Assert(err, check.NotNil)
102 func (s *VocabularySuite) TestNewVocabulary(c *check.C) {
110 {"Empty data", "", true, "", &Vocabulary{}},
111 {"Invalid JSON", "foo", false, "invalid JSON format.*", nil},
112 {"Valid, empty JSON", "{}", false, ".*doesn't match Vocabulary format.*", nil},
113 {"Valid JSON, wrong data", `{"foo":"bar"}`, false, ".*doesn't match Vocabulary format.*", nil},
115 "Simple valid example",
119 "labels": [{"label": "Animal"}, {"label": "Creature"}],
121 "IDVALANIMAL1":{"labels":[{"label":"Human"}, {"label":"Homo sapiens"}]},
122 "IDVALANIMAL2":{"labels":[{"label":"Elephant"}, {"label":"Loxodonta"}]}
128 reservedTagKeys: map[string]bool{
130 "template_uuid": true,
133 "image_timestamp": true,
134 "docker-image-repo-tag": true,
136 "container_request": true,
139 Tags: map[string]VocabularyTag{
142 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
143 Values: map[string]VocabularyTagValue{
145 Labels: []VocabularyLabel{{Label: "Human"}, {Label: "Homo sapiens"}},
148 Labels: []VocabularyLabel{{Label: "Elephant"}, {Label: "Loxodonta"}},
156 "Valid data, but uses reserved key",
160 "labels": [{"label": "Type"}]
163 false, "tag key.*is reserved", nil,
167 for _, tt := range tests {
168 c.Log(c.TestName()+" ", tt.name)
169 voc, err := NewVocabulary([]byte(tt.data), []string{})
171 c.Assert(err, check.IsNil)
173 c.Assert(err, check.NotNil)
174 if tt.errMatches != "" {
175 c.Assert(err, check.ErrorMatches, tt.errMatches)
178 c.Assert(voc, check.DeepEquals, tt.expect)
182 func (s *VocabularySuite) TestValidationErrors(c *check.C) {
189 "Strict vocabulary, no keys",
193 "vocabulary is strict but no tags are defined",
196 "Collision between tag key and tag key label",
199 Tags: map[string]VocabularyTag{
202 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
206 Labels: []VocabularyLabel{{Label: "Comment"}, {Label: "IDTAGANIMALS"}},
210 "", // Depending on how the map is sorted, this could be one of two errors
213 "Collision between tag key and tag key label (case-insensitive)",
216 Tags: map[string]VocabularyTag{
219 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
223 Labels: []VocabularyLabel{{Label: "Comment"}, {Label: "IdTagAnimals"}},
227 "", // Depending on how the map is sorted, this could be one of two errors
230 "Collision between tag key labels",
233 Tags: map[string]VocabularyTag{
236 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
240 Labels: []VocabularyLabel{{Label: "Comment"}, {Label: "Animal"}},
244 "tag label.*for key.*already seen.*",
247 "Collision between tag value and tag value label",
250 Tags: map[string]VocabularyTag{
253 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
254 Values: map[string]VocabularyTagValue{
256 Labels: []VocabularyLabel{{Label: "Human"}, {Label: "Mammal"}},
259 Labels: []VocabularyLabel{{Label: "Elephant"}, {Label: "IDVALANIMAL1"}},
265 "", // Depending on how the map is sorted, this could be one of two errors
268 "Collision between tag value and tag value label (case-insensitive)",
271 Tags: map[string]VocabularyTag{
274 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
275 Values: map[string]VocabularyTagValue{
277 Labels: []VocabularyLabel{{Label: "Human"}, {Label: "Mammal"}},
280 Labels: []VocabularyLabel{{Label: "Elephant"}, {Label: "IDValAnimal1"}},
286 "", // Depending on how the map is sorted, this could be one of two errors
289 "Collision between tag value labels",
292 Tags: map[string]VocabularyTag{
295 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
296 Values: map[string]VocabularyTagValue{
298 Labels: []VocabularyLabel{{Label: "Human"}, {Label: "Mammal"}},
301 Labels: []VocabularyLabel{{Label: "Elephant"}, {Label: "Mammal"}},
307 "tag value label.*for pair.*already seen.*",
310 "Strict tag key, with no values",
313 Tags: map[string]VocabularyTag{
316 Labels: []VocabularyLabel{{Label: "Animal"}, {Label: "Creature"}},
320 "tag key.*is configured as strict but doesn't provide values",
323 for _, tt := range tests {
324 c.Log(c.TestName()+" ", tt.name)
325 err := tt.voc.validate()
326 c.Assert(err, check.NotNil)
327 if tt.errMatches != "" {
328 c.Assert(err, check.ErrorMatches, tt.errMatches)