gitee.com/mysnapcore/mysnapd@v0.1.0/daemon/api_connections_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019-2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package daemon_test 21 22 import ( 23 "encoding/json" 24 "fmt" 25 "net/http" 26 "net/http/httptest" 27 28 "gopkg.in/check.v1" 29 30 "gitee.com/mysnapcore/mysnapd/daemon" 31 "gitee.com/mysnapcore/mysnapd/interfaces" 32 "gitee.com/mysnapcore/mysnapd/interfaces/builtin" 33 "gitee.com/mysnapcore/mysnapd/interfaces/ifacetest" 34 "gitee.com/mysnapcore/mysnapd/strutil" 35 ) 36 37 // Tests for GET /v2/connections 38 39 func (s *interfacesSuite) testConnectionsConnected(c *check.C, d *daemon.Daemon, query string, connsState map[string]interface{}, repoConnected []string, expected map[string]interface{}) { 40 repo := d.Overlord().InterfaceManager().Repository() 41 for crefStr, cstate := range connsState { 42 // if repoConnected is defined, then given connection must be on 43 // list, otherwise it's not going to be connected in the repository 44 // to simulate missing plugs/slots. 45 if repoConnected != nil && !strutil.ListContains(repoConnected, crefStr) { 46 continue 47 } 48 cref, err := interfaces.ParseConnRef(crefStr) 49 c.Assert(err, check.IsNil) 50 conn := cstate.(map[string]interface{}) 51 if undesiredRaw, ok := conn["undesired"]; ok { 52 undesired, ok := undesiredRaw.(bool) 53 c.Assert(ok, check.Equals, true, check.Commentf("unexpected value for key 'undesired': %v", cstate)) 54 if undesired { 55 // do not add connections that are undesired 56 continue 57 } 58 } 59 staticPlugAttrs, _ := conn["plug-static"].(map[string]interface{}) 60 dynamicPlugAttrs, _ := conn["plug-dynamic"].(map[string]interface{}) 61 staticSlotAttrs, _ := conn["slot-static"].(map[string]interface{}) 62 dynamicSlotAttrs, _ := conn["slot-dynamic"].(map[string]interface{}) 63 _, err = repo.Connect(cref, staticPlugAttrs, dynamicPlugAttrs, staticSlotAttrs, dynamicSlotAttrs, nil) 64 c.Assert(err, check.IsNil) 65 } 66 67 st := d.Overlord().State() 68 st.Lock() 69 st.Set("conns", connsState) 70 st.Unlock() 71 72 s.testConnections(c, query, expected) 73 } 74 75 func (s *interfacesSuite) testConnections(c *check.C, query string, expected map[string]interface{}) { 76 req, err := http.NewRequest("GET", query, nil) 77 c.Assert(err, check.IsNil) 78 rec := httptest.NewRecorder() 79 s.req(c, req, nil).ServeHTTP(rec, req) 80 c.Check(rec.Code, check.Equals, 200) 81 var body map[string]interface{} 82 err = json.Unmarshal(rec.Body.Bytes(), &body) 83 c.Check(err, check.IsNil) 84 c.Check(body, check.DeepEquals, expected) 85 } 86 87 func (s *interfacesSuite) TestConnectionsUnhappy(c *check.C) { 88 s.daemon(c) 89 req, err := http.NewRequest("GET", "/v2/connections?select=bad", nil) 90 c.Assert(err, check.IsNil) 91 rec := httptest.NewRecorder() 92 s.req(c, req, nil).ServeHTTP(rec, req) 93 c.Check(rec.Code, check.Equals, 400) 94 var body map[string]interface{} 95 err = json.Unmarshal(rec.Body.Bytes(), &body) 96 c.Check(err, check.IsNil) 97 c.Check(body, check.DeepEquals, map[string]interface{}{ 98 "result": map[string]interface{}{ 99 "message": "unsupported select qualifier", 100 }, 101 "status": "Bad Request", 102 "status-code": 400.0, 103 "type": "error", 104 }) 105 } 106 107 func (s *interfacesSuite) TestConnectionsEmpty(c *check.C) { 108 s.daemon(c) 109 s.testConnections(c, "/v2/connections", map[string]interface{}{ 110 "result": map[string]interface{}{ 111 "established": []interface{}{}, 112 "plugs": []interface{}{}, 113 "slots": []interface{}{}, 114 }, 115 "status": "OK", 116 "status-code": 200.0, 117 "type": "sync", 118 }) 119 s.testConnections(c, "/v2/connections?select=all", map[string]interface{}{ 120 "result": map[string]interface{}{ 121 "established": []interface{}{}, 122 "plugs": []interface{}{}, 123 "slots": []interface{}{}, 124 }, 125 "status": "OK", 126 "status-code": 200.0, 127 "type": "sync", 128 }) 129 } 130 131 func (s *interfacesSuite) TestConnectionsNotFound(c *check.C) { 132 s.daemon(c) 133 req, err := http.NewRequest("GET", "/v2/connections?snap=not-found", nil) 134 c.Assert(err, check.IsNil) 135 rec := httptest.NewRecorder() 136 s.req(c, req, nil).ServeHTTP(rec, req) 137 c.Check(rec.Code, check.Equals, 404) 138 var body map[string]interface{} 139 err = json.Unmarshal(rec.Body.Bytes(), &body) 140 c.Check(err, check.IsNil) 141 c.Check(body, check.DeepEquals, map[string]interface{}{ 142 "result": map[string]interface{}{ 143 "message": `no state entry for key "snaps"`, 144 "kind": "snap-not-found", 145 "value": "not-found", 146 }, 147 "status": "Not Found", 148 "status-code": 404.0, 149 "type": "error", 150 }) 151 } 152 153 func (s *interfacesSuite) TestConnectionsUnconnected(c *check.C) { 154 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 155 defer restore() 156 157 s.daemon(c) 158 159 s.mockSnap(c, consumerYaml) 160 s.mockSnap(c, producerYaml) 161 162 s.testConnections(c, "/v2/connections?select=all", map[string]interface{}{ 163 "result": map[string]interface{}{ 164 "established": []interface{}{}, 165 "plugs": []interface{}{ 166 map[string]interface{}{ 167 "snap": "consumer", 168 "plug": "plug", 169 "interface": "test", 170 "attrs": map[string]interface{}{"key": "value"}, 171 "apps": []interface{}{"app"}, 172 "label": "label", 173 }, 174 }, 175 "slots": []interface{}{ 176 map[string]interface{}{ 177 "snap": "producer", 178 "slot": "slot", 179 "interface": "test", 180 "attrs": map[string]interface{}{"key": "value"}, 181 "apps": []interface{}{"app"}, 182 "label": "label", 183 }, 184 }, 185 }, 186 "status": "OK", 187 "status-code": 200.0, 188 "type": "sync", 189 }) 190 } 191 192 func (s *interfacesSuite) TestConnectionsBySnapName(c *check.C) { 193 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 194 defer restore() 195 196 d := s.daemon(c) 197 198 s.mockSnap(c, consumerYaml) 199 s.mockSnap(c, producerYaml) 200 201 s.testConnections(c, "/v2/connections?select=all&snap=producer", map[string]interface{}{ 202 "result": map[string]interface{}{ 203 "established": []interface{}{}, 204 "slots": []interface{}{ 205 map[string]interface{}{ 206 "snap": "producer", 207 "slot": "slot", 208 "interface": "test", 209 "attrs": map[string]interface{}{"key": "value"}, 210 "apps": []interface{}{"app"}, 211 "label": "label", 212 }, 213 }, 214 "plugs": []interface{}{}, 215 }, 216 "status": "OK", 217 "status-code": 200.0, 218 "type": "sync", 219 }) 220 221 s.testConnections(c, "/v2/connections?select=all&snap=consumer", map[string]interface{}{ 222 "result": map[string]interface{}{ 223 "established": []interface{}{}, 224 "plugs": []interface{}{ 225 map[string]interface{}{ 226 "snap": "consumer", 227 "plug": "plug", 228 "interface": "test", 229 "attrs": map[string]interface{}{"key": "value"}, 230 "apps": []interface{}{"app"}, 231 "label": "label", 232 }, 233 }, 234 "slots": []interface{}{}, 235 }, 236 "status": "OK", 237 "status-code": 200.0, 238 "type": "sync", 239 }) 240 241 s.testConnectionsConnected(c, d, "/v2/connections?snap=producer", map[string]interface{}{ 242 "consumer:plug producer:slot": map[string]interface{}{ 243 "interface": "test", 244 }, 245 }, nil, map[string]interface{}{ 246 "result": map[string]interface{}{ 247 "plugs": []interface{}{ 248 map[string]interface{}{ 249 "snap": "consumer", 250 "plug": "plug", 251 "interface": "test", 252 "attrs": map[string]interface{}{"key": "value"}, 253 "apps": []interface{}{"app"}, 254 "label": "label", 255 "connections": []interface{}{ 256 map[string]interface{}{"snap": "producer", "slot": "slot"}, 257 }, 258 }, 259 }, 260 "slots": []interface{}{ 261 map[string]interface{}{ 262 "snap": "producer", 263 "slot": "slot", 264 "interface": "test", 265 "attrs": map[string]interface{}{"key": "value"}, 266 "apps": []interface{}{"app"}, 267 "label": "label", 268 "connections": []interface{}{ 269 map[string]interface{}{"snap": "consumer", "plug": "plug"}, 270 }, 271 }, 272 }, 273 "established": []interface{}{ 274 map[string]interface{}{ 275 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 276 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 277 "manual": true, 278 "interface": "test", 279 }, 280 }, 281 }, 282 "status": "OK", 283 "status-code": 200.0, 284 "type": "sync", 285 }) 286 } 287 288 func (s *interfacesSuite) TestConnectionsMissingPlugSlotFilteredOut(c *check.C) { 289 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 290 defer restore() 291 292 d := s.daemon(c) 293 294 s.mockSnap(c, consumerYaml) 295 s.mockSnap(c, producerYaml) 296 297 for _, missingPlugOrSlot := range []string{"consumer:plug2 producer:slot", "consumer:plug producer:slot2"} { 298 s.testConnectionsConnected(c, d, "/v2/connections?snap=producer", map[string]interface{}{ 299 "consumer:plug producer:slot": map[string]interface{}{ 300 "interface": "test", 301 }, 302 missingPlugOrSlot: map[string]interface{}{ 303 "interface": "test", 304 }, 305 }, 306 []string{"consumer:plug producer:slot"}, 307 map[string]interface{}{ 308 "result": map[string]interface{}{ 309 "plugs": []interface{}{ 310 map[string]interface{}{ 311 "snap": "consumer", 312 "plug": "plug", 313 "interface": "test", 314 "attrs": map[string]interface{}{"key": "value"}, 315 "apps": []interface{}{"app"}, 316 "label": "label", 317 "connections": []interface{}{ 318 map[string]interface{}{"snap": "producer", "slot": "slot"}, 319 }, 320 }, 321 }, 322 "slots": []interface{}{ 323 map[string]interface{}{ 324 "snap": "producer", 325 "slot": "slot", 326 "interface": "test", 327 "attrs": map[string]interface{}{"key": "value"}, 328 "apps": []interface{}{"app"}, 329 "label": "label", 330 "connections": []interface{}{ 331 map[string]interface{}{"snap": "consumer", "plug": "plug"}, 332 }, 333 }, 334 }, 335 "established": []interface{}{ 336 map[string]interface{}{ 337 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 338 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 339 "manual": true, 340 "interface": "test", 341 }, 342 }, 343 }, 344 "status": "OK", 345 "status-code": 200.0, 346 "type": "sync", 347 }) 348 } 349 } 350 351 func (s *interfacesSuite) TestConnectionsBySnapAlias(c *check.C) { 352 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 353 defer restore() 354 355 d := s.daemon(c) 356 357 s.mockSnap(c, consumerYaml) 358 s.mockSnap(c, coreProducerYaml) 359 360 expectedUnconnected := map[string]interface{}{ 361 "established": []interface{}{}, 362 "slots": []interface{}{ 363 map[string]interface{}{ 364 "snap": "core", 365 "slot": "slot", 366 "interface": "test", 367 "attrs": map[string]interface{}{"key": "value"}, 368 "label": "label", 369 }, 370 }, 371 "plugs": []interface{}{}, 372 } 373 s.testConnections(c, "/v2/connections?select=all&snap=core", map[string]interface{}{ 374 "result": expectedUnconnected, 375 "status": "OK", 376 "status-code": 200.0, 377 "type": "sync", 378 }) 379 // try using a well know alias 380 s.testConnections(c, "/v2/connections?select=all&snap=system", map[string]interface{}{ 381 "result": expectedUnconnected, 382 "status": "OK", 383 "status-code": 200.0, 384 "type": "sync", 385 }) 386 387 expectedConnmected := map[string]interface{}{ 388 "plugs": []interface{}{ 389 map[string]interface{}{ 390 "snap": "consumer", 391 "plug": "plug", 392 "interface": "test", 393 "attrs": map[string]interface{}{"key": "value"}, 394 "apps": []interface{}{"app"}, 395 "label": "label", 396 "connections": []interface{}{ 397 map[string]interface{}{"snap": "core", "slot": "slot"}, 398 }, 399 }, 400 }, 401 "slots": []interface{}{ 402 map[string]interface{}{ 403 "snap": "core", 404 "slot": "slot", 405 "interface": "test", 406 "attrs": map[string]interface{}{"key": "value"}, 407 "label": "label", 408 "connections": []interface{}{ 409 map[string]interface{}{"snap": "consumer", "plug": "plug"}, 410 }, 411 }, 412 }, 413 "established": []interface{}{ 414 map[string]interface{}{ 415 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 416 "slot": map[string]interface{}{"snap": "core", "slot": "slot"}, 417 "manual": true, 418 "interface": "test", 419 }, 420 }, 421 } 422 423 s.testConnectionsConnected(c, d, "/v2/connections?snap=core", map[string]interface{}{ 424 "consumer:plug core:slot": map[string]interface{}{ 425 "interface": "test", 426 }, 427 }, nil, map[string]interface{}{ 428 "result": expectedConnmected, 429 "status": "OK", 430 "status-code": 200.0, 431 "type": "sync", 432 }) 433 // connection was already established 434 s.testConnections(c, "/v2/connections?snap=system", map[string]interface{}{ 435 "result": expectedConnmected, 436 "status": "OK", 437 "status-code": 200.0, 438 "type": "sync", 439 }) 440 } 441 442 func (s *interfacesSuite) TestConnectionsByIfaceName(c *check.C) { 443 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 444 defer restore() 445 restore = builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "different"}) 446 defer restore() 447 448 d := s.daemon(c) 449 450 s.mockSnap(c, consumerYaml) 451 s.mockSnap(c, producerYaml) 452 var differentProducerYaml = ` 453 name: different-producer 454 version: 1 455 apps: 456 app: 457 slots: 458 slot: 459 interface: different 460 key: value 461 label: label 462 ` 463 var differentConsumerYaml = ` 464 name: different-consumer 465 version: 1 466 apps: 467 app: 468 plugs: 469 plug: 470 interface: different 471 key: value 472 label: label 473 ` 474 s.mockSnap(c, differentProducerYaml) 475 s.mockSnap(c, differentConsumerYaml) 476 477 s.testConnections(c, "/v2/connections?select=all&interface=test", map[string]interface{}{ 478 "result": map[string]interface{}{ 479 "established": []interface{}{}, 480 "plugs": []interface{}{ 481 map[string]interface{}{ 482 "snap": "consumer", 483 "plug": "plug", 484 "interface": "test", 485 "attrs": map[string]interface{}{"key": "value"}, 486 "apps": []interface{}{"app"}, 487 "label": "label", 488 }, 489 }, 490 "slots": []interface{}{ 491 map[string]interface{}{ 492 "snap": "producer", 493 "slot": "slot", 494 "interface": "test", 495 "attrs": map[string]interface{}{"key": "value"}, 496 "apps": []interface{}{"app"}, 497 "label": "label", 498 }, 499 }, 500 }, 501 "status": "OK", 502 "status-code": 200.0, 503 "type": "sync", 504 }) 505 s.testConnections(c, "/v2/connections?select=all&interface=different", map[string]interface{}{ 506 "result": map[string]interface{}{ 507 "established": []interface{}{}, 508 "plugs": []interface{}{ 509 map[string]interface{}{ 510 "snap": "different-consumer", 511 "plug": "plug", 512 "interface": "different", 513 "attrs": map[string]interface{}{"key": "value"}, 514 "apps": []interface{}{"app"}, 515 "label": "label", 516 }, 517 }, 518 "slots": []interface{}{ 519 map[string]interface{}{ 520 "snap": "different-producer", 521 "slot": "slot", 522 "interface": "different", 523 "attrs": map[string]interface{}{"key": "value"}, 524 "apps": []interface{}{"app"}, 525 "label": "label", 526 }, 527 }, 528 }, 529 "status": "OK", 530 "status-code": 200.0, 531 "type": "sync", 532 }) 533 534 // modifies state internally 535 s.testConnectionsConnected(c, d, "/v2/connections?interfaces=test", map[string]interface{}{ 536 "consumer:plug producer:slot": map[string]interface{}{ 537 "interface": "test", 538 }, 539 }, nil, map[string]interface{}{ 540 "result": map[string]interface{}{ 541 "plugs": []interface{}{ 542 map[string]interface{}{ 543 "snap": "consumer", 544 "plug": "plug", 545 "interface": "test", 546 "attrs": map[string]interface{}{"key": "value"}, 547 "apps": []interface{}{"app"}, 548 "label": "label", 549 "connections": []interface{}{ 550 map[string]interface{}{"snap": "producer", "slot": "slot"}, 551 }, 552 }, 553 }, 554 "slots": []interface{}{ 555 map[string]interface{}{ 556 "snap": "producer", 557 "slot": "slot", 558 "interface": "test", 559 "attrs": map[string]interface{}{"key": "value"}, 560 "apps": []interface{}{"app"}, 561 "label": "label", 562 "connections": []interface{}{ 563 map[string]interface{}{"snap": "consumer", "plug": "plug"}, 564 }, 565 }, 566 }, 567 "established": []interface{}{ 568 map[string]interface{}{ 569 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 570 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 571 "manual": true, 572 "interface": "test", 573 }, 574 }, 575 }, 576 "status": "OK", 577 "status-code": 200.0, 578 "type": "sync", 579 }) 580 // use state modified by previous cal 581 s.testConnections(c, "/v2/connections?interface=different", map[string]interface{}{ 582 "result": map[string]interface{}{ 583 "established": []interface{}{}, 584 "slots": []interface{}{}, 585 "plugs": []interface{}{}, 586 }, 587 "status": "OK", 588 "status-code": 200.0, 589 "type": "sync", 590 }) 591 } 592 593 func (s *interfacesSuite) TestConnectionsDefaultManual(c *check.C) { 594 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 595 defer restore() 596 597 d := s.daemon(c) 598 599 s.mockSnap(c, consumerYaml) 600 s.mockSnap(c, producerYaml) 601 602 s.testConnectionsConnected(c, d, "/v2/connections", map[string]interface{}{ 603 "consumer:plug producer:slot": map[string]interface{}{ 604 "interface": "test", 605 }, 606 }, nil, map[string]interface{}{ 607 "result": map[string]interface{}{ 608 "plugs": []interface{}{ 609 map[string]interface{}{ 610 "snap": "consumer", 611 "plug": "plug", 612 "interface": "test", 613 "attrs": map[string]interface{}{"key": "value"}, 614 "apps": []interface{}{"app"}, 615 "label": "label", 616 "connections": []interface{}{ 617 map[string]interface{}{"snap": "producer", "slot": "slot"}, 618 }, 619 }, 620 }, 621 "slots": []interface{}{ 622 map[string]interface{}{ 623 "snap": "producer", 624 "slot": "slot", 625 "interface": "test", 626 "attrs": map[string]interface{}{"key": "value"}, 627 "apps": []interface{}{"app"}, 628 "label": "label", 629 "connections": []interface{}{ 630 map[string]interface{}{"snap": "consumer", "plug": "plug"}, 631 }, 632 }, 633 }, 634 "established": []interface{}{ 635 map[string]interface{}{ 636 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 637 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 638 "manual": true, 639 "interface": "test", 640 }, 641 }, 642 }, 643 "status": "OK", 644 "status-code": 200.0, 645 "type": "sync", 646 }) 647 } 648 649 func (s *interfacesSuite) TestConnectionsDefaultAuto(c *check.C) { 650 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 651 defer restore() 652 653 d := s.daemon(c) 654 655 s.mockSnap(c, consumerYaml) 656 s.mockSnap(c, producerYaml) 657 658 s.testConnectionsConnected(c, d, "/v2/connections", map[string]interface{}{ 659 "consumer:plug producer:slot": map[string]interface{}{ 660 "interface": "test", 661 "auto": true, 662 "plug-static": map[string]interface{}{ 663 "key": "value", 664 }, 665 "plug-dynamic": map[string]interface{}{ 666 "foo-plug-dynamic": "bar-dynamic", 667 }, 668 "slot-static": map[string]interface{}{ 669 "key": "value", 670 }, 671 "slot-dynamic": map[string]interface{}{ 672 "foo-slot-dynamic": "bar-dynamic", 673 }, 674 }, 675 }, nil, map[string]interface{}{ 676 "result": map[string]interface{}{ 677 "plugs": []interface{}{ 678 map[string]interface{}{ 679 "snap": "consumer", 680 "plug": "plug", 681 "interface": "test", 682 "attrs": map[string]interface{}{"key": "value"}, 683 "apps": []interface{}{"app"}, 684 "label": "label", 685 "connections": []interface{}{ 686 map[string]interface{}{"snap": "producer", "slot": "slot"}, 687 }, 688 }, 689 }, 690 "slots": []interface{}{ 691 map[string]interface{}{ 692 "snap": "producer", 693 "slot": "slot", 694 "interface": "test", 695 "attrs": map[string]interface{}{"key": "value"}, 696 "apps": []interface{}{"app"}, 697 "label": "label", 698 "connections": []interface{}{ 699 map[string]interface{}{"snap": "consumer", "plug": "plug"}, 700 }, 701 }, 702 }, 703 "established": []interface{}{ 704 map[string]interface{}{ 705 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 706 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 707 "interface": "test", 708 "plug-attrs": map[string]interface{}{ 709 "key": "value", 710 "foo-plug-dynamic": "bar-dynamic", 711 }, 712 "slot-attrs": map[string]interface{}{ 713 "key": "value", 714 "foo-slot-dynamic": "bar-dynamic", 715 }, 716 }, 717 }, 718 }, 719 "status": "OK", 720 "status-code": 200.0, 721 "type": "sync", 722 }) 723 } 724 725 func (s *interfacesSuite) TestConnectionsDefaultGadget(c *check.C) { 726 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 727 defer restore() 728 729 d := s.daemon(c) 730 731 s.mockSnap(c, consumerYaml) 732 s.mockSnap(c, producerYaml) 733 734 s.testConnectionsConnected(c, d, "/v2/connections", map[string]interface{}{ 735 "consumer:plug producer:slot": map[string]interface{}{ 736 "interface": "test", 737 "by-gadget": true, 738 "auto": true, 739 }, 740 }, nil, map[string]interface{}{ 741 "result": map[string]interface{}{ 742 "plugs": []interface{}{ 743 map[string]interface{}{ 744 "snap": "consumer", 745 "plug": "plug", 746 "interface": "test", 747 "attrs": map[string]interface{}{"key": "value"}, 748 "apps": []interface{}{"app"}, 749 "label": "label", 750 "connections": []interface{}{ 751 map[string]interface{}{"snap": "producer", "slot": "slot"}, 752 }, 753 }, 754 }, 755 "slots": []interface{}{ 756 map[string]interface{}{ 757 "snap": "producer", 758 "slot": "slot", 759 "interface": "test", 760 "attrs": map[string]interface{}{"key": "value"}, 761 "apps": []interface{}{"app"}, 762 "label": "label", 763 "connections": []interface{}{ 764 map[string]interface{}{"snap": "consumer", "plug": "plug"}, 765 }, 766 }, 767 }, 768 "established": []interface{}{ 769 map[string]interface{}{ 770 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 771 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 772 "gadget": true, 773 "interface": "test", 774 }, 775 }, 776 }, 777 "status": "OK", 778 "status-code": 200.0, 779 "type": "sync", 780 }) 781 } 782 783 func (s *interfacesSuite) TestConnectionsAll(c *check.C) { 784 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 785 defer restore() 786 787 d := s.daemon(c) 788 789 s.mockSnap(c, consumerYaml) 790 s.mockSnap(c, producerYaml) 791 792 s.testConnectionsConnected(c, d, "/v2/connections?select=all", map[string]interface{}{ 793 "consumer:plug producer:slot": map[string]interface{}{ 794 "interface": "test", 795 "by-gadget": true, 796 "auto": true, 797 "undesired": true, 798 }, 799 }, nil, map[string]interface{}{ 800 "result": map[string]interface{}{ 801 "established": []interface{}{}, 802 "plugs": []interface{}{ 803 map[string]interface{}{ 804 "snap": "consumer", 805 "plug": "plug", 806 "interface": "test", 807 "attrs": map[string]interface{}{"key": "value"}, 808 "apps": []interface{}{"app"}, 809 "label": "label", 810 }, 811 }, 812 "slots": []interface{}{ 813 map[string]interface{}{ 814 "snap": "producer", 815 "slot": "slot", 816 "interface": "test", 817 "attrs": map[string]interface{}{"key": "value"}, 818 "apps": []interface{}{"app"}, 819 "label": "label", 820 }, 821 }, 822 "undesired": []interface{}{ 823 map[string]interface{}{ 824 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 825 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 826 "gadget": true, 827 "manual": true, 828 "interface": "test", 829 }, 830 }, 831 }, 832 "status": "OK", 833 "status-code": 200.0, 834 "type": "sync", 835 }) 836 } 837 838 func (s *interfacesSuite) TestConnectionsOnlyUndesired(c *check.C) { 839 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 840 defer restore() 841 842 d := s.daemon(c) 843 844 s.mockSnap(c, consumerYaml) 845 s.mockSnap(c, producerYaml) 846 847 s.testConnectionsConnected(c, d, "/v2/connections", map[string]interface{}{ 848 "consumer:plug producer:slot": map[string]interface{}{ 849 "interface": "test", 850 "by-gadget": true, 851 "auto": true, 852 "undesired": true, 853 }, 854 }, nil, map[string]interface{}{ 855 "result": map[string]interface{}{ 856 "established": []interface{}{}, 857 "plugs": []interface{}{}, 858 "slots": []interface{}{}, 859 }, 860 "status": "OK", 861 "status-code": 200.0, 862 "type": "sync", 863 }) 864 } 865 866 func (s *interfacesSuite) TestConnectionsHotplugGone(c *check.C) { 867 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 868 defer restore() 869 870 d := s.daemon(c) 871 872 s.mockSnap(c, consumerYaml) 873 s.mockSnap(c, producerYaml) 874 875 s.testConnectionsConnected(c, d, "/v2/connections", map[string]interface{}{ 876 "consumer:plug producer:slot": map[string]interface{}{ 877 "interface": "test", 878 "hotplug-gone": true, 879 }, 880 }, nil, map[string]interface{}{ 881 "result": map[string]interface{}{ 882 "established": []interface{}{}, 883 "plugs": []interface{}{}, 884 "slots": []interface{}{}, 885 }, 886 "status": "OK", 887 "status-code": 200.0, 888 "type": "sync", 889 }) 890 } 891 892 func (s *interfacesSuite) TestConnectionsSorted(c *check.C) { 893 restore := builtin.MockInterface(&ifacetest.TestInterface{InterfaceName: "test"}) 894 defer restore() 895 896 d := s.daemon(c) 897 898 var anotherConsumerYaml = ` 899 name: another-consumer-%s 900 version: 1 901 apps: 902 app: 903 plugs: 904 plug: 905 interface: test 906 key: value 907 label: label 908 ` 909 var anotherProducerYaml = ` 910 name: another-producer 911 version: 1 912 apps: 913 app: 914 slots: 915 slot: 916 interface: test 917 key: value 918 label: label 919 ` 920 921 s.mockSnap(c, consumerYaml) 922 s.mockSnap(c, fmt.Sprintf(anotherConsumerYaml, "def")) 923 s.mockSnap(c, fmt.Sprintf(anotherConsumerYaml, "abc")) 924 925 s.mockSnap(c, producerYaml) 926 s.mockSnap(c, anotherProducerYaml) 927 928 s.testConnectionsConnected(c, d, "/v2/connections", map[string]interface{}{ 929 "consumer:plug producer:slot": map[string]interface{}{ 930 "interface": "test", 931 "by-gadget": true, 932 "auto": true, 933 }, 934 "another-consumer-def:plug producer:slot": map[string]interface{}{ 935 "interface": "test", 936 "by-gadget": true, 937 "auto": true, 938 }, 939 "another-consumer-abc:plug producer:slot": map[string]interface{}{ 940 "interface": "test", 941 "by-gadget": true, 942 "auto": true, 943 }, 944 "another-consumer-def:plug another-producer:slot": map[string]interface{}{ 945 "interface": "test", 946 "by-gadget": true, 947 "auto": true, 948 }, 949 }, nil, map[string]interface{}{ 950 "result": map[string]interface{}{ 951 "plugs": []interface{}{ 952 map[string]interface{}{ 953 "snap": "another-consumer-abc", 954 "plug": "plug", 955 "interface": "test", 956 "attrs": map[string]interface{}{"key": "value"}, 957 "apps": []interface{}{"app"}, 958 "label": "label", 959 "connections": []interface{}{ 960 map[string]interface{}{"snap": "producer", "slot": "slot"}, 961 }, 962 }, 963 map[string]interface{}{ 964 "snap": "another-consumer-def", 965 "plug": "plug", 966 "interface": "test", 967 "attrs": map[string]interface{}{"key": "value"}, 968 "apps": []interface{}{"app"}, 969 "label": "label", 970 "connections": []interface{}{ 971 map[string]interface{}{"snap": "another-producer", "slot": "slot"}, 972 map[string]interface{}{"snap": "producer", "slot": "slot"}, 973 }, 974 }, 975 map[string]interface{}{ 976 "snap": "consumer", 977 "plug": "plug", 978 "interface": "test", 979 "attrs": map[string]interface{}{"key": "value"}, 980 "apps": []interface{}{"app"}, 981 "label": "label", 982 "connections": []interface{}{ 983 map[string]interface{}{"snap": "producer", "slot": "slot"}, 984 }, 985 }, 986 }, 987 "slots": []interface{}{ 988 map[string]interface{}{ 989 "snap": "another-producer", 990 "slot": "slot", 991 "interface": "test", 992 "attrs": map[string]interface{}{"key": "value"}, 993 "apps": []interface{}{"app"}, 994 "label": "label", 995 "connections": []interface{}{ 996 map[string]interface{}{"snap": "another-consumer-def", "plug": "plug"}, 997 }, 998 }, 999 map[string]interface{}{ 1000 "snap": "producer", 1001 "slot": "slot", 1002 "interface": "test", 1003 "attrs": map[string]interface{}{"key": "value"}, 1004 "apps": []interface{}{"app"}, 1005 "label": "label", 1006 "connections": []interface{}{ 1007 map[string]interface{}{"snap": "another-consumer-abc", "plug": "plug"}, 1008 map[string]interface{}{"snap": "another-consumer-def", "plug": "plug"}, 1009 map[string]interface{}{"snap": "consumer", "plug": "plug"}, 1010 }, 1011 }, 1012 }, 1013 "established": []interface{}{ 1014 map[string]interface{}{ 1015 "plug": map[string]interface{}{"snap": "another-consumer-abc", "plug": "plug"}, 1016 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 1017 "interface": "test", 1018 "gadget": true, 1019 }, 1020 map[string]interface{}{ 1021 "plug": map[string]interface{}{"snap": "another-consumer-def", "plug": "plug"}, 1022 "slot": map[string]interface{}{"snap": "another-producer", "slot": "slot"}, 1023 "interface": "test", 1024 "gadget": true, 1025 }, 1026 map[string]interface{}{ 1027 "plug": map[string]interface{}{"snap": "another-consumer-def", "plug": "plug"}, 1028 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 1029 "interface": "test", 1030 "gadget": true, 1031 }, 1032 map[string]interface{}{ 1033 "plug": map[string]interface{}{"snap": "consumer", "plug": "plug"}, 1034 "slot": map[string]interface{}{"snap": "producer", "slot": "slot"}, 1035 "interface": "test", 1036 "gadget": true, 1037 }, 1038 }, 1039 }, 1040 "status": "OK", 1041 "status-code": 200.0, 1042 "type": "sync", 1043 }) 1044 }