Skip to content

Commit

Permalink
Combine applicationoffers and remoteendpoints facades onto a single c…
Browse files Browse the repository at this point in the history
…ontroller facade
  • Loading branch information
wallyworld committed Apr 27, 2017
1 parent b15a4fe commit 92571a4
Show file tree
Hide file tree
Showing 28 changed files with 1,009 additions and 1,349 deletions.
60 changes: 60 additions & 0 deletions api/applicationoffers/client.go
Expand Up @@ -151,3 +151,63 @@ func (c *Client) modifyOfferUser(action params.OfferAction, user, access string,
}
return result.Combine()
}

// ApplicationOffer returns offered remote application details for a given URL.
func (c *Client) ApplicationOffer(urlStr string) (params.ApplicationOffer, error) {

url, err := crossmodel.ParseApplicationURL(urlStr)
if err != nil {
return params.ApplicationOffer{}, errors.Trace(err)
}
if url.Source != "" {
return params.ApplicationOffer{}, errors.NotSupportedf("query for non-local application offers")
}

found := params.ApplicationOffersResults{}

err = c.facade.FacadeCall("ApplicationOffers", params.ApplicationURLs{[]string{urlStr}}, &found)
if err != nil {
return params.ApplicationOffer{}, errors.Trace(err)
}

result := found.Results
if len(result) != 1 {
return params.ApplicationOffer{}, errors.Errorf("expected to find one result for url %q but found %d", url, len(result))
}

theOne := result[0]
if theOne.Error != nil {
return params.ApplicationOffer{}, errors.Trace(theOne.Error)
}
return theOne.Result, nil
}

// FindApplicationOffers returns all application offers matching the supplied filter.
func (c *Client) FindApplicationOffers(filters ...crossmodel.ApplicationOfferFilter) ([]params.ApplicationOffer, error) {
// We need at least one filter. The default filter will list all local applications.
if len(filters) == 0 {
return nil, errors.New("at least one filter must be specified")
}
var paramsFilter params.OfferFilters
for _, f := range filters {
filterTerm := params.OfferFilter{
OfferName: f.OfferName,
ModelName: f.ModelName,
OwnerName: f.OwnerName,
}
filterTerm.Endpoints = make([]params.EndpointFilterAttributes, len(f.Endpoints))
for i, ep := range f.Endpoints {
filterTerm.Endpoints[i].Name = ep.Name
filterTerm.Endpoints[i].Interface = ep.Interface
filterTerm.Endpoints[i].Role = ep.Role
}
paramsFilter.Filters = append(paramsFilter.Filters, filterTerm)
}

out := params.FindApplicationOffersResults{}
err := c.facade.FacadeCall("FindApplicationOffers", paramsFilter, &out)
if err != nil {
return nil, errors.Trace(err)
}
return out.Results, nil
}
321 changes: 321 additions & 0 deletions api/applicationoffers/client_test.go
Expand Up @@ -209,3 +209,324 @@ func (s *crossmodelMockSuite) TestListFacadeCallError(c *gc.C) {
c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
c.Assert(results, gc.IsNil)
}

func (s *crossmodelMockSuite) TestShow(c *gc.C) {
url := "fred/model.db2"

desc := "IBM DB2 Express Server Edition is an entry level database system"
endpoints := []params.RemoteEndpoint{
{Name: "db2", Interface: "db2", Role: charm.RoleProvider},
{Name: "log", Interface: "http", Role: charm.RoleRequirer},
}
offerName := "hosted-db2"
access := "consume"

called := false

apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
called = true

c.Check(objType, gc.Equals, "applicationoffers")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "ApplicationOffers")

args, ok := a.(params.ApplicationURLs)
c.Assert(ok, jc.IsTrue)
c.Assert(args.ApplicationURLs, gc.DeepEquals, []string{url})

