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