Skip to content

Commit 77e197b

Browse files
zohayb23jmeridth
andauthored
test: Add comprehensive unit tests for goodLicense with dependency injection (#136)
* Add comprehensive unit tests for goodLicense with dependency injection * chore: mock http client - add interface so we can mock http client and its response or error - this allows us to still test the content of MakeApiCall and not mock out the entire function (aka valuable) Signed-off-by: jmeridth <jmeridth@gmail.com> * chore: cleanup the http mock creation into a helper function Signed-off-by: jmeridth <jmeridth@gmail.com> * fix: linting Signed-off-by: jmeridth <jmeridth@gmail.com> --------- Signed-off-by: jmeridth <jmeridth@gmail.com> Co-authored-by: jmeridth <jmeridth@gmail.com>
1 parent 2abb4b9 commit 77e197b

File tree

4 files changed

+154
-5
lines changed

4 files changed

+154
-5
lines changed

data/rest-data.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,10 @@ import (
1515
"github.com/privateerproj/privateer-sdk/config"
1616
)
1717

18+
type HttpClient interface {
19+
Do(req *http.Request) (*http.Response, error)
20+
}
21+
1822
type RestData struct {
1923
owner string
2024
repo string
@@ -26,6 +30,7 @@ type RestData struct {
2630
Rulesets []Ruleset
2731
contents RepoContent
2832
ghClient *github.Client
33+
HttpClient HttpClient
2934
}
3035

3136
type RepoContent struct {
@@ -75,16 +80,20 @@ func (r *RestData) Setup() error {
7580
}
7681

7782
func (r *RestData) MakeApiCall(endpoint string, isGithub bool) (body []byte, err error) {
78-
r.Config.Logger.Trace(fmt.Sprintf("GET %s", endpoint))
83+
if r.Config != nil && r.Config.Logger != nil {
84+
r.Config.Logger.Trace(fmt.Sprintf("GET %s", endpoint))
85+
}
7986
request, err := http.NewRequest("GET", endpoint, nil)
8087
if err != nil {
8188
return nil, err
8289
}
8390
if isGithub {
8491
request.Header.Set("Authorization", "Bearer "+r.token)
8592
}
86-
client := &http.Client{}
87-
response, err := client.Do(request)
93+
if r.HttpClient == nil {
94+
r.HttpClient = &http.Client{}
95+
}
96+
response, err := r.HttpClient.Do(request)
8897
if err != nil {
8998
err = fmt.Errorf("error making http call: %s", err.Error())
9099
return nil, err

data/rest_data_mock.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package data
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"net/http"
7+
)
8+
9+
type ClientMock struct {
10+
Response *http.Response
11+
Err error
12+
}
13+
14+
func (c *ClientMock) Do(req *http.Request) (*http.Response, error) {
15+
return c.Response, c.Err
16+
}
17+
18+
func NewPayloadWithHTTPMock(base Payload, body []byte, statusCode int, httpErr error) Payload {
19+
if statusCode == 0 {
20+
statusCode = http.StatusOK
21+
}
22+
mock := &ClientMock{
23+
Response: &http.Response{
24+
StatusCode: statusCode,
25+
Body: io.NopCloser(bytes.NewReader(body)),
26+
},
27+
Err: httpErr,
28+
}
29+
if base.RestData == nil {
30+
base.RestData = &RestData{}
31+
}
32+
base.HttpClient = mock
33+
return base
34+
}

evaluation_plans/osps/legal/steps.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func goodLicense(payloadData any, _ map[string]*layer4.Change) (result layer4.Re
8484
}
8585

8686
licenses, errString := getLicenseList(data, nil)
87+
8788
if errString != "" {
8889
return layer4.Unknown, errString
8990
}
@@ -116,8 +117,10 @@ func goodLicense(payloadData any, _ map[string]*layer4.Change) (result layer4.Re
116117
}
117118
}
118119
approvedLicenses := strings.Join(spdx_ids, ", ")
119-
data.Config.Logger.Trace(fmt.Sprintf("Requested licenses: %s", approvedLicenses))
120-
data.Config.Logger.Trace(fmt.Sprintf("Non-approved licenses: %s", badLicenses))
120+
if data.Config.Logger != nil {
121+
data.Config.Logger.Trace(fmt.Sprintf("Requested licenses: %s", approvedLicenses))
122+
data.Config.Logger.Trace(fmt.Sprintf("Non-approved licenses: %s", badLicenses))
123+
}
121124

122125
if len(badLicenses) > 0 {
123126
return layer4.Failed, fmt.Sprintf("These licenses are not OSI or FSF approved: %s", strings.Join(badLicenses, ", "))

evaluation_plans/osps/legal/steps_test.go

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"testing"
66

77
"github.com/ossf/gemara/layer4"
8+
"github.com/privateerproj/privateer-sdk/config"
89
"github.com/revanite-io/pvtr-github-repo/data"
910
"github.com/stretchr/testify/assert"
1011
)
@@ -186,3 +187,105 @@ func TestSplitSpdxExpression(t *testing.T) {
186187
})
187188
}
188189
}
190+
191+
func TestGoodLicense(t *testing.T) {
192+
tests := []struct {
193+
name string
194+
payloadData any
195+
apiResponse []byte
196+
apiError error
197+
expectedResult layer4.Result
198+
expectedMessage string
199+
}{
200+
{
201+
name: "Invalid payload",
202+
payloadData: "invalid",
203+
expectedResult: layer4.Unknown,
204+
expectedMessage: "Malformed assessment: expected payload type data.Payload, got string (invalid)",
205+
},
206+
{
207+
name: "No license identifiers found",
208+
payloadData: data.Payload{
209+
GraphqlRepoData: &data.GraphqlRepoData{},
210+
Config: &config.Config{},
211+
},
212+
apiResponse: []byte(`{"licenses":[{"licenseId":"MIT","isOsiApproved":true,"isFsfLibre":false}]}`),
213+
apiError: nil,
214+
expectedResult: layer4.Failed,
215+
expectedMessage: "License SPDX identifier was not found in Security Insights data or via GitHub API",
216+
},
217+
{
218+
name: "OSI approved license (MIT)",
219+
payloadData: data.Payload{
220+
GraphqlRepoData: func() *data.GraphqlRepoData {
221+
repo := stubGraphqlRepo("")
222+
repo.Repository.LicenseInfo.SpdxId = "MIT"
223+
return repo
224+
}(),
225+
Config: &config.Config{},
226+
},
227+
apiResponse: []byte(`{"licenses":[{"licenseId":"MIT","isOsiApproved":true,"isFsfLibre":false}]}`),
228+
apiError: nil,
229+
expectedResult: layer4.NeedsReview,
230+
expectedMessage: "All license found are OSI or FSF approved",
231+
},
232+
{
233+
name: "Non-approved license",
234+
payloadData: data.Payload{
235+
GraphqlRepoData: func() *data.GraphqlRepoData {
236+
repo := stubGraphqlRepo("")
237+
repo.Repository.LicenseInfo.SpdxId = "BadLicense"
238+
return repo
239+
}(),
240+
Config: &config.Config{},
241+
},
242+
apiResponse: []byte(`{"licenses":[{"licenseId":"BadLicense","isOsiApproved":false,"isFsfLibre":false}]}`),
243+
apiError: nil,
244+
expectedResult: layer4.Failed,
245+
expectedMessage: "These licenses are not OSI or FSF approved: BadLicense",
246+
},
247+
{
248+
name: "Multiple licenses with mixed approval",
249+
payloadData: data.Payload{
250+
GraphqlRepoData: func() *data.GraphqlRepoData {
251+
repo := stubGraphqlRepo("")
252+
repo.Repository.LicenseInfo.SpdxId = "MIT AND BadLicense"
253+
return repo
254+
}(),
255+
Config: &config.Config{},
256+
},
257+
apiResponse: []byte(`{"licenses":[{"licenseId":"MIT","isOsiApproved":true,"isFsfLibre":false},{"licenseId":"BadLicense","isOsiApproved":false,"isFsfLibre":false}]}`),
258+
apiError: nil,
259+
expectedResult: layer4.Failed,
260+
expectedMessage: "These licenses are not OSI or FSF approved: BadLicense",
261+
},
262+
{
263+
name: "Unknown license ID",
264+
payloadData: data.Payload{
265+
GraphqlRepoData: func() *data.GraphqlRepoData {
266+
repo := stubGraphqlRepo("")
267+
repo.Repository.LicenseInfo.SpdxId = "UnknownLicense"
268+
return repo
269+
}(),
270+
Config: &config.Config{},
271+
},
272+
apiResponse: []byte(`{"licenses":[{"licenseId":"MIT","isOsiApproved":true,"isFsfLibre":false}]}`),
273+
apiError: nil,
274+
expectedResult: layer4.Failed,
275+
expectedMessage: "These licenses are not OSI or FSF approved: UnknownLicense",
276+
},
277+
}
278+
279+
for _, test := range tests {
280+
t.Run(test.name, func(t *testing.T) {
281+
if payload, ok := test.payloadData.(data.Payload); ok {
282+
payload = data.NewPayloadWithHTTPMock(payload, test.apiResponse, 200, test.apiError)
283+
test.payloadData = payload
284+
}
285+
286+
result, message := goodLicense(test.payloadData, nil)
287+
assert.Equal(t, test.expectedResult, result)
288+
assert.Equal(t, test.expectedMessage, message)
289+
})
290+
}
291+
}

0 commit comments

Comments
 (0)