1
0
mirror of https://github.com/SAP/jenkins-library.git synced 2024-12-14 11:03:09 +02:00
sap-jenkins-library/pkg/http/http_test.go

687 lines
23 KiB
Go
Raw Normal View History

//go:build unit
// +build unit
package http
import (
"bytes"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/xml"
"errors"
"fmt"
"io"
2020-01-14 11:29:50 +02:00
"mime/multipart"
"net/http"
"net/http/httptest"
[TMS] Reimplement tmsUpload step in Go (#3399) * Initially generated tmsUpload<...> files * First provisioning of parameters supported by tmsUpload step * Refer to Go step from tmsUpload.groovy * Initial client implementation * Reverting line delimiters in tmsUpoad.groovy back to Unix ones * Temporarily remove when-condition for Release stage * Define useGoStep parameter in tmsUpload.groovy * Unstash buildResult if useGoStep is true * No unstashing and empty credentials, when using go step * Register TmsUploadCommand in piper.go * Cleanup groovy-related changes - they will be temporarily implemented in a different repo * Make getting OAuth token success * Look through the code and cleanup it a bit * Read service key from Jenkins credentials store * Provide initial set of unit tests for methods in /pkg/tms/tms.go file * Minor improvements on logging response on http call error * Check, if positive HTTP status code is as expected * Cleanup tms.yaml file, provide additional unit test for tms.go * Provide unit test for the case, when request body contains spaces * Specify nodeExtDescriptorMapping parameter as of type map in tms.yaml * Implement client method for getting nodes * Write tests for GetNodes method * Add GetMtaExtDescriptor client method and cover it with unit tests * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide UploadFile and UploadFileToNode client methods * Provide tests for Update- and UploadMtaExtDescriptor client methods * Write tests for FileUpload and FileUploadToNode client methods * Minor corrections * Remove some TODO comments * Rename some of response structures * Revert change for line delimiters in cmd/piper.go * Add uploadType string parameter to UploadFile and UploadRequest methods of uploader mock to reflect the changed Uploader implementation * Start to implement execution logic in tmsUpload.go * Changes in tms.yaml file - remove resources from inputs in tms.yaml and implement mtaPath parameter settings in the yaml file the same way, as it is done in cloudFoundryDeploy.yaml - rename tms.yaml to tmsUpload.yaml, since some generation policy changed meanwhile * Rename tms.yaml to tmsUpload.yaml and do go generate * Use provided proxy on communication with UAA and TMS * Set proxy even before getting OAuth token * Further implementation of tmsUpload.go * Continuation on implementing the tmsUpload.go executor * Get mtarFilePath and git commitId from commonPipelineEnvironment, if they are missing in configuration file + minor changes * Implement a happy path test for tmsUpload logic * Cover with unit tests main happy and error paths of tmsUpload.go logic * Extend set of unit tests for tmsUpload.go * Eliminate some TODOs, extend unit tests for tmsUpload.go * Delete some TODOs * Remove a couple of more TODOs from tms_test.go file * Provide additional unit test for error due unexpected positive http status code on upload * Revert back line delimiters in cmd/piper.go * Comment out file uploading calls in tmsUpload.go * Run go generate to update generated files * Convert line delimiters in tmsUpload.yaml to Unix ones, as well as provide new line character in the end of the file, plus minor fix for logging in tmsUpload.go file (pipeline complained) * Correct description of a parameter in tmsUpload.yaml, extend unit tests to check for trimming a slash in the end of TMS url for client methods that do upload * [minor] Add a comment in the test code * Add stashContent parameter to do unstashing in tmsUpload.groovy, remove some of the clarified TODOs * Uncomment uploading file calls in tmsUpload.go, declare buildResult stash in tmsUpload.yaml * Remove clarified TODOs from the tmsUpload.go file * Run go fmt for jenkins-library/pkg/tms * Do not get explicitly values from common pipeline environment - all configurations are provided in yaml file * Remove unused struct from tmsUpload_test.go * Run go fmt jenkins-library\pkg\tms * Revise descriptions of parameters provided in tmsUpload.yaml file * Specify STAGES scope for tmsUpload parameters * Provide STAGES scope for the tmsUpload parameters, provide default value for stashContent parameter * Remove trailing space from tmsUpload.yaml * Provide unit tests for proxy-related changes in http.go file * Improve proxy implementation in tmsUpload.go file * Make tmsServiceKey again a mandatory parameter * Run go generate command to make the generated files correspond the yaml state * Change line delimiters back to Unix ones (were switched while resolving the conflicts) * Remove trailing spaces from tmsUpload.yaml * Minor change in a comment to trigger pipelines with commit * Improve checks for zero-structs and for empty maps, as well as use different package to read files in the tests * Revert line endings in http.go * Revert comments formatting changes in files that do not belong to the tmsUpload step
2022-08-30 10:16:09 +02:00
"net/url"
2020-01-14 11:29:50 +02:00
"os"
"path/filepath"
"testing"
"time"
"github.com/jarcoal/httpmock"
"github.com/sirupsen/logrus"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"github.com/SAP/jenkins-library/pkg/log"
)
func TestSend(t *testing.T) {
testURL := "https://example.org"
request, err := http.NewRequest(http.MethodGet, testURL, nil)
require.NoError(t, err)
t.Run("success", func(t *testing.T) {
// given
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(http.MethodGet, testURL, httpmock.NewStringResponder(200, `OK`))
client := Client{}
client.SetOptions(ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
// when
response, err := client.Send(request)
// then
assert.NoError(t, err)
assert.NotNil(t, response)
})
t.Run("failure", func(t *testing.T) {
// given
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(http.MethodGet, testURL, httpmock.NewErrorResponder(errors.New("failure")))
client := Client{}
client.SetOptions(ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
// when
response, err := client.Send(request)
// then
assert.Error(t, err)
assert.Nil(t, response)
})
[TMS] Reimplement tmsUpload step in Go (#3399) * Initially generated tmsUpload<...> files * First provisioning of parameters supported by tmsUpload step * Refer to Go step from tmsUpload.groovy * Initial client implementation * Reverting line delimiters in tmsUpoad.groovy back to Unix ones * Temporarily remove when-condition for Release stage * Define useGoStep parameter in tmsUpload.groovy * Unstash buildResult if useGoStep is true * No unstashing and empty credentials, when using go step * Register TmsUploadCommand in piper.go * Cleanup groovy-related changes - they will be temporarily implemented in a different repo * Make getting OAuth token success * Look through the code and cleanup it a bit * Read service key from Jenkins credentials store * Provide initial set of unit tests for methods in /pkg/tms/tms.go file * Minor improvements on logging response on http call error * Check, if positive HTTP status code is as expected * Cleanup tms.yaml file, provide additional unit test for tms.go * Provide unit test for the case, when request body contains spaces * Specify nodeExtDescriptorMapping parameter as of type map in tms.yaml * Implement client method for getting nodes * Write tests for GetNodes method * Add GetMtaExtDescriptor client method and cover it with unit tests * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide UploadFile and UploadFileToNode client methods * Provide tests for Update- and UploadMtaExtDescriptor client methods * Write tests for FileUpload and FileUploadToNode client methods * Minor corrections * Remove some TODO comments * Rename some of response structures * Revert change for line delimiters in cmd/piper.go * Add uploadType string parameter to UploadFile and UploadRequest methods of uploader mock to reflect the changed Uploader implementation * Start to implement execution logic in tmsUpload.go * Changes in tms.yaml file - remove resources from inputs in tms.yaml and implement mtaPath parameter settings in the yaml file the same way, as it is done in cloudFoundryDeploy.yaml - rename tms.yaml to tmsUpload.yaml, since some generation policy changed meanwhile * Rename tms.yaml to tmsUpload.yaml and do go generate * Use provided proxy on communication with UAA and TMS * Set proxy even before getting OAuth token * Further implementation of tmsUpload.go * Continuation on implementing the tmsUpload.go executor * Get mtarFilePath and git commitId from commonPipelineEnvironment, if they are missing in configuration file + minor changes * Implement a happy path test for tmsUpload logic * Cover with unit tests main happy and error paths of tmsUpload.go logic * Extend set of unit tests for tmsUpload.go * Eliminate some TODOs, extend unit tests for tmsUpload.go * Delete some TODOs * Remove a couple of more TODOs from tms_test.go file * Provide additional unit test for error due unexpected positive http status code on upload * Revert back line delimiters in cmd/piper.go * Comment out file uploading calls in tmsUpload.go * Run go generate to update generated files * Convert line delimiters in tmsUpload.yaml to Unix ones, as well as provide new line character in the end of the file, plus minor fix for logging in tmsUpload.go file (pipeline complained) * Correct description of a parameter in tmsUpload.yaml, extend unit tests to check for trimming a slash in the end of TMS url for client methods that do upload * [minor] Add a comment in the test code * Add stashContent parameter to do unstashing in tmsUpload.groovy, remove some of the clarified TODOs * Uncomment uploading file calls in tmsUpload.go, declare buildResult stash in tmsUpload.yaml * Remove clarified TODOs from the tmsUpload.go file * Run go fmt for jenkins-library/pkg/tms * Do not get explicitly values from common pipeline environment - all configurations are provided in yaml file * Remove unused struct from tmsUpload_test.go * Run go fmt jenkins-library\pkg\tms * Revise descriptions of parameters provided in tmsUpload.yaml file * Specify STAGES scope for tmsUpload parameters * Provide STAGES scope for the tmsUpload parameters, provide default value for stashContent parameter * Remove trailing space from tmsUpload.yaml * Provide unit tests for proxy-related changes in http.go file * Improve proxy implementation in tmsUpload.go file * Make tmsServiceKey again a mandatory parameter * Run go generate command to make the generated files correspond the yaml state * Change line delimiters back to Unix ones (were switched while resolving the conflicts) * Remove trailing spaces from tmsUpload.yaml * Minor change in a comment to trigger pipelines with commit * Improve checks for zero-structs and for empty maps, as well as use different package to read files in the tests * Revert line endings in http.go * Revert comments formatting changes in files that do not belong to the tmsUpload step
2022-08-30 10:16:09 +02:00
t.Run("failure when calling via proxy", func(t *testing.T) {
// given
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(http.MethodGet, testURL, httpmock.NewStringResponder(200, `OK`))
client := Client{}
transportProxy, _ := url.Parse("https://proxy.dummy.sap.com")
client.SetOptions(ClientOptions{MaxRetries: -1, TransportProxy: transportProxy})
// when
response, err := client.Send(request)
// then
assert.Error(t, err)
assert.Contains(t, err.Error(), "lookup proxy.dummy.sap.com: no such host")
assert.Nil(t, response)
})
}
func TestDefaultTransport(t *testing.T) {
const testURL string = "https://localhost/api"
t.Run("with default transport", func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(http.MethodGet, testURL, httpmock.NewStringResponder(200, `OK`))
client := Client{}
client.SetOptions(ClientOptions{MaxRetries: -1, UseDefaultTransport: true})
// test
response, err := client.SendRequest("GET", testURL, nil, nil, nil)
// assert
assert.NoError(t, err)
// assert.NotEmpty(t, count)
assert.Equal(t, 1, httpmock.GetTotalCallCount(), "unexpected number of requests")
content, err := io.ReadAll(response.Body)
defer response.Body.Close()
require.NoError(t, err, "unexpected error while reading response body")
assert.Equal(t, "OK", string(content), "unexpected response content")
})
t.Run("with custom transport", func(t *testing.T) {
httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder(http.MethodGet, testURL, httpmock.NewStringResponder(200, `OK`))
client := Client{}
// test
_, err := client.SendRequest("GET", testURL, nil, nil, nil)
// assert
assert.Error(t, err)
assert.Contains(t, err.Error(), "connection")
assert.Contains(t, err.Error(), "refused")
assert.Equal(t, 0, httpmock.GetTotalCallCount(), "unexpected number of requests")
})
}
func TestSendRequest(t *testing.T) {
var passedHeaders = map[string][]string{}
passedCookies := []*http.Cookie{}
var passedUsername string
var passedPassword string
Added user API key authentication method (#3748) * changes to detectExec before master merge * changes for detectExecuteScan * self generated code added * fix syntax errors and update docu * added unit tests for fail and Group * fix failOn bug * add Groups as string array * add Groups as string array * tests and validation for groups, failOn * Updated docs and added more tests * documentation md files should not be changed * Handle merge conflicts from PR 1845 * fix merge errors * remove duplicate groups, merge error * adding buildCode and buildTool as params * switching build options * building maven modules * parameter correction * parameter correction * gnerate with new build parameter * adding comments * removing piper lib master and modifying goUtils to download 1.5.7 release * first cleaning then installing * multi module maven built * multi module maven built removing unwanted code * multi module maven built moving inside switch * testing * modifying the default use case to also call maven build * modifying the default use case to also call maven build wih -- * corrected maven build command * corrected maven build command with %v * skipping test runs * testing for MTA project with single pom * adding absolute path to m2 path * clean up * adding switch for mta and maven and removing env from containers * commiting changes for new detect step * correting log message * code clean up * unit tests changes to detectExecute * basic tests for new change * restoring piperGoUtils to download correct piper binary * code clean up * code clean up * protecodeExecuteScan -> Added authentication with user API key * protecodeExecuteScan -> updating .yml file * protecodeExecuteScan -> go generate fixed * protecodeExecuteScan -> naming convention applied for UserAPIKey parameter * protecodeExecuteScan -> extending groovy code for mapping jenkins credentials Co-authored-by: D072410 <giridhar.shenoy@sap.com> Co-authored-by: Keshav <anil.keshav@sap.com> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
2022-10-10 10:55:21 +02:00
// Start a local HTTP server
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
passedHeaders = map[string][]string{}
if req.Header != nil {
for name, headers := range req.Header {
passedHeaders[name] = headers
}
}
passedCookies = req.Cookies()
passedUsername, passedPassword, _ = req.BasicAuth()
rw.Write([]byte("OK"))
}))
// Close the server when test finishes
defer server.Close()
oldLogLevel := logrus.GetLevel()
defer logrus.SetLevel(oldLogLevel)
logrus.SetLevel(logrus.DebugLevel)
tt := []struct {
client Client
method string
body io.Reader
header http.Header
cookies []*http.Cookie
expected string
}{
2020-01-14 11:29:50 +02:00
{client: Client{logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")}, method: "GET", expected: "OK"},
{client: Client{logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")}, method: "GET", header: map[string][]string{"Testheader": {"Test1", "Test2"}}, expected: "OK"},
2020-01-14 11:29:50 +02:00
{client: Client{logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")}, cookies: []*http.Cookie{{Name: "TestCookie1", Value: "TestValue1"}, {Name: "TestCookie2", Value: "TestValue2"}}, method: "GET", expected: "OK"},
{client: Client{logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http"), username: "TestUser", password: "TestPwd"}, method: "GET", expected: "OK"},
Added user API key authentication method (#3748) * changes to detectExec before master merge * changes for detectExecuteScan * self generated code added * fix syntax errors and update docu * added unit tests for fail and Group * fix failOn bug * add Groups as string array * add Groups as string array * tests and validation for groups, failOn * Updated docs and added more tests * documentation md files should not be changed * Handle merge conflicts from PR 1845 * fix merge errors * remove duplicate groups, merge error * adding buildCode and buildTool as params * switching build options * building maven modules * parameter correction * parameter correction * gnerate with new build parameter * adding comments * removing piper lib master and modifying goUtils to download 1.5.7 release * first cleaning then installing * multi module maven built * multi module maven built removing unwanted code * multi module maven built moving inside switch * testing * modifying the default use case to also call maven build * modifying the default use case to also call maven build wih -- * corrected maven build command * corrected maven build command with %v * skipping test runs * testing for MTA project with single pom * adding absolute path to m2 path * clean up * adding switch for mta and maven and removing env from containers * commiting changes for new detect step * correting log message * code clean up * unit tests changes to detectExecute * basic tests for new change * restoring piperGoUtils to download correct piper binary * code clean up * code clean up * protecodeExecuteScan -> Added authentication with user API key * protecodeExecuteScan -> updating .yml file * protecodeExecuteScan -> go generate fixed * protecodeExecuteScan -> naming convention applied for UserAPIKey parameter * protecodeExecuteScan -> extending groovy code for mapping jenkins credentials Co-authored-by: D072410 <giridhar.shenoy@sap.com> Co-authored-by: Keshav <anil.keshav@sap.com> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
2022-10-10 10:55:21 +02:00
{client: Client{logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http"), token: "api-token-string"}, method: "GET", expected: "OK"},
}
for key, test := range tt {
t.Run(fmt.Sprintf("Row %v", key+1), func(t *testing.T) {
oldLogOutput := test.client.logger.Logger.Out
defer func() { test.client.logger.Logger.Out = oldLogOutput }()
logBuffer := new(bytes.Buffer)
test.client.logger.Logger.Out = logBuffer
response, err := test.client.SendRequest("GET", server.URL, test.body, test.header, test.cookies)
assert.NoError(t, err, "Error occurred but none expected")
content, err := io.ReadAll(response.Body)
assert.Equal(t, test.expected, string(content), "Returned content incorrect")
response.Body.Close()
for k, h := range test.header {
assert.Containsf(t, passedHeaders, k, "Header %v not contained", k)
assert.Equalf(t, h, passedHeaders[k], "Header %v contains different value")
}
if len(test.cookies) > 0 {
assert.Equal(t, test.cookies, passedCookies, "Passed cookies not correct")
}
if len(test.client.username) > 0 || len(test.client.password) > 0 {
if len(test.client.username) == 0 || len(test.client.password) == 0 {
//"User and password must both be provided"
t.Fail()
}
assert.Equal(t, test.client.username, passedUsername)
assert.Equal(t, test.client.password, passedPassword)
log := fmt.Sprintf("%s", logBuffer)
credentialsEncoded := base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", test.client.username, test.client.password)))
assert.NotContains(t, log, fmt.Sprintf("Authorization:[Basic %s]", credentialsEncoded))
assert.Contains(t, log, "Authorization:[<set>]")
}
Added user API key authentication method (#3748) * changes to detectExec before master merge * changes for detectExecuteScan * self generated code added * fix syntax errors and update docu * added unit tests for fail and Group * fix failOn bug * add Groups as string array * add Groups as string array * tests and validation for groups, failOn * Updated docs and added more tests * documentation md files should not be changed * Handle merge conflicts from PR 1845 * fix merge errors * remove duplicate groups, merge error * adding buildCode and buildTool as params * switching build options * building maven modules * parameter correction * parameter correction * gnerate with new build parameter * adding comments * removing piper lib master and modifying goUtils to download 1.5.7 release * first cleaning then installing * multi module maven built * multi module maven built removing unwanted code * multi module maven built moving inside switch * testing * modifying the default use case to also call maven build * modifying the default use case to also call maven build wih -- * corrected maven build command * corrected maven build command with %v * skipping test runs * testing for MTA project with single pom * adding absolute path to m2 path * clean up * adding switch for mta and maven and removing env from containers * commiting changes for new detect step * correting log message * code clean up * unit tests changes to detectExecute * basic tests for new change * restoring piperGoUtils to download correct piper binary * code clean up * code clean up * protecodeExecuteScan -> Added authentication with user API key * protecodeExecuteScan -> updating .yml file * protecodeExecuteScan -> go generate fixed * protecodeExecuteScan -> naming convention applied for UserAPIKey parameter * protecodeExecuteScan -> extending groovy code for mapping jenkins credentials Co-authored-by: D072410 <giridhar.shenoy@sap.com> Co-authored-by: Keshav <anil.keshav@sap.com> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com>
2022-10-10 10:55:21 +02:00
// Token authentication
if len(test.client.token) > 0 {
assert.Equal(t, test.client.token, "api-token-string")
log := fmt.Sprintf("%s", logBuffer)
assert.Contains(t, log, fmt.Sprintf("Using Token Authentication ****"))
assert.Contains(t, log, "Authorization:[<set>]")
}
})
}
}
func TestSetOptions(t *testing.T) {
c := Client{}
[TMS] Reimplement tmsUpload step in Go (#3399) * Initially generated tmsUpload<...> files * First provisioning of parameters supported by tmsUpload step * Refer to Go step from tmsUpload.groovy * Initial client implementation * Reverting line delimiters in tmsUpoad.groovy back to Unix ones * Temporarily remove when-condition for Release stage * Define useGoStep parameter in tmsUpload.groovy * Unstash buildResult if useGoStep is true * No unstashing and empty credentials, when using go step * Register TmsUploadCommand in piper.go * Cleanup groovy-related changes - they will be temporarily implemented in a different repo * Make getting OAuth token success * Look through the code and cleanup it a bit * Read service key from Jenkins credentials store * Provide initial set of unit tests for methods in /pkg/tms/tms.go file * Minor improvements on logging response on http call error * Check, if positive HTTP status code is as expected * Cleanup tms.yaml file, provide additional unit test for tms.go * Provide unit test for the case, when request body contains spaces * Specify nodeExtDescriptorMapping parameter as of type map in tms.yaml * Implement client method for getting nodes * Write tests for GetNodes method * Add GetMtaExtDescriptor client method and cover it with unit tests * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide UploadFile and UploadFileToNode client methods * Provide tests for Update- and UploadMtaExtDescriptor client methods * Write tests for FileUpload and FileUploadToNode client methods * Minor corrections * Remove some TODO comments * Rename some of response structures * Revert change for line delimiters in cmd/piper.go * Add uploadType string parameter to UploadFile and UploadRequest methods of uploader mock to reflect the changed Uploader implementation * Start to implement execution logic in tmsUpload.go * Changes in tms.yaml file - remove resources from inputs in tms.yaml and implement mtaPath parameter settings in the yaml file the same way, as it is done in cloudFoundryDeploy.yaml - rename tms.yaml to tmsUpload.yaml, since some generation policy changed meanwhile * Rename tms.yaml to tmsUpload.yaml and do go generate * Use provided proxy on communication with UAA and TMS * Set proxy even before getting OAuth token * Further implementation of tmsUpload.go * Continuation on implementing the tmsUpload.go executor * Get mtarFilePath and git commitId from commonPipelineEnvironment, if they are missing in configuration file + minor changes * Implement a happy path test for tmsUpload logic * Cover with unit tests main happy and error paths of tmsUpload.go logic * Extend set of unit tests for tmsUpload.go * Eliminate some TODOs, extend unit tests for tmsUpload.go * Delete some TODOs * Remove a couple of more TODOs from tms_test.go file * Provide additional unit test for error due unexpected positive http status code on upload * Revert back line delimiters in cmd/piper.go * Comment out file uploading calls in tmsUpload.go * Run go generate to update generated files * Convert line delimiters in tmsUpload.yaml to Unix ones, as well as provide new line character in the end of the file, plus minor fix for logging in tmsUpload.go file (pipeline complained) * Correct description of a parameter in tmsUpload.yaml, extend unit tests to check for trimming a slash in the end of TMS url for client methods that do upload * [minor] Add a comment in the test code * Add stashContent parameter to do unstashing in tmsUpload.groovy, remove some of the clarified TODOs * Uncomment uploading file calls in tmsUpload.go, declare buildResult stash in tmsUpload.yaml * Remove clarified TODOs from the tmsUpload.go file * Run go fmt for jenkins-library/pkg/tms * Do not get explicitly values from common pipeline environment - all configurations are provided in yaml file * Remove unused struct from tmsUpload_test.go * Run go fmt jenkins-library\pkg\tms * Revise descriptions of parameters provided in tmsUpload.yaml file * Specify STAGES scope for tmsUpload parameters * Provide STAGES scope for the tmsUpload parameters, provide default value for stashContent parameter * Remove trailing space from tmsUpload.yaml * Provide unit tests for proxy-related changes in http.go file * Improve proxy implementation in tmsUpload.go file * Make tmsServiceKey again a mandatory parameter * Run go generate command to make the generated files correspond the yaml state * Change line delimiters back to Unix ones (were switched while resolving the conflicts) * Remove trailing spaces from tmsUpload.yaml * Minor change in a comment to trigger pipelines with commit * Improve checks for zero-structs and for empty maps, as well as use different package to read files in the tests * Revert line endings in http.go * Revert comments formatting changes in files that do not belong to the tmsUpload step
2022-08-30 10:16:09 +02:00
transportProxy, _ := url.Parse("https://proxy.dummy.sap.com")
opts := ClientOptions{MaxRetries: -1, TransportTimeout: 10, TransportProxy: transportProxy, MaxRequestDuration: 5, Username: "TestUser", Password: "TestPassword", Token: "TestToken", Logger: log.Entry().WithField("package", "github.com/SAP/jenkins-library/pkg/http")}
c.SetOptions(opts)
assert.Equal(t, opts.TransportTimeout, c.transportTimeout)
[TMS] Reimplement tmsUpload step in Go (#3399) * Initially generated tmsUpload<...> files * First provisioning of parameters supported by tmsUpload step * Refer to Go step from tmsUpload.groovy * Initial client implementation * Reverting line delimiters in tmsUpoad.groovy back to Unix ones * Temporarily remove when-condition for Release stage * Define useGoStep parameter in tmsUpload.groovy * Unstash buildResult if useGoStep is true * No unstashing and empty credentials, when using go step * Register TmsUploadCommand in piper.go * Cleanup groovy-related changes - they will be temporarily implemented in a different repo * Make getting OAuth token success * Look through the code and cleanup it a bit * Read service key from Jenkins credentials store * Provide initial set of unit tests for methods in /pkg/tms/tms.go file * Minor improvements on logging response on http call error * Check, if positive HTTP status code is as expected * Cleanup tms.yaml file, provide additional unit test for tms.go * Provide unit test for the case, when request body contains spaces * Specify nodeExtDescriptorMapping parameter as of type map in tms.yaml * Implement client method for getting nodes * Write tests for GetNodes method * Add GetMtaExtDescriptor client method and cover it with unit tests * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide first implementation for Update- and UploadMtaExtDescriptor client methods * Provide UploadFile and UploadFileToNode client methods * Provide tests for Update- and UploadMtaExtDescriptor client methods * Write tests for FileUpload and FileUploadToNode client methods * Minor corrections * Remove some TODO comments * Rename some of response structures * Revert change for line delimiters in cmd/piper.go * Add uploadType string parameter to UploadFile and UploadRequest methods of uploader mock to reflect the changed Uploader implementation * Start to implement execution logic in tmsUpload.go * Changes in tms.yaml file - remove resources from inputs in tms.yaml and implement mtaPath parameter settings in the yaml file the same way, as it is done in cloudFoundryDeploy.yaml - rename tms.yaml to tmsUpload.yaml, since some generation policy changed meanwhile * Rename tms.yaml to tmsUpload.yaml and do go generate * Use provided proxy on communication with UAA and TMS * Set proxy even before getting OAuth token * Further implementation of tmsUpload.go * Continuation on implementing the tmsUpload.go executor * Get mtarFilePath and git commitId from commonPipelineEnvironment, if they are missing in configuration file + minor changes * Implement a happy path test for tmsUpload logic * Cover with unit tests main happy and error paths of tmsUpload.go logic * Extend set of unit tests for tmsUpload.go * Eliminate some TODOs, extend unit tests for tmsUpload.go * Delete some TODOs * Remove a couple of more TODOs from tms_test.go file * Provide additional unit test for error due unexpected positive http status code on upload * Revert back line delimiters in cmd/piper.go * Comment out file uploading calls in tmsUpload.go * Run go generate to update generated files * Convert line delimiters in tmsUpload.yaml to Unix ones, as well as provide new line character in the end of the file, plus minor fix for logging in tmsUpload.go file (pipeline complained) * Correct description of a parameter in tmsUpload.yaml, extend unit tests to check for trimming a slash in the end of TMS url for client methods that do upload * [minor] Add a comment in the test code * Add stashContent parameter to do unstashing in tmsUpload.groovy, remove some of the clarified TODOs * Uncomment uploading file calls in tmsUpload.go, declare buildResult stash in tmsUpload.yaml * Remove clarified TODOs from the tmsUpload.go file * Run go fmt for jenkins-library/pkg/tms * Do not get explicitly values from common pipeline environment - all configurations are provided in yaml file * Remove unused struct from tmsUpload_test.go * Run go fmt jenkins-library\pkg\tms * Revise descriptions of parameters provided in tmsUpload.yaml file * Specify STAGES scope for tmsUpload parameters * Provide STAGES scope for the tmsUpload parameters, provide default value for stashContent parameter * Remove trailing space from tmsUpload.yaml * Provide unit tests for proxy-related changes in http.go file * Improve proxy implementation in tmsUpload.go file * Make tmsServiceKey again a mandatory parameter * Run go generate command to make the generated files correspond the yaml state * Change line delimiters back to Unix ones (were switched while resolving the conflicts) * Remove trailing spaces from tmsUpload.yaml * Minor change in a comment to trigger pipelines with commit * Improve checks for zero-structs and for empty maps, as well as use different package to read files in the tests * Revert line endings in http.go * Revert comments formatting changes in files that do not belong to the tmsUpload step
2022-08-30 10:16:09 +02:00
assert.Equal(t, opts.TransportProxy, c.transportProxy)
assert.Equal(t, opts.TransportSkipVerification, c.transportSkipVerification)
assert.Equal(t, opts.MaxRequestDuration, c.maxRequestDuration)
assert.Equal(t, opts.Username, c.username)
assert.Equal(t, opts.Password, c.password)
assert.Equal(t, opts.Token, c.token)
}
func TestApplyDefaults(t *testing.T) {
tt := []struct {
client Client
expected Client
}{
{client: Client{}, expected: Client{transportTimeout: 3 * time.Minute, maxRequestDuration: 0, logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")}},
{client: Client{transportTimeout: 10, maxRequestDuration: 5}, expected: Client{transportTimeout: 10, maxRequestDuration: 5, logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")}},
}
for k, v := range tt {
v.client.applyDefaults()
assert.Equal(t, v.expected, v.client, fmt.Sprintf("Run %v failed", k))
}
}
2020-01-14 11:29:50 +02:00
func TestUploadRequest(t *testing.T) {
2020-01-14 11:29:50 +02:00
var passedHeaders = map[string][]string{}
passedCookies := []*http.Cookie{}
var passedUsername string
var passedPassword string
var multipartFile multipart.File
var multipartHeader *multipart.FileHeader
var passedFileContents []byte
// Start a local HTTP server
server := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) {
passedHeaders = map[string][]string{}
if req.Header != nil {
for name, headers := range req.Header {
passedHeaders[name] = headers
}
}
passedCookies = req.Cookies()
passedUsername, passedPassword, _ = req.BasicAuth()
err := req.ParseMultipartForm(4096)
if err != nil {
t.FailNow()
}
multipartFile, multipartHeader, err = req.FormFile("Field1")
if err != nil {
t.FailNow()
}
defer req.Body.Close()
passedFileContents, err = io.ReadAll(multipartFile)
2020-01-14 11:29:50 +02:00
if err != nil {
t.FailNow()
}
rw.Write([]byte("OK"))
}))
// Close the server when test finishes
defer server.Close()
testFile, err := os.CreateTemp("", "testFileUpload")
2020-01-14 11:29:50 +02:00
if err != nil {
t.FailNow()
}
defer os.RemoveAll(testFile.Name()) // clean up
fileContents, err := os.ReadFile(testFile.Name())
2020-01-14 11:29:50 +02:00
if err != nil {
t.FailNow()
}
tt := []struct {
clientOptions ClientOptions
method string
body io.Reader
header http.Header
cookies []*http.Cookie
expected string
}{
{clientOptions: ClientOptions{MaxRetries: -1}, method: "PUT", expected: "OK"},
{clientOptions: ClientOptions{MaxRetries: -1}, method: "POST", expected: "OK"},
{clientOptions: ClientOptions{MaxRetries: -1}, method: "POST", header: map[string][]string{"Testheader": {"Test1", "Test2"}}, expected: "OK"},
{clientOptions: ClientOptions{MaxRetries: -1}, cookies: []*http.Cookie{{Name: "TestCookie1", Value: "TestValue1"}, {Name: "TestCookie2", Value: "TestValue2"}}, method: "POST", expected: "OK"},
{clientOptions: ClientOptions{MaxRetries: -1, Username: "TestUser", Password: "TestPwd"}, method: "POST", expected: "OK"},
{clientOptions: ClientOptions{MaxRetries: -1, Username: "UserOnly", Password: ""}, method: "POST", expected: "OK"},
2020-01-14 11:29:50 +02:00
}
client := Client{logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")}
for key, test := range tt {
2020-01-22 15:22:04 +02:00
t.Run(fmt.Sprintf("UploadFile Row %v", key+1), func(t *testing.T) {
2020-01-14 11:29:50 +02:00
client.SetOptions(test.clientOptions)
protecodeExecuteScan -> file upload has been extended for "binary" uploads (#3156) * changes to detectExec before master merge * changes for detectExecuteScan * self generated code added * fix syntax errors and update docu * added unit tests for fail and Group * fix failOn bug * add Groups as string array * add Groups as string array * tests and validation for groups, failOn * Updated docs and added more tests * documentation md files should not be changed * Handle merge conflicts from PR 1845 * fix merge errors * remove duplicate groups, merge error * adding buildCode and buildTool as params * switching build options * building maven modules * parameter correction * parameter correction * gnerate with new build parameter * adding comments * removing piper lib master and modifying goUtils to download 1.5.7 release * first cleaning then installing * multi module maven built * multi module maven built removing unwanted code * multi module maven built moving inside switch * testing * modifying the default use case to also call maven build * modifying the default use case to also call maven build wih -- * corrected maven build command * corrected maven build command with %v * skipping test runs * testing for MTA project with single pom * adding absolute path to m2 path * clean up * adding switch for mta and maven and removing env from containers * commiting changes for new detect step * correting log message * code clean up * unit tests changes to detectExecute * basic tests for new change * restoring piperGoUtils to download correct piper binary * code clean up * code clean up * protecodeExecuteScan :: fixing file upload for binaries * protecodeExecuteScan :: fixing protecode generate file * Fix upload test * protecodeExecuteScan -> fixing tests Co-authored-by: D072410 <giridhar.shenoy@sap.com> Co-authored-by: Keshav <anil.keshav@sap.com> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>
2021-10-21 10:03:42 +02:00
response, err := client.UploadFile(server.URL, testFile.Name(), "Field1", test.header, test.cookies, "form")
2020-01-14 11:29:50 +02:00
assert.NoError(t, err, "Error occurred but none expected")
content, err := io.ReadAll(response.Body)
2020-01-14 11:29:50 +02:00
assert.NoError(t, err, "Error occurred but none expected")
assert.Equal(t, test.expected, string(content), "Returned content incorrect")
response.Body.Close()
assert.Equal(t, filepath.Base(testFile.Name()), multipartHeader.Filename, "Uploaded file incorrect")
2020-01-14 11:29:50 +02:00
assert.Equal(t, fileContents, passedFileContents, "Uploaded file incorrect")
for k, h := range test.header {
assert.Containsf(t, passedHeaders, k, "Header %v not contained", k)
assert.Equalf(t, h, passedHeaders[k], "Header %v contains different value")
}
if len(test.cookies) > 0 {
assert.Equal(t, test.cookies, passedCookies, "Passed cookies not correct")
}
if len(client.username) > 0 {
assert.Equal(t, client.username, passedUsername)
}
2020-01-22 15:22:04 +02:00
if len(client.password) > 0 {
assert.Equal(t, client.password, passedPassword)
}
})
t.Run(fmt.Sprintf("UploadRequest Row %v", key+1), func(t *testing.T) {
client.SetOptions(test.clientOptions)
protecodeExecuteScan -> file upload has been extended for "binary" uploads (#3156) * changes to detectExec before master merge * changes for detectExecuteScan * self generated code added * fix syntax errors and update docu * added unit tests for fail and Group * fix failOn bug * add Groups as string array * add Groups as string array * tests and validation for groups, failOn * Updated docs and added more tests * documentation md files should not be changed * Handle merge conflicts from PR 1845 * fix merge errors * remove duplicate groups, merge error * adding buildCode and buildTool as params * switching build options * building maven modules * parameter correction * parameter correction * gnerate with new build parameter * adding comments * removing piper lib master and modifying goUtils to download 1.5.7 release * first cleaning then installing * multi module maven built * multi module maven built removing unwanted code * multi module maven built moving inside switch * testing * modifying the default use case to also call maven build * modifying the default use case to also call maven build wih -- * corrected maven build command * corrected maven build command with %v * skipping test runs * testing for MTA project with single pom * adding absolute path to m2 path * clean up * adding switch for mta and maven and removing env from containers * commiting changes for new detect step * correting log message * code clean up * unit tests changes to detectExecute * basic tests for new change * restoring piperGoUtils to download correct piper binary * code clean up * code clean up * protecodeExecuteScan :: fixing file upload for binaries * protecodeExecuteScan :: fixing protecode generate file * Fix upload test * protecodeExecuteScan -> fixing tests Co-authored-by: D072410 <giridhar.shenoy@sap.com> Co-authored-by: Keshav <anil.keshav@sap.com> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>
2021-10-21 10:03:42 +02:00
response, err := client.UploadRequest(test.method, server.URL, testFile.Name(), "Field1", test.header, test.cookies, "form")
2020-01-22 15:22:04 +02:00
assert.NoError(t, err, "Error occurred but none expected")
content, err := io.ReadAll(response.Body)
2020-01-22 15:22:04 +02:00
assert.NoError(t, err, "Error occurred but none expected")
assert.Equal(t, test.expected, string(content), "Returned content incorrect")
response.Body.Close()
assert.Equal(t, filepath.Base(testFile.Name()), multipartHeader.Filename, "Uploaded file incorrect")
2020-01-22 15:22:04 +02:00
assert.Equal(t, fileContents, passedFileContents, "Uploaded file incorrect")
for k, h := range test.header {
assert.Containsf(t, passedHeaders, k, "Header %v not contained", k)
assert.Equalf(t, h, passedHeaders[k], "Header %v contains different value")
}
if len(test.cookies) > 0 {
assert.Equal(t, test.cookies, passedCookies, "Passed cookies not correct")
}
if len(client.username) > 0 {
assert.Equal(t, client.username, passedUsername)
}
2020-01-14 11:29:50 +02:00
if len(client.password) > 0 {
assert.Equal(t, client.password, passedPassword)
}
})
}
}
func TestUploadRequestWrongMethod(t *testing.T) {
client := Client{logger: log.Entry().WithField("package", "SAP/jenkins-library/pkg/http")}
protecodeExecuteScan -> file upload has been extended for "binary" uploads (#3156) * changes to detectExec before master merge * changes for detectExecuteScan * self generated code added * fix syntax errors and update docu * added unit tests for fail and Group * fix failOn bug * add Groups as string array * add Groups as string array * tests and validation for groups, failOn * Updated docs and added more tests * documentation md files should not be changed * Handle merge conflicts from PR 1845 * fix merge errors * remove duplicate groups, merge error * adding buildCode and buildTool as params * switching build options * building maven modules * parameter correction * parameter correction * gnerate with new build parameter * adding comments * removing piper lib master and modifying goUtils to download 1.5.7 release * first cleaning then installing * multi module maven built * multi module maven built removing unwanted code * multi module maven built moving inside switch * testing * modifying the default use case to also call maven build * modifying the default use case to also call maven build wih -- * corrected maven build command * corrected maven build command with %v * skipping test runs * testing for MTA project with single pom * adding absolute path to m2 path * clean up * adding switch for mta and maven and removing env from containers * commiting changes for new detect step * correting log message * code clean up * unit tests changes to detectExecute * basic tests for new change * restoring piperGoUtils to download correct piper binary * code clean up * code clean up * protecodeExecuteScan :: fixing file upload for binaries * protecodeExecuteScan :: fixing protecode generate file * Fix upload test * protecodeExecuteScan -> fixing tests Co-authored-by: D072410 <giridhar.shenoy@sap.com> Co-authored-by: Keshav <anil.keshav@sap.com> Co-authored-by: Oliver Nocon <33484802+OliverNocon@users.noreply.github.com> Co-authored-by: Sven Merk <33895725+nevskrem@users.noreply.github.com>
2021-10-21 10:03:42 +02:00
_, err := client.UploadRequest("GET", "dummy", "testFile", "Field1", nil, nil, "form")
assert.Error(t, err, "No error occurred but was expected")
}
func TestTransportTimout(t *testing.T) {
t.Run("timeout works on transport level", func(t *testing.T) {
// init
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Sleep for longer than the configured timeout
time.Sleep(2 * time.Second)
}))
defer svr.Close()
client := Client{transportTimeout: 1 * time.Second}
buffer := bytes.Buffer{}
// test
_, err := client.SendRequest(http.MethodGet, svr.URL, &buffer, nil, nil)
// assert
if assert.Error(t, err, "expected request to fail") {
assert.Contains(t, err.Error(), "timeout awaiting response headers")
}
})
t.Run("timeout is not hit on transport level", func(t *testing.T) {
// init
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Sleep for less than the configured timeout
time.Sleep(1 * time.Second)
}))
defer svr.Close()
client := Client{transportTimeout: 2 * time.Second}
buffer := bytes.Buffer{}
// test
_, err := client.SendRequest(http.MethodGet, svr.URL, &buffer, nil, nil)
// assert
assert.NoError(t, err)
})
}
func TestTransportSkipVerification(t *testing.T) {
testCases := []struct {
client Client
expectedError string
}{
{client: Client{}, expectedError: "certificate signed by unknown authority"},
{client: Client{transportSkipVerification: false}, expectedError: "certificate signed by unknown authority"},
{client: Client{transportSkipVerification: true}},
}
for _, testCase := range testCases {
// init
svr := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
defer svr.Close()
// test
_, err := testCase.client.SendRequest(http.MethodGet, svr.URL, &bytes.Buffer{}, nil, nil)
// assert
if len(testCase.expectedError) > 0 {
assert.Error(t, err, "certificate signed by unknown authority")
} else {
assert.NoError(t, err)
}
}
}
func TestTransportWithCertifacteAdded(t *testing.T) {
server := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.WriteString(w, "Hello")
}))
defer server.Close()
certs := x509.NewCertPool()
for _, c := range server.TLS.Certificates {
roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1])
if err != nil {
println("error parsing server's root cert: %v", err)
}
for _, root := range roots {
certs.AddCert(root)
}
}
client := http.Client{Transport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: certs, InsecureSkipVerify: false}}}
_, err := client.Get(server.URL)
// assert
assert.NoError(t, err)
}
func TestMaxRetries(t *testing.T) {
testCases := []struct {
client Client
countedCalls int
method string
responseCode int
errorText string
timeout bool
}{
{client: Client{maxRetries: 1, useDefaultTransport: true, transportSkipVerification: true, transportTimeout: 1 * time.Microsecond}, responseCode: 666, timeout: true, countedCalls: 2, method: http.MethodPost, errorText: "timeout awaiting response headers"},
{client: Client{maxRetries: 0}, countedCalls: 1, method: http.MethodGet, responseCode: 500, errorText: "Internal Server Error"},
{client: Client{maxRetries: 2}, countedCalls: 3, method: http.MethodGet, responseCode: 500, errorText: "Internal Server Error"},
{client: Client{maxRetries: 3}, countedCalls: 4, method: http.MethodPost, responseCode: 503, errorText: "Service Unavailable"},
{client: Client{maxRetries: 1}, countedCalls: 2, method: http.MethodPut, responseCode: 506, errorText: "Variant Also Negotiates"},
{client: Client{maxRetries: 1}, countedCalls: 2, method: http.MethodHead, responseCode: 502, errorText: "Bad Gateway"},
{client: Client{maxRetries: 3}, countedCalls: 1, method: http.MethodHead, responseCode: 404, errorText: "Not Found"},
{client: Client{maxRetries: 3}, countedCalls: 1, method: http.MethodHead, responseCode: 401, errorText: "Authentication Error"},
{client: Client{maxRetries: 3}, countedCalls: 1, method: http.MethodHead, responseCode: 403, errorText: "Authorization Error"},
}
for _, testCase := range testCases {
// init
count := 0
svr := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
count++
if testCase.timeout && count == 0 {
time.Sleep(3 * time.Microsecond)
}
w.WriteHeader(testCase.responseCode)
}))
defer svr.Close()
// test
_, err := testCase.client.SendRequest(testCase.method, svr.URL, &bytes.Buffer{}, nil, nil)
// assert
assert.Error(t, err, fmt.Sprintf("%v: %v", testCase.errorText, "Expected error but did not detect one"))
assert.Equal(t, testCase.countedCalls, count, fmt.Sprintf("%v: %v", testCase.errorText, "Number of invocations mismatch"))
}
}
func TestParseHTTPResponseBodyJSON(t *testing.T) {
type myJSONStruct struct {
FullName string `json:"full_name"`
Name string `json:"name"`
Owner struct {
Login string `json:"login"`
} `json:"owner"`
}
t.Run("parse JSON successful", func(t *testing.T) {
json := `{"name":"Test Name","full_name":"test full name","owner":{"login": "octocat"}}`
// create a new reader with that JSON
r := io.NopCloser(bytes.NewReader([]byte(json)))
httpResponse := http.Response{
StatusCode: 200,
Body: r,
}
var response myJSONStruct
err := ParseHTTPResponseBodyJSON(&httpResponse, &response)
if assert.NoError(t, err) {
t.Run("check correct parsing", func(t *testing.T) {
assert.Equal(t, myJSONStruct(myJSONStruct{FullName: "test full name", Name: "Test Name", Owner: struct {
Login string "json:\"login\""
}{Login: "octocat"}}), response)
})
}
})
t.Run("http response is nil", func(t *testing.T) {
var response myJSONStruct
err := ParseHTTPResponseBodyJSON(nil, &response)
t.Run("check error", func(t *testing.T) {
assert.EqualError(t, err, "cannot parse HTTP response with value <nil>")
})
})
t.Run("wrong JSON formatting", func(t *testing.T) {
json := `{"name":"Test Name","full_name":"test full name";"owner":{"login": "octocat"}}`
r := io.NopCloser(bytes.NewReader([]byte(json)))
httpResponse := http.Response{
StatusCode: 200,
Body: r,
}
var response myJSONStruct
err := ParseHTTPResponseBodyJSON(&httpResponse, &response)
println(response.FullName)
t.Run("check error", func(t *testing.T) {
assert.EqualError(t, err, "HTTP response body could not be parsed as JSON: {\"name\":\"Test Name\",\"full_name\":\"test full name\";\"owner\":{\"login\": \"octocat\"}}: invalid character ';' after object key:value pair")
})
})
t.Run("IO read error", func(t *testing.T) {
mockReadCloser := mockReadCloser{}
// if Read is called, it will return error
mockReadCloser.On("Read", mock.AnythingOfType("[]uint8")).Return(0, fmt.Errorf("error reading"))
// if Close is called, it will return error
mockReadCloser.On("Close").Return(fmt.Errorf("error closing"))
httpResponse := http.Response{
StatusCode: 200,
Body: &mockReadCloser,
}
var response myJSONStruct
err := ParseHTTPResponseBodyJSON(&httpResponse, &response)
t.Run("check error", func(t *testing.T) {
assert.EqualError(t, err, "HTTP response body could not be read: error reading")
})
})
}
func TestParseHTTPResponseBodyXML(t *testing.T) {
type myXMLStruct struct {
XMLName xml.Name `xml:"service"`
Text string `xml:",chardata"`
App string `xml:"app,attr"`
Atom string `xml:"atom,attr"`
}
t.Run("parse XML successful", func(t *testing.T) {
myXML := `
<?xml version="1.0" encoding="utf-8"?>
<app:service xmlns:app="http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom"/>
`
// create a new reader with that xml
r := io.NopCloser(bytes.NewReader([]byte(myXML)))
httpResponse := http.Response{
StatusCode: 200,
Body: r,
}
var response myXMLStruct
err := ParseHTTPResponseBodyXML(&httpResponse, &response)
if assert.NoError(t, err) {
t.Run("check correct parsing", func(t *testing.T) {
// assert.Equal(t, "<?xml version=\"1.0\" encoding=\"utf-8\"?><app:service xmlns:app=\"http://www.w3.org/2007/app\" xmlns:atom=\"http://www.w3.org/2005/Atom\"/>", response)
assert.Equal(t, myXMLStruct(myXMLStruct{XMLName: xml.Name{Space: "http://www.w3.org/2007/app", Local: "service"}, Text: "", App: "http://www.w3.org/2007/app", Atom: "http://www.w3.org/2005/Atom"}), response)
})
}
})
t.Run("http response is nil", func(t *testing.T) {
var response myXMLStruct
err := ParseHTTPResponseBodyXML(nil, &response)
t.Run("check error", func(t *testing.T) {
assert.EqualError(t, err, "cannot parse HTTP response with value <nil>")
})
})
t.Run("wrong XML formatting", func(t *testing.T) {
myXML := `
<?xml version="1.0" encoding="utf-8"?>
<app:service xmlns:app=http://www.w3.org/2007/app" xmlns:atom="http://www.w3.org/2005/Atom"/>
`
r := io.NopCloser(bytes.NewReader([]byte(myXML)))
httpResponse := http.Response{
StatusCode: 200,
Body: r,
}
var response myXMLStruct
err := ParseHTTPResponseBodyXML(&httpResponse, &response)
t.Run("check error", func(t *testing.T) {
assert.EqualError(t, err, "HTTP response body could not be parsed as XML: \n\t\t<?xml version=\"1.0\" encoding=\"utf-8\"?>\n\t\t<app:service xmlns:app=http://www.w3.org/2007/app\" xmlns:atom=\"http://www.w3.org/2005/Atom\"/>\n\t\t: XML syntax error on line 3: unquoted or missing attribute value in element")
})
})
t.Run("IO read error", func(t *testing.T) {
mockReadCloser := mockReadCloser{}
// if Read is called, it will return error
mockReadCloser.On("Read", mock.AnythingOfType("[]uint8")).Return(0, fmt.Errorf("error reading"))
// if Close is called, it will return error
mockReadCloser.On("Close").Return(fmt.Errorf("error closing"))
httpResponse := http.Response{
StatusCode: 200,
Body: &mockReadCloser,
}
var response myXMLStruct
err := ParseHTTPResponseBodyXML(&httpResponse, &response)
t.Run("check error", func(t *testing.T) {
assert.EqualError(t, err, "HTTP response body could not be read: error reading")
})
})
}
type mockReadCloser struct {
mock.Mock
}
func (m *mockReadCloser) Read(p []byte) (n int, err error) {
args := m.Called(p)
return args.Int(0), args.Error(1)
}
func (m *mockReadCloser) Close() error {
args := m.Called()
return args.Error(0)
}