github.com/juju/juju@v0.0.0-20240430160146-1752b71fcf00/charmhub/refresh_test.go (about) 1 // Copyright 2020 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package charmhub 5 6 import ( 7 "bytes" 8 "context" 9 "io" 10 "net/http" 11 12 "github.com/juju/collections/set" 13 "github.com/juju/errors" 14 "github.com/juju/testing" 15 jc "github.com/juju/testing/checkers" 16 "github.com/juju/utils/v3" 17 "go.uber.org/mock/gomock" 18 gc "gopkg.in/check.v1" 19 20 "github.com/juju/juju/charmhub/path" 21 "github.com/juju/juju/charmhub/transport" 22 "github.com/juju/juju/core/arch" 23 charmmetrics "github.com/juju/juju/core/charm/metrics" 24 ) 25 26 type RefreshSuite struct { 27 testing.IsolationSuite 28 } 29 30 var ( 31 _ = gc.Suite(&RefreshSuite{}) 32 33 expRefreshFields = set.NewStrings( 34 "download", "id", "license", "name", "publisher", "resources", 35 "revision", "summary", "type", "version", "bases", "config-yaml", 36 "metadata-yaml", 37 ).SortedValues() 38 ) 39 40 func (s *RefreshSuite) TestRefresh(c *gc.C) { 41 ctrl := gomock.NewController(c) 42 defer ctrl.Finish() 43 44 baseURL := MustParseURL(c, "http://api.foo.bar") 45 46 baseURLPath := path.MakePath(baseURL) 47 id := "meshuggah" 48 body := transport.RefreshRequest{ 49 Context: []transport.RefreshRequestContext{{ 50 InstanceKey: "instance-key", 51 ID: id, 52 Revision: 1, 53 Base: transport.Base{ 54 Name: "ubuntu", 55 Channel: "20.04", 56 Architecture: arch.DefaultArchitecture, 57 }, 58 TrackingChannel: "latest/stable", 59 }}, 60 Actions: []transport.RefreshRequestAction{{ 61 Action: "refresh", 62 InstanceKey: "instance-key", 63 ID: &id, 64 }}, 65 Fields: expRefreshFields, 66 } 67 68 config, err := RefreshOne("instance-key", id, 1, "latest/stable", RefreshBase{ 69 Name: "ubuntu", 70 Channel: "20.04", 71 Architecture: arch.DefaultArchitecture, 72 }) 73 c.Assert(err, jc.ErrorIsNil) 74 75 restClient := NewMockRESTClient(ctrl) 76 s.expectPost(restClient, baseURLPath, id, body) 77 78 client := newRefreshClient(baseURLPath, restClient, &FakeLogger{}) 79 responses, err := client.Refresh(context.Background(), config) 80 c.Assert(err, jc.ErrorIsNil) 81 c.Assert(len(responses), gc.Equals, 1) 82 c.Assert(responses[0].Name, gc.Equals, id) 83 } 84 85 // c.Assert(results.Results[0].Error, gc.ErrorMatches, `.* pool "foo" not found`) 86 func (s *RefreshSuite) TestRefeshConfigValidateArch(c *gc.C) { 87 err := s.testRefeshConfigValidate(c, RefreshBase{ 88 Name: "ubuntu", 89 Channel: "20.04", 90 Architecture: "all", 91 }) 92 c.Assert(err, gc.ErrorMatches, "Architecture.*") 93 } 94 95 func (s *RefreshSuite) TestRefeshConfigValidateSeries(c *gc.C) { 96 err := s.testRefeshConfigValidate(c, RefreshBase{ 97 Name: "ubuntu", 98 Channel: "all", 99 Architecture: arch.DefaultArchitecture, 100 }) 101 c.Assert(err, gc.ErrorMatches, "Channel.*") 102 } 103 104 func (s *RefreshSuite) TestRefeshConfigVali914dateName(c *gc.C) { 105 err := s.testRefeshConfigValidate(c, RefreshBase{ 106 Name: "all", 107 Channel: "20.04", 108 Architecture: arch.DefaultArchitecture, 109 }) 110 c.Assert(err, gc.ErrorMatches, "Name.*") 111 } 112 113 func (s *RefreshSuite) TestRefeshConfigValidate(c *gc.C) { 114 err := s.testRefeshConfigValidate(c, RefreshBase{ 115 Name: "all", 116 Channel: "all", 117 Architecture: "all", 118 }) 119 c.Assert(err, gc.ErrorMatches, "Architecture.*, Name.*, Channel.*") 120 } 121 122 func (s *RefreshSuite) testRefeshConfigValidate(c *gc.C, rp RefreshBase) error { 123 _, err := DownloadOneFromChannel("meshuggah", "latest/stable", rp) 124 c.Assert(err, jc.Satisfies, errors.IsNotValid) 125 return err 126 } 127 128 type metadataHTTPClient struct { 129 requestHeaders http.Header 130 responseBody string 131 } 132 133 func (t *metadataHTTPClient) Do(req *http.Request) (*http.Response, error) { 134 t.requestHeaders = req.Header 135 resp := &http.Response{ 136 Status: "200 OK", 137 StatusCode: 200, 138 Proto: "HTTP/1.1", 139 ProtoMajor: 1, 140 ProtoMinor: 1, 141 Body: io.NopCloser(bytes.NewBufferString(t.responseBody)), 142 ContentLength: int64(len(t.responseBody)), 143 Request: req, 144 Header: http.Header{"Content-Type": []string{"application/json"}}, 145 } 146 return resp, nil 147 } 148 149 func (s *RefreshSuite) TestRefreshMetadata(c *gc.C) { 150 baseURL := MustParseURL(c, "http://api.foo.bar") 151 baseURLPath := path.MakePath(baseURL) 152 153 httpClient := &metadataHTTPClient{ 154 responseBody: ` 155 { 156 "error-list": [], 157 "results": [ 158 { 159 "id": "foo", 160 "instance-key": "instance-key-foo" 161 }, 162 { 163 "id": "bar", 164 "instance-key": "instance-key-bar" 165 } 166 ] 167 } 168 `, 169 } 170 171 restClient := newHTTPRESTClient(httpClient) 172 client := newRefreshClient(baseURLPath, restClient, &FakeLogger{}) 173 174 config1, err := RefreshOne("instance-key-foo", "foo", 1, "latest/stable", RefreshBase{ 175 Name: "ubuntu", 176 Channel: "20.04", 177 Architecture: "amd64", 178 }) 179 c.Assert(err, jc.ErrorIsNil) 180 181 config2, err := RefreshOne("instance-key-bar", "bar", 2, "latest/edge", RefreshBase{ 182 Name: "ubuntu", 183 Channel: "14.04", 184 Architecture: "amd64", 185 }) 186 c.Assert(err, jc.ErrorIsNil) 187 188 config := RefreshMany(config1, config2) 189 190 response, err := client.Refresh(context.Background(), config) 191 c.Assert(err, jc.ErrorIsNil) 192 193 c.Assert(response, gc.DeepEquals, []transport.RefreshResponse{ 194 {ID: "foo", InstanceKey: "instance-key-foo"}, 195 {ID: "bar", InstanceKey: "instance-key-bar"}, 196 }) 197 } 198 199 func (s *RefreshSuite) TestRefreshMetadataRandomOrder(c *gc.C) { 200 baseURL := MustParseURL(c, "http://api.foo.bar") 201 baseURLPath := path.MakePath(baseURL) 202 203 httpClient := &metadataHTTPClient{ 204 responseBody: ` 205 { 206 "error-list": [], 207 "results": [ 208 { 209 "id": "bar", 210 "instance-key": "instance-key-bar" 211 }, 212 { 213 "id": "foo", 214 "instance-key": "instance-key-foo" 215 } 216 ] 217 } 218 `, 219 } 220 221 restClient := newHTTPRESTClient(httpClient) 222 client := newRefreshClient(baseURLPath, restClient, &FakeLogger{}) 223 224 config1, err := RefreshOne("instance-key-foo", "foo", 1, "latest/stable", RefreshBase{ 225 Name: "ubuntu", 226 Channel: "20.04", 227 Architecture: "amd64", 228 }) 229 c.Assert(err, jc.ErrorIsNil) 230 231 config2, err := RefreshOne("instance-key-bar", "bar", 2, "latest/edge", RefreshBase{ 232 Name: "ubuntu", 233 Channel: "14.04", 234 Architecture: "amd64", 235 }) 236 c.Assert(err, jc.ErrorIsNil) 237 238 config := RefreshMany(config1, config2) 239 240 response, err := client.Refresh(context.Background(), config) 241 c.Assert(err, jc.ErrorIsNil) 242 243 c.Assert(response, gc.DeepEquals, []transport.RefreshResponse{ 244 {ID: "foo", InstanceKey: "instance-key-foo"}, 245 {ID: "bar", InstanceKey: "instance-key-bar"}, 246 }) 247 } 248 249 func (s *RefreshSuite) TestRefreshWithMetricsOnly(c *gc.C) { 250 ctrl := gomock.NewController(c) 251 defer ctrl.Finish() 252 253 baseURL := MustParseURL(c, "http://api.foo.bar") 254 255 baseURLPath := path.MakePath(baseURL) 256 id := "" 257 body := transport.RefreshRequest{ 258 Context: []transport.RefreshRequestContext{}, 259 Actions: []transport.RefreshRequestAction{}, 260 Metrics: map[string]map[string]string{ 261 "controller": {"uuid": "controller-uuid"}, 262 "model": {"units": "3", "controller": "controller-uuid", "uuid": "model-uuid"}, 263 }, 264 } 265 266 restClient := NewMockRESTClient(ctrl) 267 s.expectPost(restClient, baseURLPath, id, body) 268 269 metrics := map[charmmetrics.MetricKey]map[charmmetrics.MetricKey]string{ 270 charmmetrics.Controller: { 271 272 charmmetrics.UUID: "controller-uuid", 273 }, 274 charmmetrics.Model: { 275 charmmetrics.NumUnits: "3", 276 charmmetrics.Controller: "controller-uuid", 277 charmmetrics.UUID: "model-uuid", 278 }, 279 } 280 281 client := newRefreshClient(baseURLPath, restClient, &FakeLogger{}) 282 err := client.RefreshWithMetricsOnly(context.Background(), metrics) 283 c.Assert(err, jc.ErrorIsNil) 284 } 285 286 func (s *RefreshSuite) TestRefreshWithRequestMetrics(c *gc.C) { 287 ctrl := gomock.NewController(c) 288 defer ctrl.Finish() 289 290 baseURL := MustParseURL(c, "http://api.foo.bar") 291 292 baseURLPath := path.MakePath(baseURL) 293 id := "meshuggah" 294 body := transport.RefreshRequest{ 295 Context: []transport.RefreshRequestContext{{ 296 InstanceKey: "instance-key-foo", 297 ID: id, 298 Revision: 1, 299 Base: transport.Base{ 300 Name: "ubuntu", 301 Channel: "20.04", 302 Architecture: arch.DefaultArchitecture, 303 }, 304 TrackingChannel: "latest/stable", 305 }, { 306 InstanceKey: "instance-key-bar", 307 ID: id, 308 Revision: 2, 309 Base: transport.Base{ 310 Name: "ubuntu", 311 Channel: "14.04", 312 Architecture: arch.DefaultArchitecture, 313 }, 314 TrackingChannel: "latest/edge", 315 }}, 316 Actions: []transport.RefreshRequestAction{{ 317 Action: "refresh", 318 InstanceKey: "instance-key-foo", 319 ID: &id, 320 }, { 321 Action: "refresh", 322 InstanceKey: "instance-key-bar", 323 ID: &id, 324 }}, 325 Fields: expRefreshFields, 326 Metrics: map[string]map[string]string{ 327 "controller": {"uuid": "controller-uuid"}, 328 "model": {"units": "3", "controller": "controller-uuid", "uuid": "model-uuid"}, 329 }, 330 } 331 332 config1, err := RefreshOne("instance-key-foo", id, 1, "latest/stable", RefreshBase{ 333 Name: "ubuntu", 334 Channel: "20.04", 335 Architecture: "amd64", 336 }) 337 c.Assert(err, jc.ErrorIsNil) 338 339 config2, err := RefreshOne("instance-key-bar", id, 2, "latest/edge", RefreshBase{ 340 Name: "ubuntu", 341 Channel: "14.04", 342 Architecture: "amd64", 343 }) 344 c.Assert(err, jc.ErrorIsNil) 345 346 config := RefreshMany(config1, config2) 347 348 restClient := NewMockRESTClient(ctrl) 349 restClient.EXPECT().Post(gomock.Any(), baseURLPath, gomock.Any(), body, gomock.Any()).Do(func(_ context.Context, _ path.Path, _ map[string][]string, _ transport.RefreshRequest, responses *transport.RefreshResponses) { 350 responses.Results = []transport.RefreshResponse{{ 351 InstanceKey: "instance-key-foo", 352 Name: id, 353 }, { 354 InstanceKey: "instance-key-bar", 355 Name: id, 356 }} 357 }).Return(restResponse{StatusCode: http.StatusOK}, nil) 358 359 metrics := map[charmmetrics.MetricKey]map[charmmetrics.MetricKey]string{ 360 charmmetrics.Controller: { 361 charmmetrics.UUID: "controller-uuid", 362 }, 363 charmmetrics.Model: { 364 charmmetrics.NumUnits: "3", 365 charmmetrics.Controller: "controller-uuid", 366 charmmetrics.UUID: "model-uuid", 367 }, 368 } 369 370 client := newRefreshClient(baseURLPath, restClient, &FakeLogger{}) 371 responses, err := client.RefreshWithRequestMetrics(context.Background(), config, metrics) 372 c.Assert(err, jc.ErrorIsNil) 373 c.Assert(len(responses), gc.Equals, 2) 374 c.Assert(responses[0].Name, gc.Equals, id) 375 } 376 377 func (s *RefreshSuite) TestRefreshFailure(c *gc.C) { 378 ctrl := gomock.NewController(c) 379 defer ctrl.Finish() 380 381 baseURL := MustParseURL(c, "http://api.foo.bar") 382 383 baseURLPath := path.MakePath(baseURL) 384 name := "meshuggah" 385 386 config, err := RefreshOne("instance-key", name, 1, "latest/stable", RefreshBase{ 387 Name: "ubuntu", 388 Channel: "20.04", 389 Architecture: arch.DefaultArchitecture, 390 }) 391 c.Assert(err, jc.ErrorIsNil) 392 393 restClient := NewMockRESTClient(ctrl) 394 s.expectPostFailure(restClient) 395 396 client := newRefreshClient(baseURLPath, restClient, &FakeLogger{}) 397 _, err = client.Refresh(context.Background(), config) 398 c.Assert(err, gc.Not(jc.ErrorIsNil)) 399 } 400 401 func (s *RefreshSuite) expectPost(client *MockRESTClient, p path.Path, name string, body interface{}) { 402 client.EXPECT().Post(gomock.Any(), p, gomock.Any(), body, gomock.Any()).Do(func(_ context.Context, _ path.Path, _ map[string][]string, _ transport.RefreshRequest, responses *transport.RefreshResponses) { 403 responses.Results = []transport.RefreshResponse{{ 404 InstanceKey: "instance-key", 405 Name: name, 406 }} 407 }).Return(restResponse{StatusCode: http.StatusOK}, nil) 408 } 409 410 func (s *RefreshSuite) expectPostFailure(client *MockRESTClient) { 411 client.EXPECT().Post(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(restResponse{StatusCode: http.StatusInternalServerError}, errors.Errorf("boom")) 412 } 413 414 func DefineInstanceKey(c *gc.C, config RefreshConfig, key string) RefreshConfig { 415 switch t := config.(type) { 416 case refreshOne: 417 t.instanceKey = key 418 return t 419 case executeOne: 420 t.instanceKey = key 421 return t 422 case executeOneByRevision: 423 t.instanceKey = key 424 return t 425 default: 426 c.Fatalf("unexpected config %T", config) 427 } 428 return nil 429 } 430 431 type RefreshConfigSuite struct { 432 testing.IsolationSuite 433 } 434 435 var _ = gc.Suite(&RefreshConfigSuite{}) 436 437 func (s *RefreshConfigSuite) TestRefreshOneBuild(c *gc.C) { 438 id := "foo" 439 config, err := RefreshOne("instance-key", id, 1, "latest/stable", RefreshBase{ 440 Name: "ubuntu", 441 Channel: "20.04", 442 Architecture: arch.DefaultArchitecture, 443 }) 444 c.Assert(err, jc.ErrorIsNil) 445 446 req, err := config.Build() 447 c.Assert(err, jc.ErrorIsNil) 448 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 449 Context: []transport.RefreshRequestContext{{ 450 InstanceKey: "instance-key", 451 ID: "foo", 452 Revision: 1, 453 Base: transport.Base{ 454 Name: "ubuntu", 455 Channel: "20.04", 456 Architecture: arch.DefaultArchitecture, 457 }, 458 TrackingChannel: "latest/stable", 459 }}, 460 Actions: []transport.RefreshRequestAction{{ 461 Action: "refresh", 462 InstanceKey: "instance-key", 463 ID: &id, 464 }}, 465 Fields: expRefreshFields, 466 }) 467 } 468 469 func (s *RefreshConfigSuite) TestRefreshOneWithBaseChannelRiskBuild(c *gc.C) { 470 id := "foo" 471 config, err := RefreshOne("instance-key", id, 1, "latest/stable", RefreshBase{ 472 Name: "ubuntu", 473 Channel: "20.04/stable", 474 Architecture: arch.DefaultArchitecture, 475 }) 476 c.Assert(err, jc.ErrorIsNil) 477 478 req, err := config.Build() 479 c.Assert(err, jc.ErrorIsNil) 480 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 481 Context: []transport.RefreshRequestContext{{ 482 InstanceKey: "instance-key", 483 ID: "foo", 484 Revision: 1, 485 Base: transport.Base{ 486 Name: "ubuntu", 487 Channel: "20.04", 488 Architecture: arch.DefaultArchitecture, 489 }, 490 TrackingChannel: "latest/stable", 491 }}, 492 Actions: []transport.RefreshRequestAction{{ 493 Action: "refresh", 494 InstanceKey: "instance-key", 495 ID: &id, 496 }}, 497 Fields: expRefreshFields, 498 }) 499 500 } 501 502 func (s *RefreshConfigSuite) TestRefreshOneBuildInstanceKeyCompatibility(c *gc.C) { 503 id := "foo" 504 config, err := RefreshOne("", id, 1, "latest/stable", RefreshBase{ 505 Name: "ubuntu", 506 Channel: "20.04", 507 Architecture: arch.DefaultArchitecture, 508 }) 509 c.Assert(err, jc.ErrorIsNil) 510 511 key := ExtractConfigInstanceKey(config) 512 c.Assert(utils.IsValidUUIDString(key), jc.IsTrue) 513 } 514 515 func (s *RefreshConfigSuite) TestRefreshOneWithMetricsBuild(c *gc.C) { 516 id := "foo" 517 config, err := RefreshOne("instance-key", id, 1, "latest/stable", RefreshBase{ 518 Name: "ubuntu", 519 Channel: "20.04", 520 Architecture: arch.DefaultArchitecture, 521 }) 522 c.Assert(err, jc.ErrorIsNil) 523 524 config, err = AddConfigMetrics(config, map[charmmetrics.MetricKey]string{ 525 charmmetrics.Provider: "openstack", 526 charmmetrics.NumApplications: "4", 527 }) 528 c.Assert(err, jc.ErrorIsNil) 529 530 req, err := config.Build() 531 c.Assert(err, jc.ErrorIsNil) 532 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 533 Context: []transport.RefreshRequestContext{{ 534 InstanceKey: "instance-key", 535 ID: "foo", 536 Revision: 1, 537 Base: transport.Base{ 538 Name: "ubuntu", 539 Channel: "20.04", 540 Architecture: arch.DefaultArchitecture, 541 }, 542 TrackingChannel: "latest/stable", 543 Metrics: map[string]string{ 544 "provider": "openstack", 545 "applications": "4", 546 }, 547 }}, 548 Actions: []transport.RefreshRequestAction{{ 549 Action: "refresh", 550 InstanceKey: "instance-key", 551 ID: &id, 552 }}, 553 Fields: expRefreshFields, 554 }) 555 } 556 557 func (s *RefreshConfigSuite) TestRefreshOneFail(c *gc.C) { 558 _, err := RefreshOne("instance-key", "", 1, "latest/stable", RefreshBase{ 559 Name: "ubuntu", 560 Channel: "20.04", 561 Architecture: arch.DefaultArchitecture, 562 }) 563 c.Assert(err, jc.Satisfies, errors.IsNotValid) 564 } 565 566 func (s *RefreshConfigSuite) TestRefreshOneEnsure(c *gc.C) { 567 config, err := RefreshOne("instance-key", "foo", 1, "latest/stable", RefreshBase{ 568 Name: "ubuntu", 569 Channel: "20.04", 570 Architecture: arch.DefaultArchitecture, 571 }) 572 c.Assert(err, jc.ErrorIsNil) 573 574 err = config.Ensure([]transport.RefreshResponse{{ 575 InstanceKey: "instance-key", 576 }}) 577 c.Assert(err, jc.ErrorIsNil) 578 } 579 580 func (s *RefreshConfigSuite) TestInstallOneFromRevisionBuild(c *gc.C) { 581 revision := 1 582 583 name := "foo" 584 config, err := InstallOneFromRevision(name, revision) 585 c.Assert(err, jc.ErrorIsNil) 586 587 config = DefineInstanceKey(c, config, "foo-bar") 588 589 req, err := config.Build() 590 c.Assert(err, jc.ErrorIsNil) 591 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 592 Context: []transport.RefreshRequestContext{}, 593 Actions: []transport.RefreshRequestAction{{ 594 Action: "install", 595 InstanceKey: "foo-bar", 596 Name: &name, 597 Revision: &revision, 598 }}, 599 Fields: expRefreshFields, 600 }) 601 } 602 603 func (s *RefreshConfigSuite) TestInstallOneFromRevisionFail(c *gc.C) { 604 _, err := InstallOneFromRevision("", 1) 605 c.Assert(err, jc.Satisfies, errors.IsNotValid) 606 } 607 608 func (s *RefreshConfigSuite) TestInstallOneBuildRevisionResources(c *gc.C) { 609 // Tests InstallOne by revision with specific resources. 610 revision := 1 611 612 name := "foo" 613 config, err := InstallOneFromRevision(name, revision) 614 c.Assert(err, jc.ErrorIsNil) 615 616 config = DefineInstanceKey(c, config, "foo-bar") 617 config, ok := AddResource(config, "testme", 3) 618 c.Assert(ok, jc.IsTrue) 619 620 req, err := config.Build() 621 c.Assert(err, jc.ErrorIsNil) 622 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 623 Context: []transport.RefreshRequestContext{}, 624 Actions: []transport.RefreshRequestAction{{ 625 Action: "install", 626 InstanceKey: "foo-bar", 627 Name: &name, 628 Revision: &revision, 629 ResourceRevisions: []transport.RefreshResourceRevision{ 630 {Name: "testme", Revision: 3}, 631 }, 632 }}, 633 Fields: expRefreshFields, 634 }) 635 } 636 637 func (s *RefreshConfigSuite) TestAddResourceFail(c *gc.C) { 638 config, err := RefreshOne("instance-key", "testingID", 7, "latest/edge", RefreshBase{ 639 Name: "ubuntu", 640 Channel: "20.04", 641 Architecture: arch.DefaultArchitecture, 642 }) 643 c.Assert(err, jc.ErrorIsNil) 644 _, ok := AddResource(config, "testme", 3) 645 c.Assert(ok, jc.IsFalse) 646 } 647 648 func (s *RefreshConfigSuite) TestInstallOneBuildChannel(c *gc.C) { 649 channel := "latest/stable" 650 651 name := "foo" 652 config, err := InstallOneFromChannel(name, channel, RefreshBase{ 653 Name: "ubuntu", 654 Channel: "20.04", 655 Architecture: arch.DefaultArchitecture, 656 }) 657 c.Assert(err, jc.ErrorIsNil) 658 659 config = DefineInstanceKey(c, config, "foo-bar") 660 661 req, err := config.Build() 662 c.Assert(err, jc.ErrorIsNil) 663 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 664 Context: []transport.RefreshRequestContext{}, 665 Actions: []transport.RefreshRequestAction{{ 666 Action: "install", 667 InstanceKey: "foo-bar", 668 Name: &name, 669 Channel: &channel, 670 Base: &transport.Base{ 671 Name: "ubuntu", 672 Channel: "20.04", 673 Architecture: arch.DefaultArchitecture, 674 }, 675 }}, 676 Fields: expRefreshFields, 677 }) 678 } 679 680 func (s *RefreshConfigSuite) TestInstallOneChannelFail(c *gc.C) { 681 _, err := InstallOneFromChannel("", "stable", RefreshBase{ 682 Name: "ubuntu", 683 Channel: "20.04", 684 Architecture: arch.DefaultArchitecture, 685 }) 686 c.Assert(err, jc.Satisfies, errors.IsNotValid) 687 } 688 689 func (s *RefreshConfigSuite) TestInstallOneWithPartialPlatform(c *gc.C) { 690 channel := "latest/stable" 691 692 name := "foo" 693 config, err := InstallOneFromChannel(name, channel, RefreshBase{ 694 Architecture: arch.DefaultArchitecture, 695 }) 696 c.Assert(err, jc.ErrorIsNil) 697 698 config = DefineInstanceKey(c, config, "foo-bar") 699 700 req, err := config.Build() 701 c.Assert(err, jc.ErrorIsNil) 702 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 703 Context: []transport.RefreshRequestContext{}, 704 Actions: []transport.RefreshRequestAction{{ 705 Action: "install", 706 InstanceKey: "foo-bar", 707 Name: &name, 708 Channel: &channel, 709 Base: &transport.Base{ 710 Name: notAvailable, 711 Channel: notAvailable, 712 Architecture: arch.DefaultArchitecture, 713 }, 714 }}, 715 Fields: expRefreshFields, 716 }) 717 } 718 719 func (s *RefreshConfigSuite) TestInstallOneWithMissingArch(c *gc.C) { 720 channel := "latest/stable" 721 722 name := "foo" 723 config, err := InstallOneFromChannel(name, channel, RefreshBase{}) 724 c.Assert(err, jc.ErrorIsNil) 725 726 config = DefineInstanceKey(c, config, "foo-bar") 727 728 _, err = config.Build() 729 c.Assert(errors.IsNotValid(err), jc.IsTrue) 730 } 731 732 func (s *RefreshConfigSuite) TestInstallOneFromChannelEnsure(c *gc.C) { 733 config, err := InstallOneFromChannel("foo", "latest/stable", RefreshBase{ 734 Name: "ubuntu", 735 Channel: "20.04", 736 Architecture: arch.DefaultArchitecture, 737 }) 738 c.Assert(err, jc.ErrorIsNil) 739 740 config = DefineInstanceKey(c, config, "foo-bar") 741 742 err = config.Ensure([]transport.RefreshResponse{{ 743 InstanceKey: "foo-bar", 744 }}) 745 c.Assert(err, jc.ErrorIsNil) 746 } 747 748 func (s *RefreshConfigSuite) TestInstallOneFromChannelFail(c *gc.C) { 749 _, err := InstallOneFromChannel("foo", "latest/stable", RefreshBase{ 750 Name: "ubuntu", 751 Channel: "20.04", 752 Architecture: arch.DefaultArchitecture, 753 }) 754 c.Assert(err, jc.ErrorIsNil) 755 } 756 757 func (s *RefreshConfigSuite) TestDownloadOneFromRevisionBuild(c *gc.C) { 758 rev := 4 759 id := "foo" 760 config, err := DownloadOneFromRevision(id, rev) 761 c.Assert(err, jc.ErrorIsNil) 762 763 config = DefineInstanceKey(c, config, "foo-bar") 764 765 req, err := config.Build() 766 c.Assert(err, jc.ErrorIsNil) 767 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 768 Context: []transport.RefreshRequestContext{}, 769 Actions: []transport.RefreshRequestAction{{ 770 Action: "download", 771 InstanceKey: "foo-bar", 772 ID: &id, 773 Revision: &rev, 774 }}, 775 Fields: expRefreshFields, 776 }) 777 } 778 779 func (s *RefreshConfigSuite) TestDownloadOneFromRevisionFail(c *gc.C) { 780 _, err := DownloadOneFromRevision("", 7) 781 c.Assert(err, jc.Satisfies, errors.IsNotValid) 782 } 783 784 func (s *RefreshConfigSuite) TestDownloadOneFromRevisionByNameBuild(c *gc.C) { 785 rev := 4 786 name := "foo" 787 config, err := DownloadOneFromRevisionByName(name, rev) 788 c.Assert(err, jc.ErrorIsNil) 789 790 config = DefineInstanceKey(c, config, "foo-bar") 791 792 req, err := config.Build() 793 c.Assert(err, jc.ErrorIsNil) 794 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 795 Context: []transport.RefreshRequestContext{}, 796 Actions: []transport.RefreshRequestAction{{ 797 Action: "download", 798 InstanceKey: "foo-bar", 799 Name: &name, 800 Revision: &rev, 801 }}, 802 Fields: expRefreshFields, 803 }) 804 } 805 806 func (s *RefreshConfigSuite) TestDownloadOneFromRevisionByNameFail(c *gc.C) { 807 _, err := DownloadOneFromRevisionByName("", 7) 808 c.Assert(err, jc.Satisfies, errors.IsNotValid) 809 } 810 811 func (s *RefreshConfigSuite) TestDownloadOneFromChannelBuild(c *gc.C) { 812 channel := "latest/stable" 813 id := "foo" 814 config, err := DownloadOneFromChannel(id, channel, RefreshBase{ 815 Name: "ubuntu", 816 Channel: "20.04", 817 Architecture: arch.DefaultArchitecture, 818 }) 819 c.Assert(err, jc.ErrorIsNil) 820 821 config = DefineInstanceKey(c, config, "foo-bar") 822 823 req, err := config.Build() 824 c.Assert(err, jc.ErrorIsNil) 825 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 826 Context: []transport.RefreshRequestContext{}, 827 Actions: []transport.RefreshRequestAction{{ 828 Action: "download", 829 InstanceKey: "foo-bar", 830 ID: &id, 831 Channel: &channel, 832 Base: &transport.Base{ 833 Name: "ubuntu", 834 Channel: "20.04", 835 Architecture: arch.DefaultArchitecture, 836 }, 837 }}, 838 Fields: expRefreshFields, 839 }) 840 } 841 842 func (s *RefreshConfigSuite) TestDownloadOneFromChannelFail(c *gc.C) { 843 _, err := DownloadOneFromChannel("", "latest/stable", RefreshBase{ 844 Name: "ubuntu", 845 Channel: "20.04", 846 Architecture: arch.DefaultArchitecture, 847 }) 848 c.Assert(err, jc.Satisfies, errors.IsNotValid) 849 } 850 851 func (s *RefreshConfigSuite) TestDownloadOneFromChannelByNameBuild(c *gc.C) { 852 channel := "latest/stable" 853 name := "foo" 854 config, err := DownloadOneFromChannelByName(name, channel, RefreshBase{ 855 Name: "ubuntu", 856 Channel: "20.04", 857 Architecture: arch.DefaultArchitecture, 858 }) 859 c.Assert(err, jc.ErrorIsNil) 860 861 config = DefineInstanceKey(c, config, "foo-bar") 862 863 req, err := config.Build() 864 c.Assert(err, jc.ErrorIsNil) 865 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 866 Context: []transport.RefreshRequestContext{}, 867 Actions: []transport.RefreshRequestAction{{ 868 Action: "download", 869 InstanceKey: "foo-bar", 870 Name: &name, 871 Channel: &channel, 872 Base: &transport.Base{ 873 Name: "ubuntu", 874 Channel: "20.04", 875 Architecture: arch.DefaultArchitecture, 876 }, 877 }}, 878 Fields: expRefreshFields, 879 }) 880 } 881 882 func (s *RefreshConfigSuite) TestDownloadOneFromChannelByNameFail(c *gc.C) { 883 _, err := DownloadOneFromChannel("", "latest/stable", RefreshBase{ 884 Name: "ubuntu", 885 Channel: "20.04", 886 Architecture: arch.DefaultArchitecture, 887 }) 888 c.Assert(err, jc.Satisfies, errors.IsNotValid) 889 } 890 891 func (s *RefreshConfigSuite) TestDownloadOneFromChannelBuildK8s(c *gc.C) { 892 channel := "latest/stable" 893 id := "foo" 894 config, err := DownloadOneFromChannel(id, channel, RefreshBase{ 895 Name: "kubernetes", 896 Channel: "kubernetes", 897 Architecture: arch.DefaultArchitecture, 898 }) 899 c.Assert(err, jc.ErrorIsNil) 900 901 config = DefineInstanceKey(c, config, "foo-bar") 902 903 req, err := config.Build() 904 c.Assert(err, jc.ErrorIsNil) 905 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 906 Context: []transport.RefreshRequestContext{}, 907 Actions: []transport.RefreshRequestAction{{ 908 Action: "download", 909 InstanceKey: "foo-bar", 910 ID: &id, 911 Channel: &channel, 912 Base: &transport.Base{ 913 Name: "ubuntu", 914 Channel: "22.04", 915 Architecture: arch.DefaultArchitecture, 916 }, 917 }}, 918 Fields: expRefreshFields, 919 }) 920 } 921 922 func (s *RefreshConfigSuite) TestDownloadOneFromChannelEnsure(c *gc.C) { 923 config, err := DownloadOneFromChannel("foo", "latest/stable", RefreshBase{ 924 Name: "ubuntu", 925 Channel: "20.04", 926 Architecture: arch.DefaultArchitecture, 927 }) 928 c.Assert(err, jc.ErrorIsNil) 929 930 config = DefineInstanceKey(c, config, "foo-bar") 931 932 err = config.Ensure([]transport.RefreshResponse{{ 933 InstanceKey: "foo-bar", 934 }}) 935 c.Assert(err, jc.ErrorIsNil) 936 } 937 938 func (s *RefreshConfigSuite) TestRefreshManyBuildContextNotNil(c *gc.C) { 939 id1 := "foo" 940 config1, err := DownloadOneFromRevision(id1, 1) 941 c.Assert(err, jc.ErrorIsNil) 942 config1 = DefineInstanceKey(c, config1, "foo-bar") 943 944 id2 := "bar" 945 config2, err := DownloadOneFromChannel(id2, "latest/edge", RefreshBase{ 946 Name: "ubuntu", 947 Channel: "14.04", 948 Architecture: arch.DefaultArchitecture, 949 }) 950 c.Assert(err, jc.ErrorIsNil) 951 config2 = DefineInstanceKey(c, config2, "foo-baz") 952 config := RefreshMany(config1, config2) 953 954 req, err := config.Build() 955 c.Assert(err, jc.ErrorIsNil) 956 c.Assert(req.Context, gc.NotNil) 957 } 958 959 func (s *RefreshConfigSuite) TestRefreshManyBuild(c *gc.C) { 960 id1 := "foo" 961 config1, err := RefreshOne("instance-key", id1, 1, "latest/stable", RefreshBase{ 962 Name: "ubuntu", 963 Channel: "20.04", 964 Architecture: arch.DefaultArchitecture, 965 }) 966 c.Assert(err, jc.ErrorIsNil) 967 968 id2 := "bar" 969 config2, err := RefreshOne("instance-key2", id2, 2, "latest/edge", RefreshBase{ 970 Name: "ubuntu", 971 Channel: "14.04", 972 Architecture: arch.DefaultArchitecture, 973 }) 974 c.Assert(err, jc.ErrorIsNil) 975 976 channel := "1/stable" 977 978 name3 := "baz" 979 config3, err := InstallOneFromChannel(name3, "1/stable", RefreshBase{ 980 Name: "ubuntu", 981 Channel: "19.04", 982 Architecture: arch.DefaultArchitecture, 983 }) 984 c.Assert(err, jc.ErrorIsNil) 985 986 config3 = DefineInstanceKey(c, config3, "foo-taz") 987 988 name4 := "forty-two" 989 rev4 := 42 990 config4, err := InstallOneFromRevision(name4, rev4) 991 c.Assert(err, jc.ErrorIsNil) 992 993 config4 = DefineInstanceKey(c, config4, "foo-two") 994 995 config := RefreshMany(config1, config2, config3, config4) 996 997 req, err := config.Build() 998 c.Assert(err, jc.ErrorIsNil) 999 c.Assert(req, gc.DeepEquals, transport.RefreshRequest{ 1000 Context: []transport.RefreshRequestContext{{ 1001 InstanceKey: "instance-key", 1002 ID: "foo", 1003 Revision: 1, 1004 Base: transport.Base{ 1005 Name: "ubuntu", 1006 Channel: "20.04", 1007 Architecture: arch.DefaultArchitecture, 1008 }, 1009 TrackingChannel: "latest/stable", 1010 }, { 1011 InstanceKey: "instance-key2", 1012 ID: "bar", 1013 Revision: 2, 1014 Base: transport.Base{ 1015 Name: "ubuntu", 1016 Channel: "14.04", 1017 Architecture: arch.DefaultArchitecture, 1018 }, 1019 TrackingChannel: "latest/edge", 1020 }}, 1021 Actions: []transport.RefreshRequestAction{{ 1022 Action: "refresh", 1023 InstanceKey: "instance-key", 1024 ID: &id1, 1025 }, { 1026 Action: "refresh", 1027 InstanceKey: "instance-key2", 1028 ID: &id2, 1029 }, { 1030 Action: "install", 1031 InstanceKey: "foo-taz", 1032 Name: &name3, 1033 Base: &transport.Base{ 1034 Name: "ubuntu", 1035 Channel: "19.04", 1036 Architecture: arch.DefaultArchitecture, 1037 }, 1038 Channel: &channel, 1039 }, { 1040 Action: "install", 1041 InstanceKey: "foo-two", 1042 Name: &name4, 1043 Revision: &rev4, 1044 }}, 1045 Fields: expRefreshFields, 1046 }) 1047 } 1048 1049 func (s *RefreshConfigSuite) TestRefreshManyEnsure(c *gc.C) { 1050 config1, err := RefreshOne("instance-key", "foo", 1, "latest/stable", RefreshBase{ 1051 Name: "ubuntu", 1052 Channel: "20.04", 1053 Architecture: arch.DefaultArchitecture, 1054 }) 1055 c.Assert(err, jc.ErrorIsNil) 1056 1057 config2, err := RefreshOne("instance-key2", "bar", 2, "latest/edge", RefreshBase{ 1058 Name: "ubuntu", 1059 Channel: "14.04", 1060 Architecture: arch.DefaultArchitecture, 1061 }) 1062 c.Assert(err, jc.ErrorIsNil) 1063 1064 config := RefreshMany(config1, config2) 1065 1066 err = config.Ensure([]transport.RefreshResponse{{ 1067 InstanceKey: "instance-key", 1068 }, { 1069 InstanceKey: "instance-key2", 1070 }}) 1071 c.Assert(err, jc.ErrorIsNil) 1072 }