if points, ok := result.(*params.ApplicationOffersResults); ok {
points.Results = []params.ApplicationOfferResult{
{Result: params.ApplicationOffer{
ApplicationDescription: desc,
Endpoints: endpoints,
OfferURL: url,
OfferName: offerName,
Access: access,
}},
}
}
return nil
})
client := applicationoffers.NewClient(apiCaller)
found, err := client.ApplicationOffer(url)
c.Assert(err, jc.ErrorIsNil)

c.Assert(called, jc.IsTrue)
c.Assert(found, gc.DeepEquals, params.ApplicationOffer{
ApplicationDescription: desc,
Endpoints: endpoints,
OfferURL: url,
OfferName: offerName,
Access: access})
}

func (s *crossmodelMockSuite) TestShowURLError(c *gc.C) {
url := "fred/model.db2"
msg := "facade failure"

called := false

apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
called = true

c.Check(objType, gc.Equals, "applicationoffers")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "ApplicationOffers")

args, ok := a.(params.ApplicationURLs)
c.Assert(ok, jc.IsTrue)
c.Assert(args.ApplicationURLs, gc.DeepEquals, []string{url})

if points, ok := result.(*params.ApplicationOffersResults); ok {
points.Results = []params.ApplicationOfferResult{
{Error: common.ServerError(errors.New(msg))}}
}
return nil
})
client := applicationoffers.NewClient(apiCaller)
found, err := client.ApplicationOffer(url)

c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
c.Assert(found, gc.DeepEquals, params.ApplicationOffer{})
c.Assert(called, jc.IsTrue)
}

func (s *crossmodelMockSuite) TestShowMultiple(c *gc.C) {
url := "fred/model.db2"

desc := "IBM DB2 Express Server Edition is an entry level database system"
endpoints := []params.RemoteEndpoint{
{Name: "db2", Interface: "db2", Role: charm.RoleProvider},
{Name: "log", Interface: "http", Role: charm.RoleRequirer},
}
offerName := "hosted-db2"
access := "consume"

called := false

apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
called = true

c.Check(objType, gc.Equals, "applicationoffers")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "ApplicationOffers")

args, ok := a.(params.ApplicationURLs)
c.Assert(ok, jc.IsTrue)
c.Assert(args.ApplicationURLs, gc.DeepEquals, []string{url})

if points, ok := result.(*params.ApplicationOffersResults); ok {
points.Results = []params.ApplicationOfferResult{
{Result: params.ApplicationOffer{
ApplicationDescription: desc,
Endpoints: endpoints,
OfferURL: url,
OfferName: offerName,
Access: access,
}},
{Result: params.ApplicationOffer{
ApplicationDescription: desc,
Endpoints: endpoints,
OfferURL: url,
OfferName: offerName,
Access: access,
}}}
}
return nil
})
client := applicationoffers.NewClient(apiCaller)
found, err := client.ApplicationOffer(url)
c.Assert(err, gc.ErrorMatches, fmt.Sprintf(`expected to find one result for url %q but found 2`, url))
c.Assert(found, gc.DeepEquals, params.ApplicationOffer{})

c.Assert(called, jc.IsTrue)
}

func (s *crossmodelMockSuite) TestShowNonLocal(c *gc.C) {
url := "jaas:fred/model.db2"
msg := "query for non-local application offers not supported"

called := false

apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
called = true
return nil
})
client := applicationoffers.NewClient(apiCaller)
found, err := client.ApplicationOffer(url)

c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
c.Assert(found, gc.DeepEquals, params.ApplicationOffer{})
c.Assert(called, jc.IsFalse)
}

func (s *crossmodelMockSuite) TestShowFacadeCallError(c *gc.C) {
msg := "facade failure"
apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
c.Check(objType, gc.Equals, "applicationoffers")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "ApplicationOffers")

return errors.New(msg)
})
client := applicationoffers.NewClient(apiCaller)
found, err := client.ApplicationOffer("fred/model.db2")
c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
c.Assert(found, gc.DeepEquals, params.ApplicationOffer{})
}

