github.com/anonymouse64/snapd@v0.0.0-20210824153203-04c4c42d842d/snap/info_snap_yaml_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2014-2021 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 snap_test 21 22 import ( 23 "fmt" 24 "regexp" 25 "testing" 26 "time" 27 28 . "gopkg.in/check.v1" 29 30 "github.com/snapcore/snapd/snap" 31 "github.com/snapcore/snapd/strutil" 32 "github.com/snapcore/snapd/testutil" 33 "github.com/snapcore/snapd/timeout" 34 ) 35 36 // Hook up check.v1 into the "go test" runner 37 func Test(t *testing.T) { TestingT(t) } 38 39 type InfoSnapYamlTestSuite struct { 40 testutil.BaseTest 41 } 42 43 var _ = Suite(&InfoSnapYamlTestSuite{}) 44 45 var mockYaml = []byte(`name: foo 46 version: 1.0 47 type: app 48 `) 49 50 func (s *InfoSnapYamlTestSuite) SetUpTest(c *C) { 51 s.BaseTest.SetUpTest(c) 52 s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) 53 } 54 55 func (s *InfoSnapYamlTestSuite) TearDownTest(c *C) { 56 s.BaseTest.TearDownTest(c) 57 } 58 59 func (s *InfoSnapYamlTestSuite) TestSimple(c *C) { 60 info, err := snap.InfoFromSnapYaml(mockYaml) 61 c.Assert(err, IsNil) 62 c.Assert(info.InstanceName(), Equals, "foo") 63 c.Assert(info.Version, Equals, "1.0") 64 c.Assert(info.Type(), Equals, snap.TypeApp) 65 c.Assert(info.Epoch, DeepEquals, snap.E("0")) 66 } 67 68 func (s *InfoSnapYamlTestSuite) TestSnapdTypeAddedByMagic(c *C) { 69 info, err := snap.InfoFromSnapYaml([]byte(`name: snapd 70 version: 1.0`)) 71 c.Assert(err, IsNil) 72 c.Assert(info.InstanceName(), Equals, "snapd") 73 c.Assert(info.Version, Equals, "1.0") 74 c.Assert(info.Type(), Equals, snap.TypeSnapd) 75 } 76 77 func (s *InfoSnapYamlTestSuite) TestFail(c *C) { 78 _, err := snap.InfoFromSnapYaml([]byte("random-crap")) 79 c.Assert(err, ErrorMatches, "(?m)cannot parse snap.yaml:.*") 80 } 81 82 type YamlSuite struct { 83 restore func() 84 testutil.BaseTest 85 } 86 87 var _ = Suite(&YamlSuite{}) 88 89 func (s *YamlSuite) SetUpTest(c *C) { 90 s.BaseTest.SetUpTest(c) 91 s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) 92 hookType := snap.NewHookType(regexp.MustCompile(".*")) 93 s.restore = snap.MockSupportedHookTypes([]*snap.HookType{hookType}) 94 } 95 96 func (s *YamlSuite) TearDownTest(c *C) { 97 s.BaseTest.TearDownTest(c) 98 s.restore() 99 } 100 101 func (s *YamlSuite) TestUnmarshalGarbage(c *C) { 102 _, err := snap.InfoFromSnapYaml([]byte(`"`)) 103 c.Assert(err, ErrorMatches, ".*: yaml: found unexpected end of stream") 104 } 105 106 func (s *YamlSuite) TestUnmarshalEmpty(c *C) { 107 info, err := snap.InfoFromSnapYaml([]byte(``)) 108 c.Assert(err, IsNil) 109 c.Assert(info.Plugs, HasLen, 0) 110 c.Assert(info.Slots, HasLen, 0) 111 c.Assert(info.Apps, HasLen, 0) 112 } 113 114 // Tests focusing on plugs 115 116 func (s *YamlSuite) TestUnmarshalStandaloneImplicitPlug(c *C) { 117 // NOTE: yaml content cannot use tabs, indent the section with spaces. 118 info, err := snap.InfoFromSnapYaml([]byte(` 119 name: snap 120 plugs: 121 network-client: 122 `)) 123 c.Assert(err, IsNil) 124 c.Check(info.InstanceName(), Equals, "snap") 125 c.Check(info.Plugs, HasLen, 1) 126 c.Check(info.Slots, HasLen, 0) 127 c.Assert(info.Plugs["network-client"], DeepEquals, &snap.PlugInfo{ 128 Snap: info, 129 Name: "network-client", 130 Interface: "network-client", 131 }) 132 } 133 134 func (s *YamlSuite) TestUnmarshalStandaloneAbbreviatedPlug(c *C) { 135 // NOTE: yaml content cannot use tabs, indent the section with spaces. 136 info, err := snap.InfoFromSnapYaml([]byte(` 137 name: snap 138 plugs: 139 net: network-client 140 `)) 141 c.Assert(err, IsNil) 142 c.Check(info.InstanceName(), Equals, "snap") 143 c.Check(info.Plugs, HasLen, 1) 144 c.Check(info.Slots, HasLen, 0) 145 c.Assert(info.Plugs["net"], DeepEquals, &snap.PlugInfo{ 146 Snap: info, 147 Name: "net", 148 Interface: "network-client", 149 }) 150 } 151 152 func (s *YamlSuite) TestUnmarshalStandaloneMinimalisticPlug(c *C) { 153 // NOTE: yaml content cannot use tabs, indent the section with spaces. 154 info, err := snap.InfoFromSnapYaml([]byte(` 155 name: snap 156 plugs: 157 net: 158 interface: network-client 159 `)) 160 c.Assert(err, IsNil) 161 c.Check(info.InstanceName(), Equals, "snap") 162 c.Check(info.Plugs, HasLen, 1) 163 c.Check(info.Slots, HasLen, 0) 164 c.Assert(info.Plugs["net"], DeepEquals, &snap.PlugInfo{ 165 Snap: info, 166 Name: "net", 167 Interface: "network-client", 168 }) 169 } 170 171 func (s *YamlSuite) TestUnmarshalStandaloneCompletePlug(c *C) { 172 // NOTE: yaml content cannot use tabs, indent the section with spaces. 173 info, err := snap.InfoFromSnapYaml([]byte(` 174 name: snap 175 plugs: 176 net: 177 interface: network-client 178 ipv6-aware: true 179 `)) 180 c.Assert(err, IsNil) 181 c.Check(info.InstanceName(), Equals, "snap") 182 c.Check(info.Plugs, HasLen, 1) 183 c.Check(info.Slots, HasLen, 0) 184 c.Assert(info.Plugs["net"], DeepEquals, &snap.PlugInfo{ 185 Snap: info, 186 Name: "net", 187 Interface: "network-client", 188 Attrs: map[string]interface{}{"ipv6-aware": true}, 189 }) 190 } 191 192 func (s *YamlSuite) TestUnmarshalStandalonePlugWithIntAndListAndMap(c *C) { 193 // NOTE: yaml content cannot use tabs, indent the section with spaces. 194 info, err := snap.InfoFromSnapYaml([]byte(` 195 name: snap 196 plugs: 197 iface: 198 interface: complex 199 i: 3 200 l: [1,2,3] 201 m: 202 a: A 203 b: B 204 `)) 205 c.Assert(err, IsNil) 206 c.Check(info.InstanceName(), Equals, "snap") 207 c.Check(info.Plugs, HasLen, 1) 208 c.Check(info.Slots, HasLen, 0) 209 c.Assert(info.Plugs["iface"], DeepEquals, &snap.PlugInfo{ 210 Snap: info, 211 Name: "iface", 212 Interface: "complex", 213 Attrs: map[string]interface{}{ 214 "i": int64(3), 215 "l": []interface{}{int64(1), int64(2), int64(3)}, 216 "m": map[string]interface{}{"a": "A", "b": "B"}, 217 }, 218 }) 219 } 220 221 func (s *YamlSuite) TestUnmarshalLastPlugDefinitionWins(c *C) { 222 // NOTE: yaml content cannot use tabs, indent the section with spaces. 223 info, err := snap.InfoFromSnapYaml([]byte(` 224 name: snap 225 plugs: 226 net: 227 interface: network-client 228 attr: 1 229 net: 230 interface: network-client 231 attr: 2 232 `)) 233 c.Assert(err, IsNil) 234 c.Check(info.InstanceName(), Equals, "snap") 235 c.Check(info.Plugs, HasLen, 1) 236 c.Check(info.Slots, HasLen, 0) 237 c.Assert(info.Plugs["net"], DeepEquals, &snap.PlugInfo{ 238 Snap: info, 239 Name: "net", 240 Interface: "network-client", 241 Attrs: map[string]interface{}{"attr": int64(2)}, 242 }) 243 } 244 245 func (s *YamlSuite) TestUnmarshalPlugsExplicitlyDefinedImplicitlyBoundToApps(c *C) { 246 // NOTE: yaml content cannot use tabs, indent the section with spaces. 247 info, err := snap.InfoFromSnapYaml([]byte(` 248 name: snap 249 plugs: 250 network-client: 251 apps: 252 app: 253 `)) 254 c.Assert(err, IsNil) 255 c.Check(info.InstanceName(), Equals, "snap") 256 c.Check(info.Plugs, HasLen, 1) 257 c.Check(info.Slots, HasLen, 0) 258 c.Check(info.Apps, HasLen, 1) 259 260 plug := info.Plugs["network-client"] 261 app := info.Apps["app"] 262 c.Assert(plug, DeepEquals, &snap.PlugInfo{ 263 Snap: info, 264 Name: "network-client", 265 Interface: "network-client", 266 Apps: map[string]*snap.AppInfo{app.Name: app}, 267 }) 268 c.Assert(app, DeepEquals, &snap.AppInfo{ 269 Snap: info, 270 Name: "app", 271 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 272 }) 273 } 274 275 func (s *YamlSuite) TestUnmarshalGlobalPlugBoundToOneApp(c *C) { 276 // NOTE: yaml content cannot use tabs, indent the section with spaces. 277 info, err := snap.InfoFromSnapYaml([]byte(` 278 name: snap 279 plugs: 280 network-client: 281 apps: 282 with-plug: 283 plugs: [network-client] 284 without-plug: 285 `)) 286 c.Assert(err, IsNil) 287 c.Check(info.InstanceName(), Equals, "snap") 288 c.Check(info.Plugs, HasLen, 1) 289 c.Check(info.Slots, HasLen, 0) 290 c.Check(info.Apps, HasLen, 2) 291 292 plug := info.Plugs["network-client"] 293 withPlugApp := info.Apps["with-plug"] 294 withoutPlugApp := info.Apps["without-plug"] 295 c.Assert(plug, DeepEquals, &snap.PlugInfo{ 296 Snap: info, 297 Name: "network-client", 298 Interface: "network-client", 299 Apps: map[string]*snap.AppInfo{withPlugApp.Name: withPlugApp}, 300 }) 301 c.Assert(withPlugApp, DeepEquals, &snap.AppInfo{ 302 Snap: info, 303 Name: "with-plug", 304 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 305 }) 306 c.Assert(withoutPlugApp, DeepEquals, &snap.AppInfo{ 307 Snap: info, 308 Name: "without-plug", 309 Plugs: map[string]*snap.PlugInfo{}, 310 }) 311 } 312 313 func (s *YamlSuite) TestUnmarshalPlugsExplicitlyDefinedExplicitlyBoundToApps(c *C) { 314 // NOTE: yaml content cannot use tabs, indent the section with spaces. 315 info, err := snap.InfoFromSnapYaml([]byte(` 316 name: snap 317 plugs: 318 net: network-client 319 apps: 320 app: 321 plugs: ["net"] 322 `)) 323 c.Assert(err, IsNil) 324 c.Check(info.InstanceName(), Equals, "snap") 325 c.Check(info.Plugs, HasLen, 1) 326 c.Check(info.Slots, HasLen, 0) 327 c.Check(info.Apps, HasLen, 1) 328 plug := info.Plugs["net"] 329 app := info.Apps["app"] 330 c.Assert(plug, DeepEquals, &snap.PlugInfo{ 331 Snap: info, 332 Name: "net", 333 Interface: "network-client", 334 Apps: map[string]*snap.AppInfo{app.Name: app}, 335 }) 336 c.Assert(app, DeepEquals, &snap.AppInfo{ 337 Snap: info, 338 Name: "app", 339 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 340 }) 341 } 342 343 func (s *YamlSuite) TestUnmarshalPlugsImplicitlyDefinedExplicitlyBoundToApps(c *C) { 344 // NOTE: yaml content cannot use tabs, indent the section with spaces. 345 info, err := snap.InfoFromSnapYaml([]byte(` 346 name: snap 347 apps: 348 app: 349 plugs: ["network-client"] 350 `)) 351 c.Assert(err, IsNil) 352 c.Check(info.InstanceName(), Equals, "snap") 353 c.Check(info.Plugs, HasLen, 1) 354 c.Check(info.Slots, HasLen, 0) 355 c.Check(info.Apps, HasLen, 1) 356 plug := info.Plugs["network-client"] 357 app := info.Apps["app"] 358 c.Assert(plug, DeepEquals, &snap.PlugInfo{ 359 Snap: info, 360 Name: "network-client", 361 Interface: "network-client", 362 Apps: map[string]*snap.AppInfo{app.Name: app}, 363 }) 364 c.Assert(app, DeepEquals, &snap.AppInfo{ 365 Snap: info, 366 Name: "app", 367 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 368 }) 369 } 370 371 func (s *YamlSuite) TestUnmarshalPlugWithoutInterfaceName(c *C) { 372 // NOTE: yaml content cannot use tabs, indent the section with spaces. 373 info, err := snap.InfoFromSnapYaml([]byte(` 374 name: snap 375 plugs: 376 network-client: 377 ipv6-aware: true 378 `)) 379 c.Assert(err, IsNil) 380 c.Check(info.InstanceName(), Equals, "snap") 381 c.Check(info.Plugs, HasLen, 1) 382 c.Check(info.Slots, HasLen, 0) 383 c.Check(info.Apps, HasLen, 0) 384 c.Assert(info.Plugs["network-client"], DeepEquals, &snap.PlugInfo{ 385 Snap: info, 386 Name: "network-client", 387 Interface: "network-client", 388 Attrs: map[string]interface{}{"ipv6-aware": true}, 389 }) 390 } 391 392 func (s *YamlSuite) TestUnmarshalPlugWithLabel(c *C) { 393 // NOTE: yaml content cannot use tabs, indent the section with spaces. 394 info, err := snap.InfoFromSnapYaml([]byte(` 395 name: snap 396 plugs: 397 bool-file: 398 label: Disk I/O indicator 399 `)) 400 c.Assert(err, IsNil) 401 c.Check(info.InstanceName(), Equals, "snap") 402 c.Check(info.Plugs, HasLen, 1) 403 c.Check(info.Slots, HasLen, 0) 404 c.Check(info.Apps, HasLen, 0) 405 c.Assert(info.Plugs["bool-file"], DeepEquals, &snap.PlugInfo{ 406 Snap: info, 407 Name: "bool-file", 408 Interface: "bool-file", 409 Label: "Disk I/O indicator", 410 }) 411 } 412 413 func (s *YamlSuite) TestUnmarshalCorruptedPlugWithNonStringInterfaceName(c *C) { 414 // NOTE: yaml content cannot use tabs, indent the section with spaces. 415 _, err := snap.InfoFromSnapYaml([]byte(` 416 name: snap 417 plugs: 418 net: 419 interface: 1.0 420 ipv6-aware: true 421 `)) 422 c.Assert(err, ErrorMatches, `interface name on plug "net" is not a string \(found float64\)`) 423 } 424 425 func (s *YamlSuite) TestUnmarshalCorruptedPlugWithNonStringLabel(c *C) { 426 // NOTE: yaml content cannot use tabs, indent the section with spaces. 427 _, err := snap.InfoFromSnapYaml([]byte(` 428 name: snap 429 plugs: 430 bool-file: 431 label: 1.0 432 `)) 433 c.Assert(err, ErrorMatches, `label of plug "bool-file" is not a string \(found float64\)`) 434 } 435 436 func (s *YamlSuite) TestUnmarshalCorruptedPlugWithNonStringAttributes(c *C) { 437 // NOTE: yaml content cannot use tabs, indent the section with spaces. 438 _, err := snap.InfoFromSnapYaml([]byte(` 439 name: snap 440 plugs: 441 net: 442 1: ok 443 `)) 444 c.Assert(err, ErrorMatches, `plug "net" has attribute key that is not a string \(found int\)`) 445 } 446 447 func (s *YamlSuite) TestUnmarshalCorruptedPlugWithEmptyAttributeKey(c *C) { 448 // NOTE: yaml content cannot use tabs, indent the section with spaces. 449 _, err := snap.InfoFromSnapYaml([]byte(` 450 name: snap 451 plugs: 452 net: 453 "": ok 454 `)) 455 c.Assert(err, ErrorMatches, `plug "net" has an empty attribute key`) 456 } 457 458 func (s *YamlSuite) TestUnmarshalCorruptedPlugWithUnexpectedType(c *C) { 459 // NOTE: yaml content cannot use tabs, indent the section with spaces. 460 _, err := snap.InfoFromSnapYaml([]byte(` 461 name: snap 462 plugs: 463 net: 5 464 `)) 465 c.Assert(err, ErrorMatches, `plug "net" has malformed definition \(found int\)`) 466 } 467 468 func (s *YamlSuite) TestUnmarshalReservedPlugAttribute(c *C) { 469 // NOTE: yaml content cannot use tabs, indent the section with spaces. 470 _, err := snap.InfoFromSnapYaml([]byte(` 471 name: snap 472 plugs: 473 serial: 474 interface: serial-port 475 $baud-rate: [9600] 476 `)) 477 c.Assert(err, ErrorMatches, `plug "serial" uses reserved attribute "\$baud-rate"`) 478 } 479 480 func (s *YamlSuite) TestUnmarshalInvalidPlugAttribute(c *C) { 481 // NOTE: yaml content cannot use tabs, indent the section with spaces. 482 _, err := snap.InfoFromSnapYaml([]byte(` 483 name: snap 484 plugs: 485 serial: 486 interface: serial-port 487 foo: null 488 `)) 489 c.Assert(err, ErrorMatches, `attribute "foo" of plug \"serial\": invalid scalar:.*`) 490 } 491 492 func (s *YamlSuite) TestUnmarshalInvalidAttributeMapKey(c *C) { 493 // NOTE: yaml content cannot use tabs, indent the section with spaces. 494 _, err := snap.InfoFromSnapYaml([]byte(` 495 name: snap 496 plugs: 497 serial: 498 interface: serial-port 499 bar: 500 baz: 501 - 1: A 502 `)) 503 c.Assert(err, ErrorMatches, `attribute "bar" of plug \"serial\": non-string key: 1`) 504 } 505 506 // Tests focusing on slots 507 508 func (s *YamlSuite) TestUnmarshalStandaloneImplicitSlot(c *C) { 509 // NOTE: yaml content cannot use tabs, indent the section with spaces. 510 info, err := snap.InfoFromSnapYaml([]byte(` 511 name: snap 512 slots: 513 network-client: 514 `)) 515 c.Assert(err, IsNil) 516 c.Check(info.InstanceName(), Equals, "snap") 517 c.Check(info.Plugs, HasLen, 0) 518 c.Check(info.Slots, HasLen, 1) 519 c.Assert(info.Slots["network-client"], DeepEquals, &snap.SlotInfo{ 520 Snap: info, 521 Name: "network-client", 522 Interface: "network-client", 523 }) 524 } 525 526 func (s *YamlSuite) TestUnmarshalStandaloneAbbreviatedSlot(c *C) { 527 // NOTE: yaml content cannot use tabs, indent the section with spaces. 528 info, err := snap.InfoFromSnapYaml([]byte(` 529 name: snap 530 slots: 531 net: network-client 532 `)) 533 c.Assert(err, IsNil) 534 c.Check(info.InstanceName(), Equals, "snap") 535 c.Check(info.Plugs, HasLen, 0) 536 c.Check(info.Slots, HasLen, 1) 537 c.Assert(info.Slots["net"], DeepEquals, &snap.SlotInfo{ 538 Snap: info, 539 Name: "net", 540 Interface: "network-client", 541 }) 542 } 543 544 func (s *YamlSuite) TestUnmarshalStandaloneMinimalisticSlot(c *C) { 545 // NOTE: yaml content cannot use tabs, indent the section with spaces. 546 info, err := snap.InfoFromSnapYaml([]byte(` 547 name: snap 548 slots: 549 net: 550 interface: network-client 551 `)) 552 c.Assert(err, IsNil) 553 c.Check(info.InstanceName(), Equals, "snap") 554 c.Check(info.Plugs, HasLen, 0) 555 c.Check(info.Slots, HasLen, 1) 556 c.Assert(info.Slots["net"], DeepEquals, &snap.SlotInfo{ 557 Snap: info, 558 Name: "net", 559 Interface: "network-client", 560 }) 561 } 562 563 func (s *YamlSuite) TestUnmarshalStandaloneCompleteSlot(c *C) { 564 // NOTE: yaml content cannot use tabs, indent the section with spaces. 565 info, err := snap.InfoFromSnapYaml([]byte(` 566 name: snap 567 slots: 568 net: 569 interface: network-client 570 ipv6-aware: true 571 `)) 572 c.Assert(err, IsNil) 573 c.Check(info.InstanceName(), Equals, "snap") 574 c.Check(info.Plugs, HasLen, 0) 575 c.Check(info.Slots, HasLen, 1) 576 c.Assert(info.Slots["net"], DeepEquals, &snap.SlotInfo{ 577 Snap: info, 578 Name: "net", 579 Interface: "network-client", 580 Attrs: map[string]interface{}{"ipv6-aware": true}, 581 }) 582 } 583 584 func (s *YamlSuite) TestUnmarshalStandaloneSlotWithIntAndListAndMap(c *C) { 585 // NOTE: yaml content cannot use tabs, indent the section with spaces. 586 info, err := snap.InfoFromSnapYaml([]byte(` 587 name: snap 588 slots: 589 iface: 590 interface: complex 591 i: 3 592 l: [1,2] 593 m: 594 a: "A" 595 `)) 596 c.Assert(err, IsNil) 597 c.Check(info.InstanceName(), Equals, "snap") 598 c.Check(info.Plugs, HasLen, 0) 599 c.Check(info.Slots, HasLen, 1) 600 c.Assert(info.Slots["iface"], DeepEquals, &snap.SlotInfo{ 601 Snap: info, 602 Name: "iface", 603 Interface: "complex", 604 Attrs: map[string]interface{}{ 605 "i": int64(3), 606 "l": []interface{}{int64(1), int64(2)}, 607 "m": map[string]interface{}{"a": "A"}, 608 }, 609 }) 610 } 611 612 func (s *YamlSuite) TestUnmarshalLastSlotDefinitionWins(c *C) { 613 // NOTE: yaml content cannot use tabs, indent the section with spaces. 614 info, err := snap.InfoFromSnapYaml([]byte(` 615 name: snap 616 slots: 617 net: 618 interface: network-client 619 attr: 1 620 net: 621 interface: network-client 622 attr: 2 623 `)) 624 c.Assert(err, IsNil) 625 c.Check(info.InstanceName(), Equals, "snap") 626 c.Check(info.Plugs, HasLen, 0) 627 c.Check(info.Slots, HasLen, 1) 628 c.Assert(info.Slots["net"], DeepEquals, &snap.SlotInfo{ 629 Snap: info, 630 Name: "net", 631 Interface: "network-client", 632 Attrs: map[string]interface{}{"attr": int64(2)}, 633 }) 634 } 635 636 func (s *YamlSuite) TestUnmarshalSlotsExplicitlyDefinedImplicitlyBoundToApps(c *C) { 637 // NOTE: yaml content cannot use tabs, indent the section with spaces. 638 info, err := snap.InfoFromSnapYaml([]byte(` 639 name: snap 640 slots: 641 network-client: 642 apps: 643 app: 644 `)) 645 c.Assert(err, IsNil) 646 c.Check(info.InstanceName(), Equals, "snap") 647 c.Check(info.Plugs, HasLen, 0) 648 c.Check(info.Slots, HasLen, 1) 649 c.Check(info.Apps, HasLen, 1) 650 slot := info.Slots["network-client"] 651 app := info.Apps["app"] 652 c.Assert(slot, DeepEquals, &snap.SlotInfo{ 653 Snap: info, 654 Name: "network-client", 655 Interface: "network-client", 656 Apps: map[string]*snap.AppInfo{app.Name: app}, 657 }) 658 c.Assert(app, DeepEquals, &snap.AppInfo{ 659 Snap: info, 660 Name: "app", 661 Slots: map[string]*snap.SlotInfo{slot.Name: slot}, 662 }) 663 } 664 665 func (s *YamlSuite) TestUnmarshalSlotsExplicitlyDefinedExplicitlyBoundToApps(c *C) { 666 // NOTE: yaml content cannot use tabs, indent the section with spaces. 667 info, err := snap.InfoFromSnapYaml([]byte(` 668 name: snap 669 slots: 670 net: network-client 671 apps: 672 app: 673 slots: ["net"] 674 `)) 675 c.Assert(err, IsNil) 676 c.Check(info.InstanceName(), Equals, "snap") 677 c.Check(info.Plugs, HasLen, 0) 678 c.Check(info.Slots, HasLen, 1) 679 c.Check(info.Apps, HasLen, 1) 680 slot := info.Slots["net"] 681 app := info.Apps["app"] 682 c.Assert(slot, DeepEquals, &snap.SlotInfo{ 683 Snap: info, 684 Name: "net", 685 Interface: "network-client", 686 Apps: map[string]*snap.AppInfo{app.Name: app}, 687 }) 688 c.Assert(app, DeepEquals, &snap.AppInfo{ 689 Snap: info, 690 Name: "app", 691 Slots: map[string]*snap.SlotInfo{slot.Name: slot}, 692 }) 693 } 694 695 func (s *YamlSuite) TestUnmarshalSlotsImplicitlyDefinedExplicitlyBoundToApps(c *C) { 696 // NOTE: yaml content cannot use tabs, indent the section with spaces. 697 info, err := snap.InfoFromSnapYaml([]byte(` 698 name: snap 699 apps: 700 app: 701 slots: ["network-client"] 702 `)) 703 c.Assert(err, IsNil) 704 c.Check(info.InstanceName(), Equals, "snap") 705 c.Check(info.Plugs, HasLen, 0) 706 c.Check(info.Slots, HasLen, 1) 707 c.Check(info.Apps, HasLen, 1) 708 slot := info.Slots["network-client"] 709 app := info.Apps["app"] 710 c.Assert(slot, DeepEquals, &snap.SlotInfo{ 711 Snap: info, 712 Name: "network-client", 713 Interface: "network-client", 714 Apps: map[string]*snap.AppInfo{app.Name: app}, 715 }) 716 c.Assert(app, DeepEquals, &snap.AppInfo{ 717 Snap: info, 718 Name: "app", 719 Slots: map[string]*snap.SlotInfo{slot.Name: slot}, 720 }) 721 } 722 723 func (s *YamlSuite) TestUnmarshalSlotWithoutInterfaceName(c *C) { 724 // NOTE: yaml content cannot use tabs, indent the section with spaces. 725 info, err := snap.InfoFromSnapYaml([]byte(` 726 name: snap 727 slots: 728 network-client: 729 ipv6-aware: true 730 `)) 731 c.Assert(err, IsNil) 732 c.Check(info.InstanceName(), Equals, "snap") 733 c.Check(info.Plugs, HasLen, 0) 734 c.Check(info.Slots, HasLen, 1) 735 c.Check(info.Apps, HasLen, 0) 736 c.Assert(info.Slots["network-client"], DeepEquals, &snap.SlotInfo{ 737 Snap: info, 738 Name: "network-client", 739 Interface: "network-client", 740 Attrs: map[string]interface{}{"ipv6-aware": true}, 741 }) 742 } 743 744 func (s *YamlSuite) TestUnmarshalSlotWithLabel(c *C) { 745 // NOTE: yaml content cannot use tabs, indent the section with spaces. 746 info, err := snap.InfoFromSnapYaml([]byte(` 747 name: snap 748 slots: 749 led0: 750 interface: bool-file 751 label: Front panel LED (red) 752 `)) 753 c.Assert(err, IsNil) 754 c.Check(info.InstanceName(), Equals, "snap") 755 c.Check(info.Plugs, HasLen, 0) 756 c.Check(info.Slots, HasLen, 1) 757 c.Check(info.Apps, HasLen, 0) 758 c.Assert(info.Slots["led0"], DeepEquals, &snap.SlotInfo{ 759 Snap: info, 760 Name: "led0", 761 Interface: "bool-file", 762 Label: "Front panel LED (red)", 763 }) 764 } 765 766 func (s *YamlSuite) TestUnmarshalGlobalSlotsBindToHooks(c *C) { 767 // NOTE: yaml content cannot use tabs, indent the section with spaces. 768 info, err := snap.InfoFromSnapYaml([]byte(` 769 name: snap 770 slots: 771 test-slot: 772 hooks: 773 test-hook: 774 `)) 775 c.Assert(err, IsNil) 776 c.Check(info.InstanceName(), Equals, "snap") 777 c.Check(info.Plugs, HasLen, 0) 778 c.Check(info.Slots, HasLen, 1) 779 c.Check(info.Apps, HasLen, 0) 780 c.Check(info.Hooks, HasLen, 1) 781 782 slot, ok := info.Slots["test-slot"] 783 c.Assert(ok, Equals, true, Commentf("Expected slots to include 'test-slot'")) 784 hook, ok := info.Hooks["test-hook"] 785 c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) 786 787 c.Check(slot, DeepEquals, &snap.SlotInfo{ 788 Snap: info, 789 Name: "test-slot", 790 Interface: "test-slot", 791 Hooks: map[string]*snap.HookInfo{hook.Name: hook}, 792 }) 793 c.Check(hook, DeepEquals, &snap.HookInfo{ 794 Snap: info, 795 Name: "test-hook", 796 Slots: map[string]*snap.SlotInfo{slot.Name: slot}, 797 798 Explicit: true, 799 }) 800 } 801 802 func (s *YamlSuite) TestUnmarshalHookWithSlot(c *C) { 803 // NOTE: yaml content cannot use tabs, indent the section with spaces. 804 info, err := snap.InfoFromSnapYaml([]byte(` 805 name: snap 806 hooks: 807 test-hook: 808 slots: [test-slot] 809 `)) 810 c.Assert(err, IsNil) 811 c.Check(info.InstanceName(), Equals, "snap") 812 c.Check(info.Plugs, HasLen, 0) 813 c.Check(info.Slots, HasLen, 1) 814 c.Check(info.Apps, HasLen, 0) 815 c.Check(info.Hooks, HasLen, 1) 816 817 slot, ok := info.Slots["test-slot"] 818 c.Assert(ok, Equals, true, Commentf("Expected slots to include 'test-slot'")) 819 hook, ok := info.Hooks["test-hook"] 820 c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) 821 822 c.Check(slot, DeepEquals, &snap.SlotInfo{ 823 Snap: info, 824 Name: "test-slot", 825 Interface: "test-slot", 826 Hooks: map[string]*snap.HookInfo{hook.Name: hook}, 827 }) 828 c.Check(hook, DeepEquals, &snap.HookInfo{ 829 Snap: info, 830 Name: "test-hook", 831 Slots: map[string]*snap.SlotInfo{slot.Name: slot}, 832 833 Explicit: true, 834 }) 835 } 836 837 func (s *YamlSuite) TestUnmarshalCorruptedSlotWithNonStringInterfaceName(c *C) { 838 // NOTE: yaml content cannot use tabs, indent the section with spaces. 839 _, err := snap.InfoFromSnapYaml([]byte(` 840 name: snap 841 slots: 842 net: 843 interface: 1.0 844 ipv6-aware: true 845 `)) 846 c.Assert(err, ErrorMatches, `interface name on slot "net" is not a string \(found float64\)`) 847 } 848 849 func (s *YamlSuite) TestUnmarshalCorruptedSlotWithNonStringLabel(c *C) { 850 // NOTE: yaml content cannot use tabs, indent the section with spaces. 851 _, err := snap.InfoFromSnapYaml([]byte(` 852 name: snap 853 slots: 854 bool-file: 855 label: 1.0 856 `)) 857 c.Assert(err, ErrorMatches, `label of slot "bool-file" is not a string \(found float64\)`) 858 } 859 860 func (s *YamlSuite) TestUnmarshalCorruptedSlotWithNonStringAttributes(c *C) { 861 // NOTE: yaml content cannot use tabs, indent the section with spaces. 862 _, err := snap.InfoFromSnapYaml([]byte(` 863 name: snap 864 slots: 865 net: 866 1: ok 867 `)) 868 c.Assert(err, ErrorMatches, `slot "net" has attribute key that is not a string \(found int\)`) 869 } 870 871 func (s *YamlSuite) TestUnmarshalCorruptedSlotWithEmptyAttributeKey(c *C) { 872 // NOTE: yaml content cannot use tabs, indent the section with spaces. 873 _, err := snap.InfoFromSnapYaml([]byte(` 874 name: snap 875 slots: 876 net: 877 "": ok 878 `)) 879 c.Assert(err, ErrorMatches, `slot "net" has an empty attribute key`) 880 } 881 882 func (s *YamlSuite) TestUnmarshalCorruptedSlotWithUnexpectedType(c *C) { 883 // NOTE: yaml content cannot use tabs, indent the section with spaces. 884 _, err := snap.InfoFromSnapYaml([]byte(` 885 name: snap 886 slots: 887 net: 5 888 `)) 889 c.Assert(err, ErrorMatches, `slot "net" has malformed definition \(found int\)`) 890 } 891 892 func (s *YamlSuite) TestUnmarshalReservedSlotAttribute(c *C) { 893 // NOTE: yaml content cannot use tabs, indent the section with spaces. 894 _, err := snap.InfoFromSnapYaml([]byte(` 895 name: snap 896 slots: 897 serial: 898 interface: serial-port 899 $baud-rate: [9600] 900 `)) 901 c.Assert(err, ErrorMatches, `slot "serial" uses reserved attribute "\$baud-rate"`) 902 } 903 904 func (s *YamlSuite) TestUnmarshalInvalidSlotAttribute(c *C) { 905 // NOTE: yaml content cannot use tabs, indent the section with spaces. 906 _, err := snap.InfoFromSnapYaml([]byte(` 907 name: snap 908 slots: 909 serial: 910 interface: serial-port 911 foo: null 912 `)) 913 c.Assert(err, ErrorMatches, `attribute "foo" of slot \"serial\": invalid scalar:.*`) 914 } 915 916 func (s *YamlSuite) TestUnmarshalHook(c *C) { 917 // NOTE: yaml content cannot use tabs, indent the section with spaces. 918 info, err := snap.InfoFromSnapYaml([]byte(` 919 name: snap 920 hooks: 921 test-hook: 922 `)) 923 c.Assert(err, IsNil) 924 c.Check(info.InstanceName(), Equals, "snap") 925 c.Check(info.Plugs, HasLen, 0) 926 c.Check(info.Slots, HasLen, 0) 927 c.Check(info.Apps, HasLen, 0) 928 c.Check(info.Hooks, HasLen, 1) 929 930 hook, ok := info.Hooks["test-hook"] 931 c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) 932 933 c.Check(hook, DeepEquals, &snap.HookInfo{ 934 Snap: info, 935 Name: "test-hook", 936 Plugs: nil, 937 938 Explicit: true, 939 }) 940 } 941 942 func (s *YamlSuite) TestUnmarshalUnsupportedHook(c *C) { 943 s.restore() 944 hookType := snap.NewHookType(regexp.MustCompile("not-test-hook")) 945 s.restore = snap.MockSupportedHookTypes([]*snap.HookType{hookType}) 946 947 // NOTE: yaml content cannot use tabs, indent the section with spaces. 948 info, err := snap.InfoFromSnapYaml([]byte(` 949 name: snap 950 hooks: 951 test-hook: 952 `)) 953 c.Assert(err, IsNil) 954 c.Check(info.InstanceName(), Equals, "snap") 955 c.Check(info.Plugs, HasLen, 0) 956 c.Check(info.Slots, HasLen, 0) 957 c.Check(info.Apps, HasLen, 0) 958 c.Check(info.Hooks, HasLen, 0, Commentf("Expected no hooks to be loaded")) 959 } 960 961 func (s *YamlSuite) TestUnmarshalHookFiltersOutUnsupportedHooks(c *C) { 962 s.restore() 963 hookType := snap.NewHookType(regexp.MustCompile("test-.*")) 964 s.restore = snap.MockSupportedHookTypes([]*snap.HookType{hookType}) 965 966 // NOTE: yaml content cannot use tabs, indent the section with spaces. 967 info, err := snap.InfoFromSnapYaml([]byte(` 968 name: snap 969 hooks: 970 test-hook: 971 foo-hook: 972 `)) 973 c.Assert(err, IsNil) 974 c.Check(info.InstanceName(), Equals, "snap") 975 c.Check(info.Plugs, HasLen, 0) 976 c.Check(info.Slots, HasLen, 0) 977 c.Check(info.Apps, HasLen, 0) 978 c.Check(info.Hooks, HasLen, 1) 979 980 hook, ok := info.Hooks["test-hook"] 981 c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) 982 983 c.Check(hook, DeepEquals, &snap.HookInfo{ 984 Snap: info, 985 Name: "test-hook", 986 Plugs: nil, 987 988 Explicit: true, 989 }) 990 } 991 992 func (s *YamlSuite) TestUnmarshalHookWithPlug(c *C) { 993 // NOTE: yaml content cannot use tabs, indent the section with spaces. 994 info, err := snap.InfoFromSnapYaml([]byte(` 995 name: snap 996 hooks: 997 test-hook: 998 plugs: [test-plug] 999 `)) 1000 c.Assert(err, IsNil) 1001 c.Check(info.InstanceName(), Equals, "snap") 1002 c.Check(info.Plugs, HasLen, 1) 1003 c.Check(info.Slots, HasLen, 0) 1004 c.Check(info.Apps, HasLen, 0) 1005 c.Check(info.Hooks, HasLen, 1) 1006 1007 plug, ok := info.Plugs["test-plug"] 1008 c.Assert(ok, Equals, true, Commentf("Expected plugs to include 'test-plug'")) 1009 hook, ok := info.Hooks["test-hook"] 1010 c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) 1011 1012 c.Check(plug, DeepEquals, &snap.PlugInfo{ 1013 Snap: info, 1014 Name: "test-plug", 1015 Interface: "test-plug", 1016 Hooks: map[string]*snap.HookInfo{hook.Name: hook}, 1017 }) 1018 c.Check(hook, DeepEquals, &snap.HookInfo{ 1019 Snap: info, 1020 Name: "test-hook", 1021 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 1022 1023 Explicit: true, 1024 }) 1025 } 1026 1027 func (s *YamlSuite) TestUnmarshalGlobalPlugsBindToHooks(c *C) { 1028 // NOTE: yaml content cannot use tabs, indent the section with spaces. 1029 info, err := snap.InfoFromSnapYaml([]byte(` 1030 name: snap 1031 plugs: 1032 test-plug: 1033 hooks: 1034 test-hook: 1035 `)) 1036 c.Assert(err, IsNil) 1037 c.Check(info.InstanceName(), Equals, "snap") 1038 c.Check(info.Plugs, HasLen, 1) 1039 c.Check(info.Slots, HasLen, 0) 1040 c.Check(info.Apps, HasLen, 0) 1041 c.Check(info.Hooks, HasLen, 1) 1042 1043 plug, ok := info.Plugs["test-plug"] 1044 c.Assert(ok, Equals, true, Commentf("Expected plugs to include 'test-plug'")) 1045 hook, ok := info.Hooks["test-hook"] 1046 c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) 1047 1048 c.Check(plug, DeepEquals, &snap.PlugInfo{ 1049 Snap: info, 1050 Name: "test-plug", 1051 Interface: "test-plug", 1052 Hooks: map[string]*snap.HookInfo{hook.Name: hook}, 1053 }) 1054 c.Check(hook, DeepEquals, &snap.HookInfo{ 1055 Snap: info, 1056 Name: "test-hook", 1057 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 1058 1059 Explicit: true, 1060 }) 1061 } 1062 1063 func (s *YamlSuite) TestUnmarshalGlobalPlugBoundToOneHook(c *C) { 1064 // NOTE: yaml content cannot use tabs, indent the section with spaces. 1065 info, err := snap.InfoFromSnapYaml([]byte(` 1066 name: snap 1067 plugs: 1068 test-plug: 1069 hooks: 1070 with-plug: 1071 plugs: [test-plug] 1072 without-plug: 1073 `)) 1074 c.Assert(err, IsNil) 1075 c.Check(info.InstanceName(), Equals, "snap") 1076 c.Check(info.Plugs, HasLen, 1) 1077 c.Check(info.Slots, HasLen, 0) 1078 c.Check(info.Apps, HasLen, 0) 1079 c.Check(info.Hooks, HasLen, 2) 1080 1081 plug := info.Plugs["test-plug"] 1082 withPlugHook := info.Hooks["with-plug"] 1083 withoutPlugHook := info.Hooks["without-plug"] 1084 c.Assert(plug, DeepEquals, &snap.PlugInfo{ 1085 Snap: info, 1086 Name: "test-plug", 1087 Interface: "test-plug", 1088 Hooks: map[string]*snap.HookInfo{withPlugHook.Name: withPlugHook}, 1089 }) 1090 c.Assert(withPlugHook, DeepEquals, &snap.HookInfo{ 1091 Snap: info, 1092 Name: "with-plug", 1093 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 1094 1095 Explicit: true, 1096 }) 1097 c.Assert(withoutPlugHook, DeepEquals, &snap.HookInfo{ 1098 Snap: info, 1099 Name: "without-plug", 1100 Plugs: map[string]*snap.PlugInfo{}, 1101 1102 Explicit: true, 1103 }) 1104 } 1105 1106 func (s *YamlSuite) TestUnmarshalExplicitGlobalPlugBoundToHook(c *C) { 1107 // NOTE: yaml content cannot use tabs, indent the section with spaces. 1108 info, err := snap.InfoFromSnapYaml([]byte(` 1109 name: snap 1110 plugs: 1111 test-plug: test-interface 1112 hooks: 1113 test-hook: 1114 plugs: ["test-plug"] 1115 `)) 1116 c.Assert(err, IsNil) 1117 c.Check(info.InstanceName(), Equals, "snap") 1118 c.Check(info.Plugs, HasLen, 1) 1119 c.Check(info.Slots, HasLen, 0) 1120 c.Check(info.Apps, HasLen, 0) 1121 c.Check(info.Hooks, HasLen, 1) 1122 1123 plug, ok := info.Plugs["test-plug"] 1124 c.Assert(ok, Equals, true, Commentf("Expected plugs to include 'test-plug'")) 1125 hook, ok := info.Hooks["test-hook"] 1126 c.Assert(ok, Equals, true, Commentf("Expected hooks to include 'test-hook'")) 1127 1128 c.Check(plug, DeepEquals, &snap.PlugInfo{ 1129 Snap: info, 1130 Name: "test-plug", 1131 Interface: "test-interface", 1132 Hooks: map[string]*snap.HookInfo{hook.Name: hook}, 1133 }) 1134 c.Check(hook, DeepEquals, &snap.HookInfo{ 1135 Snap: info, 1136 Name: "test-hook", 1137 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 1138 1139 Explicit: true, 1140 }) 1141 } 1142 1143 func (s *YamlSuite) TestUnmarshalGlobalPlugBoundToHookNotApp(c *C) { 1144 // NOTE: yaml content cannot use tabs, indent the section with spaces. 1145 info, err := snap.InfoFromSnapYaml([]byte(` 1146 name: snap 1147 plugs: 1148 test-plug: 1149 hooks: 1150 test-hook: 1151 plugs: [test-plug] 1152 apps: 1153 test-app: 1154 `)) 1155 c.Assert(err, IsNil) 1156 c.Check(info.InstanceName(), Equals, "snap") 1157 c.Check(info.Plugs, HasLen, 1) 1158 c.Check(info.Slots, HasLen, 0) 1159 c.Check(info.Apps, HasLen, 1) 1160 c.Check(info.Hooks, HasLen, 1) 1161 1162 plug := info.Plugs["test-plug"] 1163 hook := info.Hooks["test-hook"] 1164 app := info.Apps["test-app"] 1165 c.Assert(plug, DeepEquals, &snap.PlugInfo{ 1166 Snap: info, 1167 Name: "test-plug", 1168 Interface: "test-plug", 1169 Apps: map[string]*snap.AppInfo{}, 1170 Hooks: map[string]*snap.HookInfo{hook.Name: hook}, 1171 }) 1172 c.Assert(hook, DeepEquals, &snap.HookInfo{ 1173 Snap: info, 1174 Name: "test-hook", 1175 Plugs: map[string]*snap.PlugInfo{plug.Name: plug}, 1176 1177 Explicit: true, 1178 }) 1179 c.Assert(app, DeepEquals, &snap.AppInfo{ 1180 Snap: info, 1181 Name: "test-app", 1182 Plugs: map[string]*snap.PlugInfo{}, 1183 }) 1184 } 1185 1186 func (s *YamlSuite) TestUnmarshalComplexExample(c *C) { 1187 // NOTE: yaml content cannot use tabs, indent the section with spaces. 1188 info, err := snap.InfoFromSnapYaml([]byte(` 1189 name: foo 1190 version: 1.2 1191 title: Foo 1192 summary: foo app 1193 type: app 1194 epoch: 1* 1195 confinement: devmode 1196 license: GPL-3.0 1197 description: | 1198 Foo provides useful services 1199 apps: 1200 daemon: 1201 command: foo --daemon 1202 plugs: [network, network-bind] 1203 slots: [foo-socket-slot] 1204 foo: 1205 command: fooctl 1206 plugs: [foo-socket-plug] 1207 hooks: 1208 test-hook: 1209 plugs: [foo-socket-plug] 1210 slots: [foo-socket-slot] 1211 plugs: 1212 foo-socket-plug: 1213 interface: socket 1214 # $protocol: foo 1215 logging: 1216 interface: syslog 1217 slots: 1218 foo-socket-slot: 1219 interface: socket 1220 path: $SNAP_DATA/socket 1221 protocol: foo 1222 tracing: 1223 interface: ptrace 1224 `)) 1225 c.Assert(err, IsNil) 1226 c.Check(info.InstanceName(), Equals, "foo") 1227 c.Check(info.Version, Equals, "1.2") 1228 c.Check(info.Type(), Equals, snap.TypeApp) 1229 c.Check(info.Epoch, DeepEquals, snap.E("1*")) 1230 c.Check(info.Confinement, Equals, snap.DevModeConfinement) 1231 c.Check(info.Title(), Equals, "Foo") 1232 c.Check(info.Summary(), Equals, "foo app") 1233 c.Check(info.Description(), Equals, "Foo provides useful services\n") 1234 c.Check(info.Apps, HasLen, 2) 1235 c.Check(info.Plugs, HasLen, 4) 1236 c.Check(info.Slots, HasLen, 2) 1237 // these don't come from snap.yaml 1238 c.Check(info.Publisher, Equals, snap.StoreAccount{}) 1239 c.Check(info.Channel, Equals, "") 1240 c.Check(info.License, Equals, "GPL-3.0") 1241 1242 app1 := info.Apps["daemon"] 1243 app2 := info.Apps["foo"] 1244 hook := info.Hooks["test-hook"] 1245 plug1 := info.Plugs["network"] 1246 plug2 := info.Plugs["network-bind"] 1247 plug3 := info.Plugs["foo-socket-plug"] 1248 plug4 := info.Plugs["logging"] 1249 slot1 := info.Slots["foo-socket-slot"] 1250 slot2 := info.Slots["tracing"] 1251 1252 // app1 ("daemon") has three plugs ("network", "network-bind", "logging") 1253 // and two slots ("foo-socket", "tracing"). The slot "tracing" and plug 1254 // "logging" are global, everything else is app-bound. 1255 1256 c.Assert(app1, Not(IsNil)) 1257 c.Check(app1.Snap, Equals, info) 1258 c.Check(app1.Name, Equals, "daemon") 1259 c.Check(app1.Command, Equals, "foo --daemon") 1260 c.Check(app1.Plugs, DeepEquals, map[string]*snap.PlugInfo{ 1261 plug1.Name: plug1, plug2.Name: plug2, plug4.Name: plug4}) 1262 c.Check(app1.Slots, DeepEquals, map[string]*snap.SlotInfo{ 1263 slot1.Name: slot1, slot2.Name: slot2}) 1264 1265 // app2 ("foo") has two plugs ("foo-socket", "logging") and one slot 1266 // ("tracing"). The slot "tracing" and plug "logging" are global while 1267 // "foo-socket" is app-bound. 1268 1269 c.Assert(app2, Not(IsNil)) 1270 c.Check(app2.Snap, Equals, info) 1271 c.Check(app2.Name, Equals, "foo") 1272 c.Check(app2.Command, Equals, "fooctl") 1273 c.Check(app2.Plugs, DeepEquals, map[string]*snap.PlugInfo{ 1274 plug3.Name: plug3, plug4.Name: plug4}) 1275 c.Check(app2.Slots, DeepEquals, map[string]*snap.SlotInfo{ 1276 slot2.Name: slot2}) 1277 1278 // hook1 has two plugs ("foo-socket", "logging") and two slots ("foo-socket", "tracing"). 1279 // The plug "logging" and slot "tracing" are global while "foo-socket" is hook-bound. 1280 1281 c.Assert(hook, NotNil) 1282 c.Check(hook.Snap, Equals, info) 1283 c.Check(hook.Name, Equals, "test-hook") 1284 c.Check(hook.Plugs, DeepEquals, map[string]*snap.PlugInfo{ 1285 plug3.Name: plug3, plug4.Name: plug4}) 1286 c.Check(hook.Slots, DeepEquals, map[string]*snap.SlotInfo{ 1287 slot1.Name: slot1, slot2.Name: slot2}) 1288 1289 // plug1 ("network") is implicitly defined and app-bound to "daemon" 1290 1291 c.Assert(plug1, Not(IsNil)) 1292 c.Check(plug1.Snap, Equals, info) 1293 c.Check(plug1.Name, Equals, "network") 1294 c.Check(plug1.Interface, Equals, "network") 1295 c.Check(plug1.Attrs, HasLen, 0) 1296 c.Check(plug1.Label, Equals, "") 1297 c.Check(plug1.Apps, DeepEquals, map[string]*snap.AppInfo{app1.Name: app1}) 1298 1299 // plug2 ("network-bind") is implicitly defined and app-bound to "daemon" 1300 1301 c.Assert(plug2, Not(IsNil)) 1302 c.Check(plug2.Snap, Equals, info) 1303 c.Check(plug2.Name, Equals, "network-bind") 1304 c.Check(plug2.Interface, Equals, "network-bind") 1305 c.Check(plug2.Attrs, HasLen, 0) 1306 c.Check(plug2.Label, Equals, "") 1307 c.Check(plug2.Apps, DeepEquals, map[string]*snap.AppInfo{app1.Name: app1}) 1308 1309 // plug3 ("foo-socket") is app-bound to "foo" 1310 1311 c.Assert(plug3, Not(IsNil)) 1312 c.Check(plug3.Snap, Equals, info) 1313 c.Check(plug3.Name, Equals, "foo-socket-plug") 1314 c.Check(plug3.Interface, Equals, "socket") 1315 c.Check(plug3.Attrs, HasLen, 0) 1316 c.Check(plug3.Label, Equals, "") 1317 c.Check(plug3.Apps, DeepEquals, map[string]*snap.AppInfo{app2.Name: app2}) 1318 1319 // plug4 ("logging") is global so it is bound to all apps 1320 1321 c.Assert(plug4, Not(IsNil)) 1322 c.Check(plug4.Snap, Equals, info) 1323 c.Check(plug4.Name, Equals, "logging") 1324 c.Check(plug4.Interface, Equals, "syslog") 1325 c.Check(plug4.Attrs, HasLen, 0) 1326 c.Check(plug4.Label, Equals, "") 1327 c.Check(plug4.Apps, DeepEquals, map[string]*snap.AppInfo{ 1328 app1.Name: app1, app2.Name: app2}) 1329 1330 // slot1 ("foo-socket") is app-bound to "daemon" 1331 1332 c.Assert(slot1, Not(IsNil)) 1333 c.Check(slot1.Snap, Equals, info) 1334 c.Check(slot1.Name, Equals, "foo-socket-slot") 1335 c.Check(slot1.Interface, Equals, "socket") 1336 c.Check(slot1.Attrs, DeepEquals, map[string]interface{}{ 1337 "protocol": "foo", "path": "$SNAP_DATA/socket"}) 1338 c.Check(slot1.Label, Equals, "") 1339 c.Check(slot1.Apps, DeepEquals, map[string]*snap.AppInfo{app1.Name: app1}) 1340 1341 // slot2 ("tracing") is global so it is bound to all apps 1342 1343 c.Assert(slot2, Not(IsNil)) 1344 c.Check(slot2.Snap, Equals, info) 1345 c.Check(slot2.Name, Equals, "tracing") 1346 c.Check(slot2.Interface, Equals, "ptrace") 1347 c.Check(slot2.Attrs, HasLen, 0) 1348 c.Check(slot2.Label, Equals, "") 1349 c.Check(slot2.Apps, DeepEquals, map[string]*snap.AppInfo{ 1350 app1.Name: app1, app2.Name: app2}) 1351 } 1352 1353 func (s *YamlSuite) TestUnmarshalActivatesOn(c *C) { 1354 info, err := snap.InfoFromSnapYaml([]byte(` 1355 name: snap 1356 slots: 1357 test-slot1: 1358 test-slot2: 1359 apps: 1360 daemon: 1361 activates-on: ["test-slot1", "test-slot2"] 1362 foo: 1363 `)) 1364 c.Assert(err, IsNil) 1365 c.Check(info.InstanceName(), Equals, "snap") 1366 c.Check(info.Plugs, HasLen, 0) 1367 c.Check(info.Slots, HasLen, 2) 1368 c.Check(info.Apps, HasLen, 2) 1369 c.Check(info.Hooks, HasLen, 0) 1370 1371 app1 := info.Apps["daemon"] 1372 app2 := info.Apps["foo"] 1373 slot1 := info.Slots["test-slot1"] 1374 slot2 := info.Slots["test-slot2"] 1375 1376 c.Assert(app1, Not(IsNil)) 1377 c.Check(app1.Name, Equals, "daemon") 1378 c.Check(app1.ActivatesOn, DeepEquals, []*snap.SlotInfo{slot1, slot2}) 1379 // activates-on slots are implicitly added to the app 1380 c.Check(app1.Slots, DeepEquals, map[string]*snap.SlotInfo{ 1381 slot1.Name: slot1, slot2.Name: slot2}) 1382 1383 c.Assert(app2, Not(IsNil)) 1384 c.Check(app2.Name, Equals, "foo") 1385 c.Check(app2.ActivatesOn, HasLen, 0) 1386 // As slot has been bound to app1, it isn't implicitly applied here 1387 c.Check(app2.Slots, HasLen, 0) 1388 1389 c.Assert(slot1, Not(IsNil)) 1390 c.Check(slot1.Name, Equals, "test-slot1") 1391 c.Check(slot1.Apps, DeepEquals, map[string]*snap.AppInfo{ 1392 app1.Name: app1}) 1393 1394 c.Assert(slot2, Not(IsNil)) 1395 c.Check(slot2.Name, Equals, "test-slot2") 1396 c.Check(slot2.Apps, DeepEquals, map[string]*snap.AppInfo{ 1397 app1.Name: app1}) 1398 } 1399 1400 func (s *YamlSuite) TestUnmarshalActivatesOnUnknownSlot(c *C) { 1401 info, err := snap.InfoFromSnapYaml([]byte(` 1402 name: snap 1403 apps: 1404 daemon: 1405 activates-on: ["test-slot"] 1406 `)) 1407 c.Check(info, IsNil) 1408 c.Check(err, ErrorMatches, `invalid activates-on value "test-slot" on app "daemon": slot not found`) 1409 } 1410 1411 // type and architectures 1412 1413 func (s *YamlSuite) TestSnapYamlTypeDefault(c *C) { 1414 y := []byte(`name: binary 1415 version: 1.0 1416 `) 1417 info, err := snap.InfoFromSnapYaml(y) 1418 c.Assert(err, IsNil) 1419 c.Assert(info.Type(), Equals, snap.TypeApp) 1420 } 1421 1422 func (s *YamlSuite) TestSnapYamlEpochDefault(c *C) { 1423 y := []byte(`name: binary 1424 version: 1.0 1425 `) 1426 info, err := snap.InfoFromSnapYaml(y) 1427 c.Assert(err, IsNil) 1428 c.Assert(info.Epoch, DeepEquals, snap.E("0")) 1429 } 1430 1431 func (s *YamlSuite) TestSnapYamlConfinementDefault(c *C) { 1432 y := []byte(`name: binary 1433 version: 1.0 1434 `) 1435 info, err := snap.InfoFromSnapYaml(y) 1436 c.Assert(err, IsNil) 1437 c.Assert(info.Confinement, Equals, snap.StrictConfinement) 1438 } 1439 1440 func (s *YamlSuite) TestSnapYamlMultipleArchitecturesParsing(c *C) { 1441 y := []byte(`name: binary 1442 version: 1.0 1443 architectures: [i386, armhf] 1444 `) 1445 info, err := snap.InfoFromSnapYaml(y) 1446 c.Assert(err, IsNil) 1447 c.Assert(info.Architectures, DeepEquals, []string{"i386", "armhf"}) 1448 } 1449 1450 func (s *YamlSuite) TestSnapYamlSingleArchitecturesParsing(c *C) { 1451 y := []byte(`name: binary 1452 version: 1.0 1453 architectures: [i386] 1454 `) 1455 info, err := snap.InfoFromSnapYaml(y) 1456 c.Assert(err, IsNil) 1457 c.Assert(info.Architectures, DeepEquals, []string{"i386"}) 1458 } 1459 1460 func (s *YamlSuite) TestSnapYamlAssumesParsing(c *C) { 1461 y := []byte(`name: binary 1462 version: 1.0 1463 assumes: [feature2, feature1] 1464 `) 1465 info, err := snap.InfoFromSnapYaml(y) 1466 c.Assert(err, IsNil) 1467 c.Assert(info.Assumes, DeepEquals, []string{"feature1", "feature2"}) 1468 } 1469 1470 func (s *YamlSuite) TestSnapYamlNoArchitecturesParsing(c *C) { 1471 y := []byte(`name: binary 1472 version: 1.0 1473 `) 1474 info, err := snap.InfoFromSnapYaml(y) 1475 c.Assert(err, IsNil) 1476 c.Assert(info.Architectures, DeepEquals, []string{"all"}) 1477 } 1478 1479 func (s *YamlSuite) TestSnapYamlBadArchitectureParsing(c *C) { 1480 y := []byte(`name: binary 1481 version: 1.0 1482 architectures: 1483 armhf: 1484 no 1485 `) 1486 _, err := snap.InfoFromSnapYaml(y) 1487 c.Assert(err, NotNil) 1488 } 1489 1490 // apps 1491 1492 func (s *YamlSuite) TestSimpleAppExample(c *C) { 1493 y := []byte(`name: wat 1494 version: 42 1495 apps: 1496 cm: 1497 command: cm0 1498 `) 1499 info, err := snap.InfoFromSnapYaml(y) 1500 c.Assert(err, IsNil) 1501 c.Check(info.Apps, DeepEquals, map[string]*snap.AppInfo{ 1502 "cm": { 1503 Snap: info, 1504 Name: "cm", 1505 Command: "cm0", 1506 }, 1507 }) 1508 } 1509 1510 func (s *YamlSuite) TestDaemonEverythingExample(c *C) { 1511 y := []byte(`name: wat 1512 version: 42 1513 apps: 1514 svc: 1515 command: svc1 1516 description: svc one 1517 stop-timeout: 25s 1518 start-timeout: 42m 1519 daemon: forking 1520 daemon-scope: system 1521 stop-command: stop-cmd 1522 post-stop-command: post-stop-cmd 1523 restart-condition: on-abnormal 1524 bus-name: busName 1525 sockets: 1526 sock1: 1527 listen-stream: $SNAP_DATA/sock1.socket 1528 socket-mode: 0666 1529 `) 1530 info, err := snap.InfoFromSnapYaml(y) 1531 c.Assert(err, IsNil) 1532 1533 app := snap.AppInfo{ 1534 Snap: info, 1535 Name: "svc", 1536 Command: "svc1", 1537 Daemon: "forking", 1538 DaemonScope: snap.SystemDaemon, 1539 RestartCond: snap.RestartOnAbnormal, 1540 StopTimeout: timeout.Timeout(25 * time.Second), 1541 StartTimeout: timeout.Timeout(42 * time.Minute), 1542 StopCommand: "stop-cmd", 1543 PostStopCommand: "post-stop-cmd", 1544 BusName: "busName", 1545 Sockets: map[string]*snap.SocketInfo{}, 1546 } 1547 1548 app.Sockets["sock1"] = &snap.SocketInfo{ 1549 App: &app, 1550 Name: "sock1", 1551 ListenStream: "$SNAP_DATA/sock1.socket", 1552 SocketMode: 0666, 1553 } 1554 1555 c.Check(info.Apps, DeepEquals, map[string]*snap.AppInfo{"svc": &app}) 1556 } 1557 1558 func (s *YamlSuite) TestDaemonUserDaemon(c *C) { 1559 y := []byte(`name: wat 1560 version: 42 1561 apps: 1562 svc: 1563 command: svc1 1564 daemon: simple 1565 daemon-scope: user 1566 `) 1567 info, err := snap.InfoFromSnapYaml(y) 1568 c.Assert(err, IsNil) 1569 c.Check(info.Apps["svc"].DaemonScope, Equals, snap.UserDaemon) 1570 } 1571 1572 func (s *YamlSuite) TestDaemonNoDaemonScope(c *C) { 1573 y := []byte(`name: wat 1574 version: 42 1575 apps: 1576 svc: 1577 command: svc1 1578 daemon: simple 1579 `) 1580 info, err := snap.InfoFromSnapYaml(y) 1581 c.Assert(err, IsNil) 1582 1583 // If daemon-scope is unset, default to system scope 1584 c.Check(info.Apps["svc"].DaemonScope, Equals, snap.SystemDaemon) 1585 } 1586 1587 func (s *YamlSuite) TestDaemonListenStreamAsInteger(c *C) { 1588 y := []byte(`name: wat 1589 version: 42 1590 apps: 1591 svc: 1592 command: svc 1593 sockets: 1594 sock: 1595 listen-stream: 8080 1596 `) 1597 info, err := snap.InfoFromSnapYaml(y) 1598 c.Assert(err, IsNil) 1599 1600 app := snap.AppInfo{ 1601 Snap: info, 1602 Name: "svc", 1603 Command: "svc", 1604 Sockets: map[string]*snap.SocketInfo{}, 1605 } 1606 1607 app.Sockets["sock"] = &snap.SocketInfo{ 1608 App: &app, 1609 Name: "sock", 1610 ListenStream: "8080", 1611 } 1612 1613 c.Check(info.Apps, DeepEquals, map[string]*snap.AppInfo{ 1614 "svc": &app, 1615 }) 1616 } 1617 1618 func (s *YamlSuite) TestDaemonInvalidSocketMode(c *C) { 1619 y := []byte(`name: wat 1620 version: 42 1621 apps: 1622 svc: 1623 command: svc 1624 sockets: 1625 sock: 1626 listen-stream: 8080 1627 socket-mode: asdfasdf 1628 `) 1629 _, err := snap.InfoFromSnapYaml(y) 1630 c.Check(err.Error(), Matches, "cannot parse snap.yaml: yaml: unmarshal errors:\n"+ 1631 " line 9: cannot unmarshal !!str `asdfasdf` into (os|fs).FileMode") 1632 } 1633 1634 func (s *YamlSuite) TestDaemonInvalidDaemonScope(c *C) { 1635 y := []byte(`name: wat 1636 version: 42 1637 apps: 1638 svc: 1639 command: svc 1640 daemon-scope: invalid 1641 `) 1642 _, err := snap.InfoFromSnapYaml(y) 1643 c.Check(err.Error(), Equals, "cannot parse snap.yaml: invalid daemon scope: \"invalid\"") 1644 } 1645 1646 func (s *YamlSuite) TestSnapYamlGlobalEnvironment(c *C) { 1647 y := []byte(` 1648 name: foo 1649 version: 1.0 1650 environment: 1651 foo: bar 1652 baz: boom 1653 `) 1654 info, err := snap.InfoFromSnapYaml(y) 1655 c.Assert(err, IsNil) 1656 c.Assert(info.Environment, DeepEquals, *strutil.NewOrderedMap("foo", "bar", "baz", "boom")) 1657 } 1658 1659 func (s *YamlSuite) TestSnapYamlPerAppEnvironment(c *C) { 1660 y := []byte(` 1661 name: foo 1662 version: 1.0 1663 apps: 1664 foo: 1665 environment: 1666 k1: v1 1667 k2: v2 1668 `) 1669 info, err := snap.InfoFromSnapYaml(y) 1670 c.Assert(err, IsNil) 1671 c.Assert(info.Apps["foo"].Environment, DeepEquals, *strutil.NewOrderedMap("k1", "v1", "k2", "v2")) 1672 } 1673 1674 func (s *YamlSuite) TestSnapYamlPerHookEnvironment(c *C) { 1675 y := []byte(` 1676 name: foo 1677 version: 1.0 1678 hooks: 1679 foo: 1680 environment: 1681 k1: v1 1682 k2: v2 1683 `) 1684 info, err := snap.InfoFromSnapYaml(y) 1685 c.Assert(err, IsNil) 1686 c.Assert(info.Hooks["foo"].Environment, DeepEquals, *strutil.NewOrderedMap("k1", "v1", "k2", "v2")) 1687 } 1688 1689 // classic confinement 1690 func (s *YamlSuite) TestClassicConfinement(c *C) { 1691 y := []byte(` 1692 name: foo 1693 confinement: classic 1694 `) 1695 info, err := snap.InfoFromSnapYaml(y) 1696 c.Assert(err, IsNil) 1697 c.Assert(info.Confinement, Equals, snap.ClassicConfinement) 1698 } 1699 1700 func (s *YamlSuite) TestSnapYamlAliases(c *C) { 1701 y := []byte(` 1702 name: foo 1703 version: 1.0 1704 apps: 1705 foo: 1706 aliases: [foo] 1707 bar: 1708 aliases: [bar, bar1] 1709 `) 1710 info, err := snap.InfoFromSnapYaml(y) 1711 c.Assert(err, IsNil) 1712 1713 c.Check(info.Apps["foo"].LegacyAliases, DeepEquals, []string{"foo"}) 1714 c.Check(info.Apps["bar"].LegacyAliases, DeepEquals, []string{"bar", "bar1"}) 1715 1716 c.Check(info.LegacyAliases, DeepEquals, map[string]*snap.AppInfo{ 1717 "foo": info.Apps["foo"], 1718 "bar": info.Apps["bar"], 1719 "bar1": info.Apps["bar"], 1720 }) 1721 } 1722 1723 func (s *YamlSuite) TestSnapYamlAliasesConflict(c *C) { 1724 y := []byte(` 1725 name: foo 1726 version: 1.0 1727 apps: 1728 foo: 1729 aliases: [bar] 1730 bar: 1731 aliases: [bar] 1732 `) 1733 _, err := snap.InfoFromSnapYaml(y) 1734 c.Assert(err, ErrorMatches, `cannot set "bar" as alias for both ("foo" and "bar"|"bar" and "foo")`) 1735 } 1736 1737 func (s *YamlSuite) TestSnapYamlAppStartOrder(c *C) { 1738 y := []byte(`name: wat 1739 version: 42 1740 apps: 1741 foo: 1742 after: [bar, zed] 1743 bar: 1744 before: [foo] 1745 baz: 1746 after: [foo] 1747 zed: 1748 1749 `) 1750 info, err := snap.InfoFromSnapYaml(y) 1751 c.Assert(err, IsNil) 1752 1753 c.Check(info.Apps, DeepEquals, map[string]*snap.AppInfo{ 1754 "foo": { 1755 Snap: info, 1756 Name: "foo", 1757 After: []string{"bar", "zed"}, 1758 }, 1759 "bar": { 1760 Snap: info, 1761 Name: "bar", 1762 Before: []string{"foo"}, 1763 }, 1764 "baz": { 1765 Snap: info, 1766 Name: "baz", 1767 After: []string{"foo"}, 1768 }, 1769 "zed": { 1770 Snap: info, 1771 Name: "zed", 1772 }, 1773 }) 1774 } 1775 1776 func (s *YamlSuite) TestSnapYamlWatchdog(c *C) { 1777 y := []byte(` 1778 name: foo 1779 version: 1.0 1780 apps: 1781 foo: 1782 watchdog-timeout: 12s 1783 `) 1784 info, err := snap.InfoFromSnapYaml(y) 1785 c.Assert(err, IsNil) 1786 1787 c.Check(info.Apps["foo"].WatchdogTimeout, Equals, timeout.Timeout(12*time.Second)) 1788 } 1789 1790 func (s *YamlSuite) TestLayout(c *C) { 1791 y := []byte(` 1792 name: foo 1793 version: 1.0 1794 layout: 1795 /usr/share/foo: 1796 bind: $SNAP/usr/share/foo 1797 /usr/share/bar: 1798 symlink: $SNAP/usr/share/bar 1799 /etc/froz: 1800 bind-file: $SNAP/etc/froz 1801 `) 1802 info, err := snap.InfoFromSnapYaml(y) 1803 c.Assert(err, IsNil) 1804 c.Assert(info.Layout["/usr/share/foo"], DeepEquals, &snap.Layout{ 1805 Snap: info, 1806 Path: "/usr/share/foo", 1807 Bind: "$SNAP/usr/share/foo", 1808 User: "root", 1809 Group: "root", 1810 Mode: 0755, 1811 }) 1812 c.Assert(info.Layout["/usr/share/bar"], DeepEquals, &snap.Layout{ 1813 Snap: info, 1814 Path: "/usr/share/bar", 1815 Symlink: "$SNAP/usr/share/bar", 1816 User: "root", 1817 Group: "root", 1818 Mode: 0755, 1819 }) 1820 c.Assert(info.Layout["/etc/froz"], DeepEquals, &snap.Layout{ 1821 Snap: info, 1822 Path: "/etc/froz", 1823 BindFile: "$SNAP/etc/froz", 1824 User: "root", 1825 Group: "root", 1826 Mode: 0755, 1827 }) 1828 } 1829 1830 func (s *YamlSuite) TestLayoutsWithTypo(c *C) { 1831 y := []byte(` 1832 name: foo 1833 version: 1.0 1834 layouts: 1835 /usr/share/foo: 1836 bind: $SNAP/usr/share/foo 1837 `) 1838 info, err := snap.InfoFromSnapYaml(y) 1839 c.Assert(err, ErrorMatches, `cannot parse snap.yaml: typo detected: use singular "layout" instead of plural "layouts"`) 1840 c.Assert(info, IsNil) 1841 } 1842 1843 func (s *YamlSuite) TestSnapYamlAppTimer(c *C) { 1844 y := []byte(`name: wat 1845 version: 42 1846 apps: 1847 foo: 1848 daemon: oneshot 1849 timer: mon,10:00-12:00 1850 1851 `) 1852 info, err := snap.InfoFromSnapYaml(y) 1853 c.Assert(err, IsNil) 1854 app := info.Apps["foo"] 1855 c.Check(app.Timer, DeepEquals, &snap.TimerInfo{App: app, Timer: "mon,10:00-12:00"}) 1856 } 1857 1858 func (s *YamlSuite) TestSnapYamlAppAutostart(c *C) { 1859 yAutostart := []byte(`name: wat 1860 version: 42 1861 apps: 1862 foo: 1863 command: bin/foo 1864 autostart: foo.desktop 1865 1866 `) 1867 info, err := snap.InfoFromSnapYaml(yAutostart) 1868 c.Assert(err, IsNil) 1869 app := info.Apps["foo"] 1870 c.Check(app.Autostart, Equals, "foo.desktop") 1871 1872 yNoAutostart := []byte(`name: wat 1873 version: 42 1874 apps: 1875 foo: 1876 command: bin/foo 1877 1878 `) 1879 info, err = snap.InfoFromSnapYaml(yNoAutostart) 1880 c.Assert(err, IsNil) 1881 app = info.Apps["foo"] 1882 c.Check(app.Autostart, Equals, "") 1883 } 1884 1885 func (s *YamlSuite) TestSnapYamlAppCommonID(c *C) { 1886 yAutostart := []byte(`name: wat 1887 version: 42 1888 apps: 1889 foo: 1890 command: bin/foo 1891 common-id: org.foo 1892 bar: 1893 command: bin/foo 1894 common-id: org.bar 1895 baz: 1896 command: bin/foo 1897 1898 `) 1899 info, err := snap.InfoFromSnapYaml(yAutostart) 1900 c.Assert(err, IsNil) 1901 c.Check(info.Apps["foo"].CommonID, Equals, "org.foo") 1902 c.Check(info.Apps["bar"].CommonID, Equals, "org.bar") 1903 c.Check(info.Apps["baz"].CommonID, Equals, "") 1904 c.Assert(info.CommonIDs, HasLen, 2) 1905 c.Assert((info.CommonIDs[0] == "org.foo" && info.CommonIDs[1] == "org.bar") || 1906 (info.CommonIDs[1] == "org.foo" && info.CommonIDs[0] == "org.bar"), 1907 Equals, 1908 true) 1909 } 1910 1911 func (s *YamlSuite) TestSnapYamlCommandChain(c *C) { 1912 yAutostart := []byte(`name: wat 1913 version: 42 1914 apps: 1915 foo: 1916 command: bin/foo 1917 command-chain: [chain1, chain2] 1918 hooks: 1919 configure: 1920 command-chain: [hookchain1, hookchain2] 1921 `) 1922 info, err := snap.InfoFromSnapYaml(yAutostart) 1923 c.Assert(err, IsNil) 1924 app := info.Apps["foo"] 1925 c.Check(app.CommandChain, DeepEquals, []string{"chain1", "chain2"}) 1926 hook := info.Hooks["configure"] 1927 c.Check(hook.CommandChain, DeepEquals, []string{"hookchain1", "hookchain2"}) 1928 } 1929 1930 func (s *YamlSuite) TestSnapYamlRestartDelay(c *C) { 1931 yAutostart := []byte(`name: wat 1932 version: 42 1933 apps: 1934 foo: 1935 command: bin/foo 1936 daemon: simple 1937 restart-delay: 12s 1938 `) 1939 info, err := snap.InfoFromSnapYaml(yAutostart) 1940 c.Assert(err, IsNil) 1941 app := info.Apps["foo"] 1942 c.Assert(app, NotNil) 1943 c.Check(app.RestartDelay, Equals, timeout.Timeout(12*time.Second)) 1944 } 1945 1946 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsing(c *C) { 1947 y := []byte(`name: binary 1948 version: 1.0 1949 system-usernames: 1950 foo: shared 1951 bar: 1952 scope: external 1953 baz: 1954 scope: private 1955 attr1: norf 1956 attr2: corge 1957 attr3: "" 1958 `) 1959 info, err := snap.InfoFromSnapYaml(y) 1960 c.Assert(err, IsNil) 1961 c.Check(info.SystemUsernames, HasLen, 3) 1962 c.Assert(info.SystemUsernames["foo"], DeepEquals, &snap.SystemUsernameInfo{ 1963 Name: "foo", 1964 Scope: "shared", 1965 }) 1966 c.Assert(info.SystemUsernames["bar"], DeepEquals, &snap.SystemUsernameInfo{ 1967 Name: "bar", 1968 Scope: "external", 1969 }) 1970 c.Assert(info.SystemUsernames["baz"], DeepEquals, &snap.SystemUsernameInfo{ 1971 Name: "baz", 1972 Scope: "private", 1973 Attrs: map[string]interface{}{ 1974 "attr1": "norf", 1975 "attr2": "corge", 1976 "attr3": "", 1977 }, 1978 }) 1979 } 1980 1981 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadType(c *C) { 1982 y := []byte(`name: binary 1983 version: 1.0 1984 system-usernames: 1985 a: true 1986 `) 1987 info, err := snap.InfoFromSnapYaml(y) 1988 c.Assert(err, ErrorMatches, `system username "a" has malformed definition \(found bool\)`) 1989 c.Assert(info, IsNil) 1990 } 1991 1992 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadValue(c *C) { 1993 y := []byte(`name: binary 1994 version: 1.0 1995 system-usernames: 1996 a: [b, c] 1997 `) 1998 info, err := snap.InfoFromSnapYaml(y) 1999 c.Assert(err, ErrorMatches, `system username "a" has malformed definition \(found \[\]interface {}\)`) 2000 c.Assert(info, IsNil) 2001 } 2002 2003 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadKeyEmpty(c *C) { 2004 y := []byte(`name: binary 2005 version: 1.0 2006 system-usernames: 2007 "": shared 2008 `) 2009 _, err := snap.InfoFromSnapYaml(y) 2010 c.Assert(err, ErrorMatches, `system username cannot be empty`) 2011 } 2012 2013 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadKeyList(c *C) { 2014 y := []byte(`name: binary 2015 version: 1.0 2016 system-usernames: 2017 - foo: shared 2018 `) 2019 _, err := snap.InfoFromSnapYaml(y) 2020 c.Assert(err, ErrorMatches, `(?m)cannot parse snap.yaml:.*`) 2021 } 2022 2023 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadValueEmpty(c *C) { 2024 y := []byte(`name: binary 2025 version: 1.0 2026 system-usernames: 2027 a: "" 2028 `) 2029 _, err := snap.InfoFromSnapYaml(y) 2030 c.Assert(err, ErrorMatches, `system username "a" does not specify a scope`) 2031 } 2032 2033 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadValueNull(c *C) { 2034 y := []byte(`name: binary 2035 version: 1.0 2036 system-usernames: 2037 a: null 2038 `) 2039 _, err := snap.InfoFromSnapYaml(y) 2040 c.Assert(err, ErrorMatches, `system username "a" does not specify a scope`) 2041 } 2042 2043 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadAttrKeyEmpty(c *C) { 2044 y := []byte(`name: binary 2045 version: 1.0 2046 system-usernames: 2047 foo: 2048 scope: shared 2049 "": bar 2050 `) 2051 _, err := snap.InfoFromSnapYaml(y) 2052 c.Assert(err, ErrorMatches, `system username "foo" has an empty attribute key`) 2053 } 2054 2055 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadAttrKeyNonString(c *C) { 2056 y := []byte(`name: binary 2057 version: 1.0 2058 system-usernames: 2059 foo: 2060 scope: shared 2061 1: bar 2062 `) 2063 _, err := snap.InfoFromSnapYaml(y) 2064 c.Assert(err, ErrorMatches, `system username "foo" has attribute key that is not a string \(found int\)`) 2065 } 2066 2067 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadAttrValue(c *C) { 2068 y := []byte(`name: binary 2069 version: 1.0 2070 system-usernames: 2071 foo: 2072 scope: shared 2073 bar: null 2074 `) 2075 _, err := snap.InfoFromSnapYaml(y) 2076 c.Assert(err, ErrorMatches, `attribute "bar" of system username "foo": invalid scalar:.*`) 2077 } 2078 2079 func (s *YamlSuite) TestSnapYamlSystemUsernamesParsingBadScopeNonString(c *C) { 2080 y := []byte(`name: binary 2081 version: 1.0 2082 system-usernames: 2083 foo: 2084 scope: 10 2085 `) 2086 _, err := snap.InfoFromSnapYaml(y) 2087 c.Assert(err, ErrorMatches, `scope on system username "foo" is not a string \(found int\)`) 2088 } 2089 2090 func (s *YamlSuite) TestSnapYamlLinks(c *C) { 2091 yLinks := []byte(`name: my-snap 2092 version: 1.0 2093 2094 links: 2095 donations: 2096 - https://donate.me 2097 contact: 2098 - mailto:me@toto.space 2099 - https://toto.space 2100 bug-url: 2101 - https://github.com/webteam-space/toto.space/issues 2102 website: 2103 - https://toto.space 2104 source-code: 2105 - https://github.com/webteam-space/toto.space 2106 `) 2107 info, err := snap.InfoFromSnapYaml(yLinks) 2108 c.Assert(err, IsNil) 2109 c.Check(info.Links(), DeepEquals, map[string][]string{ 2110 "bug-url": {"https://github.com/webteam-space/toto.space/issues"}, 2111 "contact": {"mailto:me@toto.space", "https://toto.space"}, 2112 "donations": {"https://donate.me"}, 2113 "source-code": {"https://github.com/webteam-space/toto.space"}, 2114 "website": {"https://toto.space"}, 2115 }) 2116 c.Check(info.Contact(), Equals, "mailto:me@toto.space") 2117 } 2118 2119 func (s *YamlSuite) TestSnapYamlEmptyLinksKey(c *C) { 2120 yLinks := []byte(`name: my-snap 2121 version: 1.0 2122 2123 links: 2124 "": 2125 - htps://toto.space 2126 `) 2127 _, err := snap.InfoFromSnapYaml(yLinks) 2128 c.Check(err, ErrorMatches, `links key cannot be empty`) 2129 } 2130 2131 func (s *YamlSuite) TestSnapYamlInvalidLinksKey(c *C) { 2132 yLinks := `name: my-snap 2133 version: 1.0 2134 2135 links: 2136 %s: 2137 - link.website 2138 ` 2139 2140 invalid := []string{ 2141 "--", 2142 "1-2", 2143 "aa-", 2144 } 2145 2146 for _, k := range invalid { 2147 _, err := snap.InfoFromSnapYaml([]byte(fmt.Sprintf(yLinks, k))) 2148 c.Check(err, ErrorMatches, fmt.Sprintf(`links key is invalid: %s`, k)) 2149 } 2150 }