forked from juju/juju
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Move as much API HTTP code as possible into its own package.
- Loading branch information
1 parent
7a2c4b9
commit 837f41f
Showing
9 changed files
with
225 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright 2014 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package http | ||
|
||
import ( | ||
"net/http" | ||
) | ||
|
||
// Request is a wrapper around an HTTP request that has been | ||
// prepared for use in API HTTP calls. | ||
type Request struct { | ||
http.Request | ||
} | ||
|
||
// HTTPClient is an API-specific HTTP client. | ||
type HTTPClient interface { | ||
// Do sends the HTTP request, returning the subsequent response. | ||
Do(req *http.Request) (*http.Response, error) | ||
} | ||
|
||
// Client exposes direct HTTP request functionality for the juju state | ||
// API. This is significant for upload and download of files, which the | ||
// websockets-based RPC does not support. | ||
type Client interface { | ||
// NewHTTPRequest returns a new API-specific HTTP request. Callers | ||
// should finish the request (setting headers, body) before sending. | ||
NewHTTPRequest(method, path string) (*Request, error) | ||
// SendHTTPRequest returns the HTTP response from the API server. | ||
// The caller is then responsible for handling the response. | ||
SendHTTPRequest(req *Request) (*http.Response, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
// Copyright 2014 Canonical Ltd. | ||
// Licensed under the LGPLv3, see LICENCE file for details. | ||
|
||
package http_test | ||
|
||
import ( | ||
"testing" | ||
|
||
gc "gopkg.in/check.v1" | ||
) | ||
|
||
func TestPackage(t *testing.T) { | ||
gc.TestingT(t) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// Copyright 2014 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package http | ||
|
||
import ( | ||
"net/http" | ||
"net/url" | ||
"path" | ||
|
||
"github.com/juju/errors" | ||
) | ||
|
||
// NewRequest returns a new HTTP request suitable for the API. | ||
func NewRequest(method string, baseURL *url.URL, pth, uuid, tag, pw string) (*Request, error) { | ||
baseURL.Path = path.Join("/environment", uuid, pth) | ||
req, err := http.NewRequest(method, baseURL.String(), nil) | ||
if err != nil { | ||
return nil, errors.Annotate(err, "while building HTTP request") | ||
} | ||
req.SetBasicAuth(tag, pw) | ||
return &Request{*req}, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
// Copyright 2014 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package http_test | ||
|
||
import ( | ||
"net/url" | ||
|
||
gc "gopkg.in/check.v1" | ||
|
||
apihttp "github.com/juju/juju/api/http" | ||
apihttptesting "github.com/juju/juju/api/http/testing" | ||
) | ||
|
||
type requestSuite struct { | ||
apihttptesting.BaseSuite | ||
} | ||
|
||
var _ = gc.Suite(&requestSuite{}) | ||
|
||
func (s *requestSuite) SetUpTest(c *gc.C) { | ||
s.BaseSuite.SetUpTest(c) | ||
} | ||
|
||
func (s *requestSuite) TestNewRequestSuccess(c *gc.C) { | ||
baseURL, err := url.Parse("https://localhost:8080/") | ||
c.Assert(err, gc.IsNil) | ||
uuid := "abcd-efedcb-012345-6789" | ||
tag := "machine-0" | ||
pw := "secure" | ||
req, err := apihttp.NewRequest("GET", baseURL, "somefacade", uuid, tag, pw) | ||
c.Assert(err, gc.IsNil) | ||
|
||
s.CheckRequest(c, req, "GET", tag, pw, "localhost", "somefacade") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
// Copyright 2014 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package testing | ||
|
||
import ( | ||
"bytes" | ||
"io/ioutil" | ||
"net/http" | ||
|
||
gc "gopkg.in/check.v1" | ||
) | ||
|
||
// FakeHTTPClient is used in testing in place of an actual http.Client. | ||
type FakeHTTPClient struct { | ||
// Error is the error that will be returned for any calls. | ||
Error error | ||
// Response is the response returned from calls. | ||
Response *http.Response | ||
|
||
// Calls is the record of which methods were called. | ||
Calls []string | ||
// RequestArg is the request that was passed to a call. | ||
RequestArg *http.Request | ||
} | ||
|
||
// NewFakeHTTPClient returns a fake with Response set to an OK status, | ||
// no headers, and no body. | ||
func NewFakeHTTPClient() *FakeHTTPClient { | ||
resp := http.Response{ | ||
StatusCode: http.StatusOK, | ||
Header: make(http.Header), | ||
Body: ioutil.NopCloser(&bytes.Buffer{}), | ||
} | ||
|
||
fake := FakeHTTPClient{ | ||
Response: &resp, | ||
} | ||
return &fake | ||
} | ||
|
||
// CheckCalled checks that the Do was called once with the request and | ||
// returned the correct value. | ||
func (f *FakeHTTPClient) CheckCalled(c *gc.C, req *http.Request, resp *http.Response) { | ||
c.Check(f.Calls, gc.DeepEquals, []string{"Do"}) | ||
c.Check(f.RequestArg, gc.Equals, req) | ||
c.Check(resp, gc.Equals, f.Response) | ||
} | ||
|
||
// Do fakes the behavior of http.Client.Do(). | ||
func (f *FakeHTTPClient) Do(req *http.Request) (*http.Response, error) { | ||
f.Calls = append(f.Calls, "Do") | ||
f.RequestArg = req | ||
return f.Response, f.Error | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
// Copyright 2014 Canonical Ltd. | ||
// Licensed under the AGPLv3, see LICENCE file for details. | ||
|
||
package testing | ||
|
||
import ( | ||
"encoding/base64" | ||
|
||
gc "gopkg.in/check.v1" | ||
|
||
apihttp "github.com/juju/juju/api/http" | ||
"github.com/juju/juju/testing" | ||
) | ||
|
||
// BaseSuite provides basic testing capability for API HTTP tests. | ||
type BaseSuite struct { | ||
testing.BaseSuite | ||
// Fake is the fake HTTP client used in tests. | ||
Fake *FakeHTTPClient | ||
} | ||
|
||
func (s *BaseSuite) SetUpTest(c *gc.C) { | ||
s.BaseSuite.SetUpTest(c) | ||
|
||
s.Fake = NewFakeHTTPClient() | ||
} | ||
|
||
func (s *BaseSuite) CheckRequest(c *gc.C, req *apihttp.Request, method, user, pw, host, pth string) { | ||
// Only check API-related request fields. | ||
|
||
c.Check(req.Method, gc.Equals, method) | ||
|
||
url := `https://` + host + `:\d+/environment/[-0-9a-f]+/` + pth | ||
c.Check(req.URL.String(), gc.Matches, url) | ||
|
||
c.Assert(req.Header, gc.HasLen, 1) | ||
auth := base64.StdEncoding.EncodeToString([]byte(user + ":" + pw)) | ||
c.Check(req.Header.Get("Authorization"), gc.Equals, "Basic "+auth) | ||
} |
Oops, something went wrong.