helpers_test.go

Copyright 2020, 2021, 2022 Red Hat, Inc

Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

package
helpers_test

Documentation in literate-programming-style is available at: https://redhatinsights.github.io/insights-operator-utils/packages/tests/helpers/helpers_test.html


import
(
"encoding/json"
"fmt"
"io"
"net/http"
"strings"
"testing"
"time"
"github.com/RedHatInsights/insights-results-aggregator-data/testdata"
types
"github.com/RedHatInsights/insights-results-types"
"github.com/golang/mock/gomock"
"github.com/mozillazg/request"
"github.com/stretchr/testify/assert"
"github.com/verdverm/frisby"
"gopkg.in/h2non/gock.v1"
httputils
"github.com/RedHatInsights/insights-operator-utils/http"
"github.com/RedHatInsights/insights-operator-utils/responses"
"github.com/RedHatInsights/insights-operator-utils/tests/helpers"
"github.com/RedHatInsights/insights-operator-utils/tests/mock_io"
)
const
(
localhostAddress
=
"http://localhost"
port
=
9999
notJSONString
=
"not-json"
okBody
=
`{"status": "ok"}`
testEndpoint
=
"test"
)
var
(
serverAddress
=
localhostAddress
+
":"
+
fmt
.
Sprint
(
port
)
testError
=
fmt
.
Errorf
(
"test error"
)
devNull
interface
{
}
)
func
TestFailOnError
(
t
*
testing
.
T
)
{
helpers
.
FailOnError
(
t
,
nil
)
}
func
TestFailOnError_Fatal
(
t
*
testing
.
T
)
{
mockT
:=
helpers
.
NewMockT
(
t
)
defer
mockT
.
Finish
(
)
mockT
.
ExpectFailOnError
(
testError
)
helpers
.
FailOnError
(
mockT
,
testError
)
}
func
TestToJSONString
(
t
*
testing
.
T
)
{
assert
.
Equal
(
t
,
`{"test":1}`
,
helpers
.
ToJSONString
(
map
[
string
]
int
{
"test"
:
1
,
}
)
)
}
func
TestToJSONString_Error
(
t
*
testing
.
T
)
{
assert
.
Panics
(
t
,
func
(
)
{
helpers
.
ToJSONString
(
make
(
chan
int
)
)
}
,
"should panic on unsupported type"
)
}
func
TestToJSONPrettyString
(
t
*
testing
.
T
)
{
helpers
.
AssertStringsAreEqualJSON
(
t
,
`{"test": 1, "k": 2}`
,
helpers
.
ToJSONPrettyString
(
map
[
string
]
int
{
"test"
:
1
,
"k"
:
2
,
}
)
)
}
func
TestNewMicroHTTPServer
(
t
*
testing
.
T
)
{
server
:=
helpers
.
NewMicroHTTPServer
(
":"
+
fmt
.
Sprint
(
port
)
,
""
)
_
=
server
.
Initialize
(
)
server
.
AddEndpoint
(
"/"
,
func
(
http
.
ResponseWriter
,
*
http
.
Request
)
{
}
)
}
func
TestMustGobSerialize
(
t
*
testing
.
T
)
{
objectToSerialize
:=
1
bytesResult
:=
helpers
.
MustGobSerialize
(
t
,
objectToSerialize
)
expectedBytes
:=
[
]
byte
{
0x3
,
0x4
,
0x0
,
0x2
}
assert
.
Equal
(
t
,
expectedBytes
,
bytesResult
)
}
func
TestAssertStringsAreEqualJSON
(
t
*
testing
.
T
)
{
helpers
.
AssertStringsAreEqualJSON
(
t
,
`{"one": 1, "two": 2}`
,
`{"two": 2, "one": 1}`
)
}
func
TestAssertStringsAreEqualJSON_Error
(
t
*
testing
.
T
)
{
t
.
Run
(
"ExpectedIsNotJSON"
,
func
(
t
*
testing
.
T
)
{
mockT
:=
helpers
.
NewMockT
(
t
)
defer
mockT
.
Finish
(
)
mockT
.
ExpectFailOnErrorAnyArgument
(
)
mockT
.
Expects
.
EXPECT
(
)
.
Errorf
(
gomock
.
Any
(
)
,
gomock
.
Any
(
)
)
helpers
.
AssertStringsAreEqualJSON
(
mockT
,
notJSONString
,
`{"two": 2, "one": 1}`
)
}
)
t
.
Run
(
"GotIsNotJSON"
,
func
(
t
*
testing
.
T
)
{
mockT
:=
helpers
.
NewMockT
(
t
)
defer
mockT
.
Finish
(
)
mockT
.
ExpectFailOnErrorAnyArgument
(
)
mockT
.
Expects
.
EXPECT
(
)
.
Errorf
(
gomock
.
Any
(
)
,
gomock
.
Any
(
)
)
helpers
.
AssertStringsAreEqualJSON
(
mockT
,
`{"one": 1, "two": 2}`
,
notJSONString
)
}
)
}
func
TestJSONUnmarshalStrict
(
t
*
testing
.
T
)
{
jsonBytes
:=
[
]
byte
(
`{"one": 1, "two": 2, "three": 3}`
)
var
resultObj
map
[
string
]
int
err
:=
helpers
.
JSONUnmarshalStrict
(
jsonBytes
,
&
resultObj
)
helpers
.
FailOnError
(
t
,
err
)
assert
.
Equal
(
t
,
map
[
string
]
int
{
"one"
:
1
,
"two"
:
2
,
"three"
:
3
}
,
resultObj
)
}
func
TestIsStringJSON
(
t
*
testing
.
T
)
{
t
.
Run
(
"true"
,
func
(
t
*
testing
.
T
)
{
assert
.
True
(
t
,
helpers
.
IsStringJSON
(
`{"one": 1, "two": 2}`
)
)
}
)
t
.
Run
(
"false"
,
func
(
t
*
testing
.
T
)
{
assert
.
False
(
t
,
helpers
.
IsStringJSON
(
`{"one": 1"two": 2}`
)
)
}
)
}
func
TestRunTestWithTimeout
(
t
*
testing
.
T
)
{
helpers
.
RunTestWithTimeout
(
t
,
func
(
t
testing
.
TB
)
{
}
,
time
.
Second
)
}
func
TestRunTestWithTimeout_Error
(
t
*
testing
.
T
)
{
mockT
:=
helpers
.
NewMockT
(
t
)
defer
mockT
.
Finish
(
)
mockT
.
Expects
.
EXPECT
(
)
.
Fatal
(
"test ran out of time"
)
helpers
.
RunTestWithTimeout
(
mockT
,
func
(
t
testing
.
TB
)
{
time
.
Sleep
(
time
.
Hour
)
}
,
time
.
Microsecond
)
}
func
TestAssertAPIRequest
(
t
*
testing
.
T
)
{
const
(
apiPrefix
=
"/api/v1/"
endpoint
=
"test/{param}"
expectedURLParam
=
uint64
(
55
)
expectedRequestBody
=
`{"test": "json"}`
)
token
:=
helpers
.
MakeXRHTokenString
(
t
,
&
types
.
Token
{
Identity
:
types
.
Identity
{
AccountNumber
:
testdata
.
UserID
,
OrgID
:
testdata
.
Org2ID
,
User
:
types
.
User
{
UserID
:
testdata
.
UserID
}
,
}
,
}
)
testServer
:=
helpers
.
NewMicroHTTPServer
(
":8080"
,
apiPrefix
)
testServer
.
AddEndpoint
(
endpoint
,
func
(
writer
http
.
ResponseWriter
,
request
*
http
.
Request
)
{
paramValue
,
err
:=
httputils
.
GetRouterPositiveIntParam
(
request
,
"param"
)
helpers
.
FailOnError
(
t
,
err
)
assert
.
Equal
(
t
,
expectedURLParam
,
paramValue
)
helpers
.
CheckResponseBodyJSON
(
t
,
expectedRequestBody
,
request
.
Body
)
err
=
responses
.
SendOK
(
writer
,
map
[
string
]
interface
{
}
{
"param"
:
paramValue
}
)
helpers
.
FailOnError
(
t
,
err
)
}
)
helpers
.
AssertAPIRequest
(
t
,
testServer
,
apiPrefix
,
&
helpers
.
APIRequest
{
Method
:
http
.
MethodGet
,
Endpoint
:
endpoint
,
EndpointArgs
:
[
]
interface
{
}
{
expectedURLParam
}
,
Body
:
expectedRequestBody
,
UserID
:
testdata
.
UserID
,
OrgID
:
testdata
.
OrgID
,
XRHIdentity
:
token
,
AuthorizationToken
:
token
,
ExtraHeaders
:
map
[
string
]
[
]
string
{
"User-Agent"
:
{
"test"
}
,
}
,
}
,
&
helpers
.
APIResponse
{
StatusCode
:
http
.
StatusOK
,
Body
:
fmt
.
Sprintf
(
`{"param": %v}`
,
expectedURLParam
)
,
Headers
:
map
[
string
]
string
{

should be empty, which means there's no such header

			
"non-existing-header"
:
""
,
}
,
BodyChecker
:
func
(
t
testing
.
TB
,
expected
,
got
[
]
byte
)
{
helpers
.
AssertStringsAreEqualJSON
(
t
,
string
(
expected
)
,
string
(
got
)
)
}
,
}
)
t
.
Run
(
"NoBodyChecker"
,
func
(
t
*
testing
.
T
)
{
helpers
.
AssertAPIRequest
(
t
,
testServer
,
apiPrefix
,
&
helpers
.
APIRequest
{
Method
:
http
.
MethodGet
,
Endpoint
:
endpoint
,
EndpointArgs
:
[
]
interface
{
}
{
expectedURLParam
}
,
Body
:
expectedRequestBody
,
}
,
&
helpers
.
APIResponse
{
StatusCode
:
http
.
StatusOK
,
Body
:
fmt
.
Sprintf
(
`{"param": %v}`
,
expectedURLParam
)
,
}
)
}
)
}
func
TestAssertReportResponsesEqual
(
t
*
testing
.
T
)
{
testAssertResponsesEqual
(
t
,
helpers
.
AssertReportResponsesEqual
,
testdata
.
Report3RulesExpectedResponse
,
5
,
4
,
)
}
func
TestAssertRuleResponsesEqual
(
t
*
testing
.
T
)
{
correctResponse
:=
struct
{
Status
string
`json:"status"`
Report
types
.
RuleOnReport
`json:"report"`
}
{
Status
:
"ok"
,
}
testAssertResponsesEqual
(
t
,
helpers
.
AssertRuleResponsesEqual
,
helpers
.
ToJSONString
(
correctResponse
)
,
2
,
1
,
)
}
func
testAssertResponsesEqual
(
t
*
testing
.
T
,
function
func
(
testing
.
TB
,
[
]
byte
,
[
]
byte
)
,
correctResponse
string
,
numberOfErrorsOnBadExpectedValue
int
,
numberOfErrorsOnBadGotValue
int
,
)
{
t
.
Run
(
"OK"
,
func
(
t
*
testing
.
T
)
{
function
(
t
,
[
]
byte
(
correctResponse
)
,
[
]
byte
(
correctResponse
)
,
)
}
)
mockT
:=
helpers
.
NewMockT
(
t
)
defer
mockT
.
Finish
(
)
var
devNull
interface
{
}
badJSONError
:=
json
.
Unmarshal
(
[
]
byte
(
notJSONString
)
,
&
devNull
)
expectAssertReportResponsesEqualWrongArg
:=
func
(
n
int
)
{
mockT
.
ExpectFailOnError
(
badJSONError
)

each AssertReportResponsesEqual raises a lot of errors

		
for
i
:=
0
;
i
<
n
;
i
++
{
mockT
.
Expects
.
EXPECT
(
)
.
Errorf
(
gomock
.
Any
(
)
,
gomock
.
Any
(
)
)
}
}
t
.
Run
(
"BadExpectedValue"
,
func
(
t
*
testing
.
T
)
{
expectAssertReportResponsesEqualWrongArg
(
numberOfErrorsOnBadExpectedValue
)
function
(
mockT
,
[
]
byte
(
notJSONString
)
,
[
]
byte
(
correctResponse
)
,
)
}
)
t
.
Run
(
"BadGotValue"
,
func
(
t
*
testing
.
T
)
{
expectAssertReportResponsesEqualWrongArg
(
numberOfErrorsOnBadGotValue
)
function
(
mockT
,
[
]
byte
(
correctResponse
)
,
[
]
byte
(
"not-json"
)
,
)
}
)
}
func
TestGockExpectAPIRequest
(
t
*
testing
.
T
)
{
defer
helpers
.
CleanAfterGock
(
t
)
helpers
.
GockExpectAPIRequest
(
t
,
serverAddress
,
&
helpers
.
APIRequest
{
Method
:
http
.
MethodPost
,
Endpoint
:
testEndpoint
,
Body
:
okBody
,
ExtraHeaders
:
map
[
string
]
[
]
string
{
"Content-Type"
:
{
"application/json"
}
,
}
,
}
,
&
helpers
.
APIResponse
{
StatusCode
:
http
.
StatusOK
,
Body
:
okBody
,
}
)
resp
,
err
:=
http
.
Post
(
serverAddress
+
"/"
+
testEndpoint
,
"application/json"
,
strings
.
NewReader
(
okBody
)
)
helpers
.
FailOnError
(
t
,
err
)
bodyBytes
,
err
:=
io
.
ReadAll
(
resp
.
Body
)
helpers
.
FailOnError
(
t
,
err
)
assert
.
Equal
(
t
,
http
.
StatusOK
,
resp
.
StatusCode
)
assert
.
Equal
(
t
,
okBody
,
string
(
bodyBytes
)
)
}
func
TestNewGockAPIEndpointMatcher
(
t
*
testing
.
T
)
{
matcher
:=
helpers
.
NewGockAPIEndpointMatcher
(
testEndpoint
)
httpRequest
,
err
:=
http
.
NewRequest
(
http
.
MethodGet
,
testEndpoint
,
http
.
NoBody
)
helpers
.
FailOnError
(
t
,
err
)
result
,
err
:=
matcher
(
httpRequest
,
nil
)
helpers
.
FailOnError
(
t
,
err
)
assert
.
True
(
t
,
result
)
}
func
TestCleanAfterGockError
(
t
*
testing
.
T
)
{
mockT
:=
helpers
.
NewMockT
(
t
)
defer
mockT
.
Finish
(
)

remove is crucial

	
gock
.
Remove
(
gock
.
New
(
serverAddress
)
.
Mock
)
defer
helpers
.
CleanAfterGock
(
mockT
)
_
,
err
:=
http
.
Post
(
serverAddress
,
"application/json"
,
strings
.
NewReader
(
"{}"
)
)
assert
.
Error
(
t
,
err
)
assert
.
Contains
(
t
,
err
.
Error
(
)
,
"gock: cannot match any request"
)
mockT
.
Expects
.
EXPECT
(
)
.
Error
(
gomock
.
Any
(
)
)
for
i
:=
0
;
i
<
4
;
i
++
{
mockT
.
Expects
.
EXPECT
(
)
.
Errorf
(
gomock
.
Any
(
)
,
gomock
.
Any
(
)
)
}
mockT
.
Expects
.
EXPECT
(
)
.
Fatalf
(
gomock
.
Any
(
)
,
gomock
.
Any
(
)
)
}
func
TestToBytes
(
t
*
testing
.
T
)
{
t
.
Run
(
"OK"
,
func
(
t
*
testing
.
T
)
{
assert
.
Equal
(
t
,
[
]
byte
(
nil
)
,
helpers
.
ToBytes
(
t
,
nil
)
)
const
testStr
=
"1"
assert
.
Equal
(
t
,
[
]
byte
(
testStr
)
,
helpers
.
ToBytes
(
t
,
[
]
byte
(
testStr
)
)
)
assert
.
Equal
(
t
,
[
]
byte
(
testStr
)
,
helpers
.
ToBytes
(
t
,
testStr
)
)
assert
.
Equal
(
t
,
[
]
byte
(
testStr
)
,
helpers
.
ToBytes
(
t
,
strings
.
NewReader
(
testStr
)
)
)
}
)
t
.
Run
(
"Error"
,
func
(
t
*
testing
.
T
)
{
mockT
:=
helpers
.
NewMockT
(
t
)
defer
mockT
.
Finish
(
)
mockT
.
Expects
.
EXPECT
(
)
.
Fatalf
(
gomock
.
Any
(
)
,
gomock
.
Any
(
)
)
_
=
helpers
.
ToBytes
(
mockT
,
[
]
string
{
}
)
}
)
}
func
TestUnmarshalResponseBodyToJSON
(
t
*
testing
.
T
)
{
var
result
map
[
string
]
int
err
:=
helpers
.
UnmarshalResponseBodyToJSON
(
io
.
NopCloser
(
strings
.
NewReader
(
`{"test": 1}`
)
)
,
&
result
,
)
helpers
.
FailOnError
(
t
,
err
)
assert
.
Len
(
t
,
result
,
1
)
assert
.
Equal
(
t
,
1
,
result
[
"test"
]
)
}
func
TestUnmarshalResponseBodyToJSON_UnmarshalError
(
t
*
testing
.
T
)
{
err
:=
helpers
.
UnmarshalResponseBodyToJSON
(
io
.
NopCloser
(
strings
.
NewReader
(
notJSONString
)
)
,
&
devNull
,
)
assert
.
EqualError
(
t
,
err
,
"invalid character 'o' in literal null (expecting 'u')"
)
}
func
TestUnmarshalResponseBodyToJSON_ReaderError
(
t
*
testing
.
T
)
{
mockController
:=
gomock
.
NewController
(
t
)
defer
mockController
.
Finish
(
)
mockReadCloser
:=
mock_io
.
NewMockReadCloser
(
mockController
)
t
.
Run
(
"ReadError"
,
func
(
t
*
testing
.
T
)
{
mockReadCloser
.
EXPECT
(
)
.
Read
(
gomock
.
Any
(
)
)
.
Return
(
0
,
testError
)
err
:=
helpers
.
UnmarshalResponseBodyToJSON
(
mockReadCloser
,
&
devNull
,
)
assert
.
EqualError
(
t
,
err
,
testError
.
Error
(
)
)
}
)
t
.
Run
(
"CloseError"
,
func
(
t
*
testing
.
T
)
{
mockReadCloser
.
EXPECT
(
)
.
Read
(
gomock
.
Any
(
)
)
.
Return
(
0
,
io
.
EOF
)
mockReadCloser
.
EXPECT
(
)
.
Close
(
)
.
Return
(
testError
)
err
:=
helpers
.
UnmarshalResponseBodyToJSON
(
mockReadCloser
,
&
devNull
,
)
assert
.
EqualError
(
t
,
err
,
testError
.
Error
(
)
)
}
)
}
func
TestFrisbyExpectItemInArray
(
t
*
testing
.
T
)
{
testFrisbyExpectItemInArray
(
t
,
`{"organizations": [1, 2, 3, 55], "status": "ok"}`
,
true
,
""
,
)
testFrisbyExpectItemInArray
(
t
,
notJSONString
,
false
,
"invalid character 'o' in literal null (expecting 'u')"
,
)
testFrisbyExpectItemInArray
(
t
,
`{"orgs": [1, 2, 3, 55], "status": "ok"}`
,
false
,
`field organizations does not exist in response {"orgs":[1,2,3,55],"status":"ok"}`
,
)
testFrisbyExpectItemInArray
(
t
,
`{"organizations": 1, "status": "ok"}`
,
false
,
`field organizations is not an array in response {"organizations":1,"status":"ok"}`
,
)
testFrisbyExpectItemInArray
(
t
,
`{"organizations": [1, 2, 3], "status": "ok"}`
,
false
,
`Item 55 was not found in array [1 2 3] in response {"organizations":[1,2,3],"status":"ok"}`
,
)
}
func
testFrisbyExpectItemInArray
(
t
*
testing
.
T
,
responseBody
string
,
expectedFound
bool
,
expectedErrStr
string
)
{
checker
:=
helpers
.
FrisbyExpectItemInArray
(
"organizations"
,
55
)
f
:=
frisby
.
Create
(
""
)
f
.
Resp
=
&
request
.
Response
{
Response
:
&
http
.
Response
{
Status
:
"ok"
,
StatusCode
:
http
.
StatusOK
,
Body
:
io
.
NopCloser
(
strings
.
NewReader
(
responseBody
)
)
,
ContentLength
:
int64
(
len
(
responseBody
)
)
,
}
,
}
found
,
errStr
:=
checker
(
f
)
assert
.
Equal
(
t
,
expectedFound
,
found
)
assert
.
Equal
(
t
,
expectedErrStr
,
errStr
)
}