From f769a83cb5cd4c7b82cacba221d42d52e9dd3aa9 Mon Sep 17 00:00:00 2001 From: Stamatis Katsaounis Date: Thu, 2 May 2024 16:35:13 +0300 Subject: [PATCH 1/2] feat: add methods to put and update with files --- client.go | 5 +++++ client_test.go | 40 ++++++++++++++++++++++++++++++++-------- maasobject.go | 15 +++++++++++++++ 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/client.go b/client.go index d90c010..a43f478 100644 --- a/client.go +++ b/client.go @@ -252,6 +252,11 @@ func (client Client) Put(uri *url.URL, parameters url.Values) ([]byte, error) { return client.nonIdempotentRequest("PUT", uri, parameters) } +// PutFiles updates an object on the API, using an HTTP "PUT" request. +func (client Client) PutFiles(uri *url.URL, parameters url.Values, files map[string][]byte) ([]byte, error) { + return client.nonIdempotentRequestFiles("PUT", uri, parameters, files) +} + // Delete deletes an object on the API, using an HTTP "DELETE" request. func (client Client) Delete(uri *url.URL) error { url := client.GetURL(uri) diff --git a/client_test.go b/client_test.go index 1cff8a4..f07bc00 100644 --- a/client_test.go +++ b/client_test.go @@ -276,25 +276,27 @@ func (suite *ClientSuite) TestClientPostSendsRequestWithParams(c *gc.C) { c.Check(postedValues, jc.DeepEquals, expectedPostedValues) } -// extractFileContent extracts from the request built using 'requestContent', +// extractFileContentAndParamValue extracts from the request built using 'requestContent', // 'requestHeader' and 'requestURL', the file named 'filename'. -func extractFileContent(requestContent string, requestHeader *http.Header, requestURL string, _ string) ([]byte, error) { +// In addition, it extracts the url.Value of the given 'key'. +func extractFileContentAndParamValue(requestContent string, requestHeader *http.Header, requestURL string, filename string, key string) ([]byte, string, error) { // Recreate the request from server.requestContent to use the parsing // utility from the http package (http.Request.FormFile). request, err := http.NewRequest("POST", requestURL, bytes.NewBufferString(requestContent)) if err != nil { - return nil, err + return nil, "", err } request.Header.Set("Content-Type", requestHeader.Get("Content-Type")) - file, _, err := request.FormFile("testfile") + file, _, err := request.FormFile(filename) if err != nil { - return nil, err + return nil, "", err } fileContent, err := io.ReadAll(file) if err != nil { - return nil, err + return nil, "", err } - return fileContent, nil + + return fileContent, request.FormValue(key), nil } func (suite *ClientSuite) TestClientPostSendsMultipartRequest(c *gc.C) { @@ -313,7 +315,7 @@ func (suite *ClientSuite) TestClientPostSendsMultipartRequest(c *gc.C) { c.Assert(err, jc.ErrorIsNil) c.Check(string(result), gc.Equals, expectedResult) - receivedFileContent, err := extractFileContent(*server.requestContent, server.requestHeader, fullURI, "testfile") + receivedFileContent, _, err := extractFileContentAndParamValue(*server.requestContent, server.requestHeader, fullURI, "testfile", "") c.Assert(err, jc.ErrorIsNil) c.Check(receivedFileContent, jc.DeepEquals, fileContent) } @@ -335,6 +337,28 @@ func (suite *ClientSuite) TestClientPutSendsRequest(c *gc.C) { c.Check(*server.requestContent, gc.Equals, "test=123") } +func (suite *ClientSuite) TestClientPutFilesSendsRequest(c *gc.C) { + URI, err := url.Parse("/some/url") + c.Assert(err, jc.ErrorIsNil) + expectedResult := "expected:result" + params := url.Values{"test": {"123"}} + server := newSingleServingServer(URI.String(), expectedResult, http.StatusOK, -1) + defer server.Close() + client, err := NewAnonymousClient(server.URL, "1.0") + c.Assert(err, jc.ErrorIsNil) + fileContent := []byte("content") + files := map[string][]byte{"testfile": fileContent} + + result, err := client.PutFiles(URI, params, files) + + c.Assert(err, jc.ErrorIsNil) + c.Check(string(result), gc.Equals, expectedResult) + receivedFileContent, value, err := extractFileContentAndParamValue(*server.requestContent, server.requestHeader, URI.String(), "testfile", "test") + c.Assert(err, jc.ErrorIsNil) + c.Check(receivedFileContent, jc.DeepEquals, fileContent) + c.Check(value, gc.Equals, "123") +} + func (suite *ClientSuite) TestClientDeleteSendsRequest(c *gc.C) { URI, err := url.Parse("/some/url") c.Assert(err, jc.ErrorIsNil) diff --git a/maasobject.go b/maasobject.go index 3978252..55ac593 100644 --- a/maasobject.go +++ b/maasobject.go @@ -163,6 +163,21 @@ func (obj MAASObject) Update(params url.Values) (MAASObject, error) { return jsonObj.GetMAASObject() } +// UpdateFiles modifies this object on the API, based on the values given in +// "params." It returns the object's new value as received from the API. +func (obj MAASObject) UpdateFiles(params url.Values, files map[string][]byte) (MAASObject, error) { + uri := obj.URI() + result, err := obj.client.PutFiles(uri, params, files) + if err != nil { + return MAASObject{}, err + } + jsonObj, err := Parse(obj.client, result) + if err != nil { + return MAASObject{}, err + } + return jsonObj.GetMAASObject() +} + // Delete removes this object on the API. func (obj MAASObject) Delete() error { uri := obj.URI() From 2435e09ae62816d907d2b32ef4f0878595b4fd6c Mon Sep 17 00:00:00 2001 From: Stamatis Katsaounis Date: Mon, 3 Jun 2024 10:08:13 +0300 Subject: [PATCH 2/2] update based on code review --- client.go | 10 ++++------ client_test.go | 19 +------------------ controller.go | 2 +- maasobject.go | 4 ++-- 4 files changed, 8 insertions(+), 27 deletions(-) diff --git a/client.go b/client.go index a43f478..5be4414 100644 --- a/client.go +++ b/client.go @@ -248,15 +248,13 @@ func (client Client) Post(uri *url.URL, operation string, parameters url.Values, } // Put updates an object on the API, using an HTTP "PUT" request. -func (client Client) Put(uri *url.URL, parameters url.Values) ([]byte, error) { +func (client Client) Put(uri *url.URL, parameters url.Values, files map[string][]byte) ([]byte, error) { + if files != nil { + return client.nonIdempotentRequestFiles("PUT", uri, parameters, files) + } return client.nonIdempotentRequest("PUT", uri, parameters) } -// PutFiles updates an object on the API, using an HTTP "PUT" request. -func (client Client) PutFiles(uri *url.URL, parameters url.Values, files map[string][]byte) ([]byte, error) { - return client.nonIdempotentRequestFiles("PUT", uri, parameters, files) -} - // Delete deletes an object on the API, using an HTTP "DELETE" request. func (client Client) Delete(uri *url.URL) error { url := client.GetURL(uri) diff --git a/client_test.go b/client_test.go index f07bc00..f599679 100644 --- a/client_test.go +++ b/client_test.go @@ -329,27 +329,10 @@ func (suite *ClientSuite) TestClientPutSendsRequest(c *gc.C) { defer server.Close() client, err := NewAnonymousClient(server.URL, "1.0") c.Assert(err, jc.ErrorIsNil) - - result, err := client.Put(URI, params) - - c.Assert(err, jc.ErrorIsNil) - c.Check(string(result), gc.Equals, expectedResult) - c.Check(*server.requestContent, gc.Equals, "test=123") -} - -func (suite *ClientSuite) TestClientPutFilesSendsRequest(c *gc.C) { - URI, err := url.Parse("/some/url") - c.Assert(err, jc.ErrorIsNil) - expectedResult := "expected:result" - params := url.Values{"test": {"123"}} - server := newSingleServingServer(URI.String(), expectedResult, http.StatusOK, -1) - defer server.Close() - client, err := NewAnonymousClient(server.URL, "1.0") - c.Assert(err, jc.ErrorIsNil) fileContent := []byte("content") files := map[string][]byte{"testfile": fileContent} - result, err := client.PutFiles(URI, params, files) + result, err := client.Put(URI, params, files) c.Assert(err, jc.ErrorIsNil) c.Check(string(result), gc.Equals, expectedResult) diff --git a/controller.go b/controller.go index 7b266fb..105bc16 100644 --- a/controller.go +++ b/controller.go @@ -775,7 +775,7 @@ func (c *controller) put(path string, params url.Values) (interface{}, error) { path = EnsureTrailingSlash(path) requestID := nextRequestID() logger.Tracef("request %x: PUT %s%s, params: %s", requestID, c.client.APIURL, path, params.Encode()) - bytes, err := c.client.Put(&url.URL{Path: path}, params) + bytes, err := c.client.Put(&url.URL{Path: path}, params, nil) if err != nil { logger.Tracef("response %x: error: %q", requestID, err.Error()) logger.Tracef("error detail: %#v", err) diff --git a/maasobject.go b/maasobject.go index 55ac593..126afb1 100644 --- a/maasobject.go +++ b/maasobject.go @@ -152,7 +152,7 @@ func (obj MAASObject) Post(params url.Values) (JSONObject, error) { // "params." It returns the object's new value as received from the API. func (obj MAASObject) Update(params url.Values) (MAASObject, error) { uri := obj.URI() - result, err := obj.client.Put(uri, params) + result, err := obj.client.Put(uri, params, nil) if err != nil { return MAASObject{}, err } @@ -167,7 +167,7 @@ func (obj MAASObject) Update(params url.Values) (MAASObject, error) { // "params." It returns the object's new value as received from the API. func (obj MAASObject) UpdateFiles(params url.Values, files map[string][]byte) (MAASObject, error) { uri := obj.URI() - result, err := obj.client.PutFiles(uri, params, files) + result, err := obj.client.Put(uri, params, files) if err != nil { return MAASObject{}, err }