github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/cmd/juju/application/register_test.go (about) 1 // Copyright 2015 Canonical Ltd. All rights reserved. 2 3 package application 4 5 import ( 6 "encoding/json" 7 "net/http" 8 "net/http/httptest" 9 10 "github.com/juju/cmd" 11 "github.com/juju/errors" 12 "github.com/juju/testing" 13 jc "github.com/juju/testing/checkers" 14 gc "gopkg.in/check.v1" 15 "gopkg.in/juju/charm.v6-unstable" 16 "gopkg.in/macaroon-bakery.v1/httpbakery" 17 18 apicharms "github.com/juju/juju/api/charms" 19 "github.com/juju/juju/charmstore" 20 coretesting "github.com/juju/juju/testing" 21 ) 22 23 var _ = gc.Suite(®istrationSuite{}) 24 25 type registrationSuite struct { 26 testing.CleanupSuite 27 stub *testing.Stub 28 handler *testMetricsRegistrationHandler 29 server *httptest.Server 30 register DeployStep 31 ctx *cmd.Context 32 } 33 34 func (s *registrationSuite) SetUpTest(c *gc.C) { 35 s.CleanupSuite.SetUpTest(c) 36 s.stub = &testing.Stub{} 37 s.handler = &testMetricsRegistrationHandler{Stub: s.stub} 38 s.server = httptest.NewServer(s.handler) 39 s.register = &RegisterMeteredCharm{ 40 Plan: "someplan", 41 RegisterURL: s.server.URL, 42 AllocationSpec: "personal:100", 43 } 44 s.ctx = coretesting.Context(c) 45 } 46 47 func (s *registrationSuite) TearDownTest(c *gc.C) { 48 s.CleanupSuite.TearDownTest(c) 49 s.server.Close() 50 } 51 52 func (s *registrationSuite) TestMeteredCharm(c *gc.C) { 53 client := httpbakery.NewClient() 54 d := DeploymentInfo{ 55 CharmID: charmstore.CharmID{ 56 URL: charm.MustParseURL("cs:quantal/metered-1"), 57 }, 58 ApplicationName: "application name", 59 ModelUUID: "model uuid", 60 CharmInfo: &apicharms.CharmInfo{ 61 Metrics: &charm.Metrics{ 62 Plan: &charm.Plan{Required: true}, 63 }, 64 }, 65 } 66 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 67 c.Assert(err, jc.ErrorIsNil) 68 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 69 c.Assert(err, jc.ErrorIsNil) 70 authorization, err := json.Marshal([]byte("hello registration")) 71 authorization = append(authorization, byte(0xa)) 72 s.stub.CheckCalls(c, []testing.StubCall{{ 73 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 74 }, { 75 "Authorize", []interface{}{metricRegistrationPost{ 76 ModelUUID: "model uuid", 77 CharmURL: "cs:quantal/metered-1", 78 ApplicationName: "application name", 79 PlanURL: "someplan", 80 Budget: "personal", 81 Limit: "100", 82 }}, 83 }, { 84 "SetMetricCredentials", []interface{}{ 85 "application name", 86 authorization, 87 }}, 88 }) 89 } 90 91 func (s *registrationSuite) TestOptionalPlanMeteredCharm(c *gc.C) { 92 client := httpbakery.NewClient() 93 d := DeploymentInfo{ 94 CharmID: charmstore.CharmID{ 95 URL: charm.MustParseURL("cs:quantal/metered-1"), 96 }, 97 ApplicationName: "application name", 98 ModelUUID: "model uuid", 99 CharmInfo: &apicharms.CharmInfo{ 100 Metrics: &charm.Metrics{ 101 Plan: &charm.Plan{Required: false}, 102 }, 103 }, 104 } 105 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 106 c.Assert(err, jc.ErrorIsNil) 107 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 108 c.Assert(err, jc.ErrorIsNil) 109 authorization, err := json.Marshal([]byte("hello registration")) 110 authorization = append(authorization, byte(0xa)) 111 s.stub.CheckCalls(c, []testing.StubCall{{ 112 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 113 }, { 114 "Authorize", []interface{}{metricRegistrationPost{ 115 ModelUUID: "model uuid", 116 CharmURL: "cs:quantal/metered-1", 117 ApplicationName: "application name", 118 PlanURL: "someplan", 119 Budget: "personal", 120 Limit: "100", 121 }}, 122 }, { 123 "SetMetricCredentials", []interface{}{ 124 "application name", 125 authorization, 126 }}, 127 }) 128 } 129 130 func (s *registrationSuite) TestPlanNotSpecifiedCharm(c *gc.C) { 131 client := httpbakery.NewClient() 132 d := DeploymentInfo{ 133 CharmID: charmstore.CharmID{ 134 URL: charm.MustParseURL("cs:quantal/metered-1"), 135 }, 136 ApplicationName: "application name", 137 ModelUUID: "model uuid", 138 CharmInfo: &apicharms.CharmInfo{ 139 Metrics: &charm.Metrics{ 140 Plan: nil, 141 }, 142 }, 143 } 144 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 145 c.Assert(err, jc.ErrorIsNil) 146 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 147 c.Assert(err, jc.ErrorIsNil) 148 authorization, err := json.Marshal([]byte("hello registration")) 149 authorization = append(authorization, byte(0xa)) 150 s.stub.CheckCalls(c, []testing.StubCall{{ 151 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 152 }, { 153 "Authorize", []interface{}{metricRegistrationPost{ 154 ModelUUID: "model uuid", 155 CharmURL: "cs:quantal/metered-1", 156 ApplicationName: "application name", 157 PlanURL: "someplan", 158 Budget: "personal", 159 Limit: "100", 160 }}, 161 }, { 162 "SetMetricCredentials", []interface{}{ 163 "application name", 164 authorization, 165 }}, 166 }) 167 } 168 169 func (s *registrationSuite) TestMeteredCharmAPIError(c *gc.C) { 170 s.stub.SetErrors(nil, errors.New("something failed")) 171 client := httpbakery.NewClient() 172 d := DeploymentInfo{ 173 CharmID: charmstore.CharmID{ 174 URL: charm.MustParseURL("cs:quantal/metered-1"), 175 }, 176 ApplicationName: "application name", 177 ModelUUID: "model uuid", 178 CharmInfo: &apicharms.CharmInfo{ 179 Metrics: &charm.Metrics{ 180 Plan: &charm.Plan{Required: true}, 181 }, 182 }, 183 } 184 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 185 c.Assert(err, gc.ErrorMatches, `authorization failed: something failed`) 186 s.stub.CheckCalls(c, []testing.StubCall{{ 187 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 188 }, { 189 "Authorize", []interface{}{metricRegistrationPost{ 190 ModelUUID: "model uuid", 191 CharmURL: "cs:quantal/metered-1", 192 ApplicationName: "application name", 193 PlanURL: "someplan", 194 Budget: "personal", 195 Limit: "100", 196 }}, 197 }}) 198 } 199 200 func (s *registrationSuite) TestMeteredCharmInvalidAllocation(c *gc.C) { 201 client := httpbakery.NewClient() 202 d := DeploymentInfo{ 203 CharmID: charmstore.CharmID{ 204 URL: charm.MustParseURL("cs:quantal/metered-1"), 205 }, 206 ApplicationName: "application name", 207 ModelUUID: "model uuid", 208 CharmInfo: &apicharms.CharmInfo{ 209 Metrics: &charm.Metrics{ 210 Plan: &charm.Plan{Required: true}, 211 }, 212 }, 213 } 214 s.register = &RegisterMeteredCharm{ 215 Plan: "someplan", 216 RegisterURL: s.server.URL, 217 AllocationSpec: "invalid allocation", 218 } 219 220 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 221 c.Assert(err, gc.ErrorMatches, `invalid allocation, expecting <budget>:<limit>`) 222 s.stub.CheckNoCalls(c) 223 } 224 225 func (s *registrationSuite) TestMeteredCharmDeployError(c *gc.C) { 226 client := httpbakery.NewClient() 227 d := DeploymentInfo{ 228 CharmID: charmstore.CharmID{ 229 URL: charm.MustParseURL("cs:quantal/metered-1"), 230 }, 231 ApplicationName: "application name", 232 ModelUUID: "model uuid", 233 CharmInfo: &apicharms.CharmInfo{ 234 Metrics: &charm.Metrics{ 235 Plan: &charm.Plan{Required: true}, 236 }, 237 }, 238 } 239 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 240 c.Assert(err, jc.ErrorIsNil) 241 deployError := errors.New("deployment failed") 242 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, deployError) 243 c.Assert(err, jc.ErrorIsNil) 244 authorization, err := json.Marshal([]byte("hello registration")) 245 authorization = append(authorization, byte(0xa)) 246 c.Assert(err, jc.ErrorIsNil) 247 s.stub.CheckCalls(c, []testing.StubCall{{ 248 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 249 }, { 250 "Authorize", []interface{}{metricRegistrationPost{ 251 ModelUUID: "model uuid", 252 CharmURL: "cs:quantal/metered-1", 253 ApplicationName: "application name", 254 PlanURL: "someplan", 255 Budget: "personal", 256 Limit: "100", 257 }}, 258 }}) 259 } 260 261 func (s *registrationSuite) TestMeteredLocalCharmWithPlan(c *gc.C) { 262 client := httpbakery.NewClient() 263 d := DeploymentInfo{ 264 CharmID: charmstore.CharmID{ 265 URL: charm.MustParseURL("local:quantal/metered-1"), 266 }, 267 ApplicationName: "application name", 268 ModelUUID: "model uuid", 269 CharmInfo: &apicharms.CharmInfo{ 270 Metrics: &charm.Metrics{ 271 Plan: &charm.Plan{Required: true}, 272 }, 273 }, 274 } 275 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 276 c.Assert(err, jc.ErrorIsNil) 277 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 278 c.Assert(err, jc.ErrorIsNil) 279 authorization, err := json.Marshal([]byte("hello registration")) 280 authorization = append(authorization, byte(0xa)) 281 s.stub.CheckCalls(c, []testing.StubCall{{ 282 "IsMetered", []interface{}{"local:quantal/metered-1"}, 283 }, { 284 "Authorize", []interface{}{metricRegistrationPost{ 285 ModelUUID: "model uuid", 286 CharmURL: "local:quantal/metered-1", 287 ApplicationName: "application name", 288 PlanURL: "someplan", 289 Budget: "personal", 290 Limit: "100", 291 }}, 292 }, { 293 "SetMetricCredentials", []interface{}{ 294 "application name", 295 authorization, 296 }, 297 }}) 298 } 299 300 func (s *registrationSuite) TestMeteredLocalCharmNoPlan(c *gc.C) { 301 s.register = &RegisterMeteredCharm{ 302 RegisterURL: s.server.URL, 303 QueryURL: s.server.URL, 304 AllocationSpec: "personal:100", 305 } 306 client := httpbakery.NewClient() 307 d := DeploymentInfo{ 308 CharmID: charmstore.CharmID{ 309 URL: charm.MustParseURL("local:quantal/metered-1"), 310 }, 311 ApplicationName: "application name", 312 ModelUUID: "model uuid", 313 CharmInfo: &apicharms.CharmInfo{ 314 Metrics: &charm.Metrics{ 315 Plan: &charm.Plan{Required: true}, 316 }, 317 }, 318 } 319 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 320 c.Assert(err, jc.ErrorIsNil) 321 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 322 c.Assert(err, jc.ErrorIsNil) 323 authorization, err := json.Marshal([]byte("hello registration")) 324 authorization = append(authorization, byte(0xa)) 325 s.stub.CheckCalls(c, []testing.StubCall{{ 326 "IsMetered", []interface{}{"local:quantal/metered-1"}, 327 }, { 328 "Authorize", []interface{}{metricRegistrationPost{ 329 ModelUUID: "model uuid", 330 CharmURL: "local:quantal/metered-1", 331 ApplicationName: "application name", 332 PlanURL: "", 333 Budget: "personal", 334 Limit: "100", 335 }}, 336 }, { 337 "SetMetricCredentials", []interface{}{ 338 "application name", 339 authorization, 340 }}, 341 }) 342 } 343 344 func (s *registrationSuite) TestMeteredCharmNoPlanSet(c *gc.C) { 345 s.register = &RegisterMeteredCharm{ 346 AllocationSpec: "personal:100", 347 RegisterURL: s.server.URL, 348 QueryURL: s.server.URL} 349 client := httpbakery.NewClient() 350 d := DeploymentInfo{ 351 CharmID: charmstore.CharmID{ 352 URL: charm.MustParseURL("cs:quantal/metered-1"), 353 }, 354 ApplicationName: "application name", 355 ModelUUID: "model uuid", 356 CharmInfo: &apicharms.CharmInfo{ 357 Metrics: &charm.Metrics{ 358 Plan: &charm.Plan{Required: true}, 359 }, 360 }, 361 } 362 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 363 c.Assert(err, jc.ErrorIsNil) 364 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 365 c.Assert(err, jc.ErrorIsNil) 366 authorization, err := json.Marshal([]byte("hello registration")) 367 authorization = append(authorization, byte(0xa)) 368 c.Assert(err, jc.ErrorIsNil) 369 s.stub.CheckCalls(c, []testing.StubCall{{ 370 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 371 }, { 372 "DefaultPlan", []interface{}{"cs:quantal/metered-1"}, 373 }, { 374 "Authorize", []interface{}{metricRegistrationPost{ 375 ModelUUID: "model uuid", 376 CharmURL: "cs:quantal/metered-1", 377 ApplicationName: "application name", 378 PlanURL: "thisplan", 379 Budget: "personal", 380 Limit: "100", 381 }}, 382 }, { 383 "SetMetricCredentials", []interface{}{ 384 "application name", 385 authorization, 386 }, 387 }}) 388 } 389 390 func (s *registrationSuite) TestMeteredCharmNoDefaultPlan(c *gc.C) { 391 s.stub.SetErrors(nil, errors.NotFoundf("default plan")) 392 s.register = &RegisterMeteredCharm{ 393 AllocationSpec: "personal:100", 394 RegisterURL: s.server.URL, 395 QueryURL: s.server.URL} 396 client := httpbakery.NewClient() 397 d := DeploymentInfo{ 398 CharmID: charmstore.CharmID{ 399 URL: charm.MustParseURL("cs:quantal/metered-1"), 400 }, 401 ApplicationName: "application name", 402 ModelUUID: "model uuid", 403 CharmInfo: &apicharms.CharmInfo{ 404 Metrics: &charm.Metrics{ 405 Plan: &charm.Plan{Required: true}, 406 }, 407 }, 408 } 409 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 410 c.Assert(err, gc.ErrorMatches, `cs:quantal/metered-1 has no default plan. Try "juju deploy --plan <plan-name> with one of thisplan, thisotherplan"`) 411 s.stub.CheckCalls(c, []testing.StubCall{{ 412 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 413 }, { 414 "DefaultPlan", []interface{}{"cs:quantal/metered-1"}, 415 }, { 416 "ListPlans", []interface{}{"cs:quantal/metered-1"}, 417 }}) 418 } 419 420 func (s *registrationSuite) TestMeteredCharmFailToQueryDefaultCharm(c *gc.C) { 421 s.stub.SetErrors(nil, errors.New("something failed")) 422 s.register = &RegisterMeteredCharm{ 423 AllocationSpec: "personal:100", 424 RegisterURL: s.server.URL, 425 QueryURL: s.server.URL} 426 client := httpbakery.NewClient() 427 d := DeploymentInfo{ 428 CharmID: charmstore.CharmID{ 429 URL: charm.MustParseURL("cs:quantal/metered-1"), 430 }, 431 ApplicationName: "application name", 432 ModelUUID: "model uuid", 433 CharmInfo: &apicharms.CharmInfo{ 434 Metrics: &charm.Metrics{ 435 Plan: &charm.Plan{Required: true}, 436 }, 437 }, 438 } 439 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 440 c.Assert(err, gc.ErrorMatches, `failed to query default plan:.*`) 441 s.stub.CheckCalls(c, []testing.StubCall{{ 442 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 443 }, { 444 "DefaultPlan", []interface{}{"cs:quantal/metered-1"}, 445 }}) 446 } 447 448 func (s *registrationSuite) TestUnmeteredCharm(c *gc.C) { 449 client := httpbakery.NewClient() 450 d := DeploymentInfo{ 451 CharmID: charmstore.CharmID{ 452 URL: charm.MustParseURL("cs:quantal/unmetered-1"), 453 }, 454 ApplicationName: "application name", 455 ModelUUID: "model uuid", 456 CharmInfo: &apicharms.CharmInfo{ 457 Metrics: &charm.Metrics{ 458 Plan: &charm.Plan{Required: true}, 459 }, 460 }, 461 } 462 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 463 c.Assert(err, jc.ErrorIsNil) 464 s.stub.CheckCalls(c, []testing.StubCall{{ 465 "IsMetered", []interface{}{"cs:quantal/unmetered-1"}, 466 }}) 467 s.stub.ResetCalls() 468 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 469 c.Assert(err, jc.ErrorIsNil) 470 s.stub.CheckCalls(c, []testing.StubCall{}) 471 } 472 473 func (s *registrationSuite) TestFailedAuth(c *gc.C) { 474 s.stub.SetErrors(nil, errors.Errorf("could not authorize")) 475 client := httpbakery.NewClient() 476 d := DeploymentInfo{ 477 CharmID: charmstore.CharmID{ 478 URL: charm.MustParseURL("cs:quantal/metered-1"), 479 }, 480 ApplicationName: "application name", 481 ModelUUID: "model uuid", 482 CharmInfo: &apicharms.CharmInfo{ 483 Metrics: &charm.Metrics{ 484 Plan: &charm.Plan{Required: true}, 485 }, 486 }, 487 } 488 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 489 c.Assert(err, gc.ErrorMatches, `authorization failed:.*`) 490 authorization, err := json.Marshal([]byte("hello registration")) 491 authorization = append(authorization, byte(0xa)) 492 c.Assert(err, jc.ErrorIsNil) 493 s.stub.CheckCalls(c, []testing.StubCall{{ 494 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 495 }, { 496 "Authorize", []interface{}{metricRegistrationPost{ 497 ModelUUID: "model uuid", 498 CharmURL: "cs:quantal/metered-1", 499 ApplicationName: "application name", 500 PlanURL: "someplan", 501 Budget: "personal", 502 Limit: "100", 503 }}, 504 }}) 505 } 506 507 func (s *registrationSuite) TestPlanArgumentPlanRequiredInteraction(c *gc.C) { 508 tests := []struct { 509 about string 510 planArgument string 511 planRequired bool 512 noDefaultPlan bool 513 apiCalls []string 514 err string 515 }{{ 516 about: "deploy with --plan, required false", 517 planArgument: "plan", 518 planRequired: false, 519 apiCalls: []string{"IsMetered", "Authorize"}, 520 err: "", 521 }, { 522 about: "deploy with --plan, required true", 523 planArgument: "plan", 524 planRequired: true, 525 apiCalls: []string{"IsMetered", "Authorize"}, 526 err: "", 527 }, { 528 about: "deploy without --plan, required false with default plan", 529 planRequired: false, 530 apiCalls: []string{"IsMetered"}, 531 err: "", 532 }, { 533 about: "deploy without --plan, required true with default plan", 534 planRequired: true, 535 apiCalls: []string{"IsMetered", "DefaultPlan", "Authorize"}, 536 err: "", 537 }, { 538 about: "deploy without --plan, required false with no default plan", 539 planRequired: false, 540 noDefaultPlan: true, 541 apiCalls: []string{"IsMetered"}, 542 err: "", 543 }, { 544 about: "deploy without --plan, required true with no default plan", 545 planRequired: true, 546 noDefaultPlan: true, 547 apiCalls: []string{"IsMetered", "DefaultPlan", "ListPlans"}, 548 err: `cs:quantal/metered-1 has no default plan. Try "juju deploy --plan <plan-name> with one of thisplan, thisotherplan"`, 549 }, 550 } 551 for i, test := range tests { 552 s.stub.ResetCalls() 553 c.Logf("running test %d: %s", i, test.about) 554 if test.noDefaultPlan { 555 s.stub.SetErrors(nil, errors.NotFoundf("default plan")) 556 } else { 557 s.stub.SetErrors(nil) 558 } 559 s.register = &RegisterMeteredCharm{ 560 Plan: test.planArgument, 561 AllocationSpec: "personal:100", 562 RegisterURL: s.server.URL, 563 QueryURL: s.server.URL, 564 } 565 client := httpbakery.NewClient() 566 d := DeploymentInfo{ 567 CharmID: charmstore.CharmID{ 568 URL: charm.MustParseURL("cs:quantal/metered-1"), 569 }, 570 ApplicationName: "application name", 571 ModelUUID: "model uuid", 572 CharmInfo: &apicharms.CharmInfo{ 573 Metrics: &charm.Metrics{ 574 Plan: &charm.Plan{Required: test.planRequired}, 575 }, 576 }, 577 } 578 579 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 580 if test.err != "" { 581 c.Assert(err, gc.ErrorMatches, test.err) 582 } else { 583 c.Assert(err, jc.ErrorIsNil) 584 } 585 586 s.stub.CheckCallNames(c, test.apiCalls...) 587 } 588 } 589 590 type testMetricsRegistrationHandler struct { 591 *testing.Stub 592 } 593 594 type respErr struct { 595 Error string `json:"error"` 596 } 597 598 // ServeHTTP implements http.Handler. 599 func (c *testMetricsRegistrationHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { 600 if req.Method == "POST" { 601 var registrationPost metricRegistrationPost 602 decoder := json.NewDecoder(req.Body) 603 err := decoder.Decode(®istrationPost) 604 if err != nil { 605 http.Error(w, "bad request", http.StatusBadRequest) 606 return 607 } 608 c.AddCall("Authorize", registrationPost) 609 rErr := c.NextErr() 610 if rErr != nil { 611 w.WriteHeader(http.StatusInternalServerError) 612 err = json.NewEncoder(w).Encode(respErr{Error: rErr.Error()}) 613 if err != nil { 614 panic(err) 615 } 616 return 617 } 618 err = json.NewEncoder(w).Encode([]byte("hello registration")) 619 if err != nil { 620 panic(err) 621 } 622 } else if req.Method == "GET" { 623 if req.URL.Path == "/default" { 624 cURL := req.URL.Query().Get("charm-url") 625 c.AddCall("DefaultPlan", cURL) 626 rErr := c.NextErr() 627 if rErr != nil { 628 if errors.IsNotFound(rErr) { 629 http.Error(w, rErr.Error(), http.StatusNotFound) 630 return 631 } 632 http.Error(w, rErr.Error(), http.StatusInternalServerError) 633 return 634 } 635 result := struct { 636 URL string `json:"url"` 637 }{"thisplan"} 638 err := json.NewEncoder(w).Encode(result) 639 if err != nil { 640 panic(err) 641 } 642 return 643 } 644 cURL := req.URL.Query().Get("charm-url") 645 c.AddCall("ListPlans", cURL) 646 rErr := c.NextErr() 647 if rErr != nil { 648 http.Error(w, rErr.Error(), http.StatusInternalServerError) 649 return 650 } 651 result := []struct { 652 URL string `json:"url"` 653 }{ 654 {"thisplan"}, 655 {"thisotherplan"}, 656 } 657 err := json.NewEncoder(w).Encode(result) 658 if err != nil { 659 panic(err) 660 } 661 } else { 662 http.Error(w, "method not allowed", http.StatusMethodNotAllowed) 663 return 664 } 665 } 666 667 var _ = gc.Suite(&noPlanRegistrationSuite{}) 668 669 type noPlanRegistrationSuite struct { 670 testing.CleanupSuite 671 stub *testing.Stub 672 handler *testMetricsRegistrationHandler 673 server *httptest.Server 674 register DeployStep 675 ctx *cmd.Context 676 } 677 678 func (s *noPlanRegistrationSuite) SetUpTest(c *gc.C) { 679 s.CleanupSuite.SetUpTest(c) 680 s.stub = &testing.Stub{} 681 s.handler = &testMetricsRegistrationHandler{Stub: s.stub} 682 s.server = httptest.NewServer(s.handler) 683 s.register = &RegisterMeteredCharm{ 684 Plan: "", 685 RegisterURL: s.server.URL, 686 AllocationSpec: "personal:100", 687 } 688 s.ctx = coretesting.Context(c) 689 } 690 691 func (s *noPlanRegistrationSuite) TearDownTest(c *gc.C) { 692 s.CleanupSuite.TearDownTest(c) 693 s.server.Close() 694 } 695 func (s *noPlanRegistrationSuite) TestOptionalPlanMeteredCharm(c *gc.C) { 696 client := httpbakery.NewClient() 697 d := DeploymentInfo{ 698 CharmID: charmstore.CharmID{ 699 URL: charm.MustParseURL("cs:quantal/metered-1"), 700 }, 701 ApplicationName: "application name", 702 ModelUUID: "model uuid", 703 CharmInfo: &apicharms.CharmInfo{ 704 Metrics: &charm.Metrics{ 705 Plan: &charm.Plan{Required: false}, 706 }, 707 }, 708 } 709 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 710 c.Assert(err, jc.ErrorIsNil) 711 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 712 c.Assert(err, jc.ErrorIsNil) 713 s.stub.CheckCalls(c, []testing.StubCall{{ 714 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 715 }}) 716 } 717 718 func (s *noPlanRegistrationSuite) TestPlanNotSpecifiedCharm(c *gc.C) { 719 client := httpbakery.NewClient() 720 d := DeploymentInfo{ 721 CharmID: charmstore.CharmID{ 722 URL: charm.MustParseURL("cs:quantal/metered-1"), 723 }, 724 ApplicationName: "application name", 725 ModelUUID: "model uuid", 726 CharmInfo: &apicharms.CharmInfo{ 727 Metrics: &charm.Metrics{ 728 Plan: nil, 729 }, 730 }, 731 } 732 err := s.register.RunPre(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d) 733 c.Assert(err, jc.ErrorIsNil) 734 err = s.register.RunPost(&mockMeteredDeployAPI{Stub: s.stub}, client, s.ctx, d, nil) 735 c.Assert(err, jc.ErrorIsNil) 736 s.stub.CheckCalls(c, []testing.StubCall{{ 737 "IsMetered", []interface{}{"cs:quantal/metered-1"}, 738 }}) 739 } 740 741 type mockMeteredDeployAPI struct { 742 MeteredDeployAPI 743 *testing.Stub 744 } 745 746 func (m *mockMeteredDeployAPI) IsMetered(charmURL string) (bool, error) { 747 m.AddCall("IsMetered", charmURL) 748 if charmURL == "cs:quantal/metered-1" || charmURL == "local:quantal/metered-1" { 749 return true, m.NextErr() 750 } 751 return false, m.NextErr() 752 753 } 754 func (m *mockMeteredDeployAPI) SetMetricCredentials(service string, credentials []byte) error { 755 m.AddCall("SetMetricCredentials", service, credentials) 756 return m.NextErr() 757 }