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