func (s *crossmodelMockSuite) TestFind(c *gc.C) {
offerName := "hosted-db2"
ownerName := "owner"
modelName := "model"
access := "consume"
url := fmt.Sprintf("fred/model.%s", offerName)
endpoints := []params.RemoteEndpoint{{Name: "endPointA"}}
relations := []jujucrossmodel.EndpointFilterTerm{{Name: "endPointA", Interface: "http"}}

filter := jujucrossmodel.ApplicationOfferFilter{
OwnerName: ownerName,
ModelName: modelName,
OfferName: offerName,
Endpoints: relations,
}

called := false
apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
c.Check(objType, gc.Equals, "applicationoffers")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "FindApplicationOffers")

called = true
args, ok := a.(params.OfferFilters)
c.Assert(ok, jc.IsTrue)
c.Assert(args.Filters, gc.HasLen, 1)
c.Assert(args.Filters[0], jc.DeepEquals, params.OfferFilter{
OwnerName: filter.OwnerName,
ModelName: filter.ModelName,
OfferName: filter.OfferName,
ApplicationName: filter.ApplicationName,
Endpoints: []params.EndpointFilterAttributes{{
Name: "endPointA",
Interface: "http",
}},
})

if results, ok := result.(*params.FindApplicationOffersResults); ok {
offer := params.ApplicationOffer{
OfferURL: url,
OfferName: offerName,
Endpoints: endpoints,
Access: access,
}
results.Results = []params.ApplicationOffer{offer}
}
return nil
})

client := applicationoffers.NewClient(apiCaller)
results, err := client.FindApplicationOffers(filter)
c.Assert(err, jc.ErrorIsNil)
c.Assert(called, jc.IsTrue)
c.Assert(results, jc.DeepEquals, []params.ApplicationOffer{{
OfferURL: url,
OfferName: offerName,
Endpoints: endpoints,
Access: access,
}})
}

func (s *crossmodelMockSuite) TestFindNoFilter(c *gc.C) {
apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
c.Fail()
return nil
})

client := applicationoffers.NewClient(apiCaller)
_, err := client.FindApplicationOffers()
c.Assert(err, gc.ErrorMatches, "at least one filter must be specified")
}

func (s *crossmodelMockSuite) TestFindError(c *gc.C) {
msg := "find failure"
called := false
apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
c.Check(objType, gc.Equals, "applicationoffers")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "FindApplicationOffers")

called = true
return errors.New(msg)
})

client := applicationoffers.NewClient(apiCaller)
filter := jujucrossmodel.ApplicationOfferFilter{
OfferName: "foo",
}
_, err := client.FindApplicationOffers(filter)
c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
c.Assert(called, jc.IsTrue)
}

func (s *crossmodelMockSuite) TestFindFacadeCallError(c *gc.C) {
msg := "facade failure"
apiCaller := basetesting.APICallerFunc(
func(objType string,
version int,
id, request string,
a, result interface{},
) error {
c.Check(objType, gc.Equals, "applicationoffers")
c.Check(id, gc.Equals, "")
c.Check(request, gc.Equals, "FindApplicationOffers")

return errors.New(msg)
})
client := applicationoffers.NewClient(apiCaller)
filter := jujucrossmodel.ApplicationOfferFilter{
OfferName: "foo",
}
results, err := client.FindApplicationOffers(filter)
c.Assert(errors.Cause(err), gc.ErrorMatches, msg)
c.Assert(results, gc.IsNil)
}
1 change: 0 additions & 1 deletion api/facadeversions.go
Expand Up @@ -69,7 +69,6 @@ var facadeVersions = map[string]int{
"ProxyUpdater": 1,
"Reboot": 2,
"RelationUnitsWatcher": 1,
"RemoteEndpoints": 1,
"RemoteFirewaller": 1,
"RemoteRelations": 1,
"Resources": 1,
Expand Down

0 comments on commit 92571a4

Please sign in to comment.