Skip to content

Commit

Permalink
refactor: use http.ServeMux in snyk unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
mcombuechen committed Nov 28, 2024
1 parent 3fb71c0 commit 5b23f91
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 99 deletions.
2 changes: 1 addition & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ orbs:
go_image: &go_image
resource_class: small
docker:
- image: cimg/go:1.21
- image: cimg/go:1.23

jobs:
security-scans:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- name: Set up Go
uses: actions/setup-go@v3
with:
go-version: 1.20.3
go-version: 1.23.2

- name: Lint
uses: golangci/golangci-lint-action@v3
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/snyk/parlay

go 1.20
go 1.23

require (
github.com/CycloneDX/cyclonedx-go v0.9.0
Expand Down
10 changes: 10 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHS
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M=
github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
Expand All @@ -73,6 +74,7 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
Expand Down Expand Up @@ -155,9 +157,11 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
Expand All @@ -167,6 +171,7 @@ github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27k
github.com/mattn/go-isatty v0.0.16 h1:bq3VjFmv/sOjHtdEhmkEV4x1AJtvUvOJ2PFAZ5+peKQ=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g=
github.com/maxatome/go-testdeep v1.12.0/go.mod h1:lPZc/HAcJMP92l7yI6TRz1aZN5URwUBUAfUNvrclaNM=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/package-url/packageurl-go v0.1.2 h1:0H2DQt6DHd/NeRlVwW4EZ4oEI6Bn40XlNPRqegcxuo4=
Expand All @@ -182,6 +187,7 @@ github.com/remeh/sizedwaitgroup v1.0.0 h1:VNGGFwNo/R5+MJBf6yrsr110p0m4/OX4S3DCy7
github.com/remeh/sizedwaitgroup v1.0.0/go.mod h1:3j2R4OIe/SeS6YDhICBy22RWjJC5eNCJ1V+9+NVNYlo=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rs/xid v1.4.0/go.mod h1:trrq9SKmegXys3aeAKXMUTdJsYXVwGY3RLcfgqegfbg=
github.com/rs/zerolog v1.29.1 h1:cO+d60CHkknCbvzEWxP0S9K6KqyTjrCNUy1LdQLCGPc=
github.com/rs/zerolog v1.29.1/go.mod h1:Le6ESbR7hc+DP6Lt1THiV8CQSdkkNrd3R0XbEgp3ZBU=
Expand Down Expand Up @@ -220,9 +226,13 @@ github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo=
github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
145 changes: 67 additions & 78 deletions lib/snyk/enrich_test.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,32 @@
package snyk

import (
_ "embed"
"net/http"
"net/http/httptest"
"testing"

cdx "github.com/CycloneDX/cyclonedx-go"
"github.com/jarcoal/httpmock"
"github.com/rs/zerolog"
spdx "github.com/spdx/tools-golang/spdx/v2/common"
spdx_2_3 "github.com/spdx/tools-golang/spdx/v2/v2_3"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/snyk/parlay/lib/sbom"
)

func TestEnrichSBOM_CycloneDXWithVulnerabilities(t *testing.T) {
teardown := setupTestEnv(t)
defer teardown()
var (
//go:embed testdata/numpy_issues.json
numpyIssues []byte
//go:embed testdata/pandas_issues.json
pandasIssues []byte
//go:embed testdata/no_issues.json
noIssues []byte
)

cfg := newTestConfig(t)
logger := zerolog.Nop()
svc := NewService(cfg, &logger)
func TestEnrichSBOM_CycloneDXWithVulnerabilities(t *testing.T) {
svc := setupTestEnv(t)

bom := &cdx.BOM{
Components: &[]cdx.Component{
Expand All @@ -35,20 +42,15 @@ func TestEnrichSBOM_CycloneDXWithVulnerabilities(t *testing.T) {

svc.EnrichSBOM(doc)

assert.NotNil(t, bom.Vulnerabilities)
require.NotNil(t, bom.Vulnerabilities)
assert.Len(t, *bom.Vulnerabilities, 1)
vuln := (*bom.Vulnerabilities)[0]
assert.Equal(t, "pkg:pypi/[email protected]", vuln.BOMRef)
assert.Equal(t, "SNYK-PYTHON-NUMPY-73513", vuln.ID)
}

func TestEnrichSBOM_CycloneDXExternalRefs(t *testing.T) {
teardown := setupTestEnv(t)
defer teardown()

cfg := newTestConfig(t)
logger := zerolog.Nop()
svc := NewService(cfg, &logger)
svc := setupTestEnv(t)

bom := &cdx.BOM{
Components: &[]cdx.Component{
Expand All @@ -64,7 +66,7 @@ func TestEnrichSBOM_CycloneDXExternalRefs(t *testing.T) {

svc.EnrichSBOM(doc)

assert.NotNil(t, bom.Components)
require.NotNil(t, bom.Components)
refs := (*bom.Components)[0].ExternalReferences
assert.Len(t, *refs, 2)

Expand All @@ -80,12 +82,7 @@ func TestEnrichSBOM_CycloneDXExternalRefs(t *testing.T) {
}

func TestEnrichSBOM_CycloneDXExternalRefs_WithNamespace(t *testing.T) {
teardown := setupTestEnv(t)
defer teardown()

cfg := newTestConfig(t)
logger := zerolog.Nop()
svc := NewService(cfg, &logger)
svc := setupTestEnv(t)

bom := &cdx.BOM{
Components: &[]cdx.Component{
Expand All @@ -101,7 +98,7 @@ func TestEnrichSBOM_CycloneDXExternalRefs_WithNamespace(t *testing.T) {

svc.EnrichSBOM(doc)

assert.NotNil(t, bom.Components)
require.NotNil(t, bom.Components)
refs := (*bom.Components)[0].ExternalReferences
assert.Len(t, *refs, 2)

Expand All @@ -117,12 +114,7 @@ func TestEnrichSBOM_CycloneDXExternalRefs_WithNamespace(t *testing.T) {
}

func TestEnrichSBOM_CycloneDXWithVulnerabilities_NestedComponents(t *testing.T) {
teardown := setupTestEnv(t)
defer teardown()

cfg := newTestConfig(t)
logger := zerolog.Nop()
svc := NewService(cfg, &logger)
svc := setupTestEnv(t)

bom := &cdx.BOM{
Components: &[]cdx.Component{
Expand All @@ -146,17 +138,12 @@ func TestEnrichSBOM_CycloneDXWithVulnerabilities_NestedComponents(t *testing.T)

svc.EnrichSBOM(doc)

assert.NotNil(t, bom.Vulnerabilities)
require.NotNil(t, bom.Vulnerabilities)
assert.Len(t, *bom.Vulnerabilities, 2)
}

func TestEnrichSBOM_CycloneDXWithoutVulnerabilities(t *testing.T) {
teardown := setupTestEnv(t)
defer teardown()

cfg := newTestConfig(t)
logger := zerolog.Nop()
svc := NewService(cfg, &logger)
svc := setupTestEnv(t)

bom := &cdx.BOM{
Components: &[]cdx.Component{
Expand All @@ -176,12 +163,7 @@ func TestEnrichSBOM_CycloneDXWithoutVulnerabilities(t *testing.T) {
}

func TestEnrichSBOM_SPDXWithVulnerabilities(t *testing.T) {
teardown := setupTestEnv(t)
defer teardown()

cfg := newTestConfig(t)
logger := zerolog.Nop()
svc := NewService(cfg, &logger)
svc := setupTestEnv(t)

bom := &spdx_2_3.Document{
Packages: []*spdx_2_3.Package{
Expand Down Expand Up @@ -211,12 +193,7 @@ func TestEnrichSBOM_SPDXWithVulnerabilities(t *testing.T) {
}

func TestEnrichSBOM_SPDXExternalRefs(t *testing.T) {
teardown := setupTestEnv(t)
defer teardown()

cfg := newTestConfig(t)
logger := zerolog.Nop()
svc := NewService(cfg, &logger)
svc := setupTestEnv(t)

bom := &spdx_2_3.Document{
Packages: []*spdx_2_3.Package{
Expand Down Expand Up @@ -256,39 +233,51 @@ func TestEnrichSBOM_SPDXExternalRefs(t *testing.T) {
assert.Equal(t, spdx.CategoryOther, ref2.Category)
}

func setupTestEnv(t *testing.T) func() {
func setupTestEnv(t *testing.T) Service {
t.Helper()

httpmock.Activate()
httpmock.RegisterResponder(
"GET",
`=~^https://api\.snyk\.io/rest/self`,
httpmock.NewJsonResponderOrPanic(200, httpmock.File("testdata/self.json")),
)
httpmock.RegisterResponder(
"GET",
`=~^https://api\.snyk\.io/rest/orgs/[a-z0-9-]+/packages/pkg%3Apypi%2Fnumpy%401.16.0/issues`,
httpmock.NewJsonResponderOrPanic(200, httpmock.File("testdata/numpy_issues.json")),
)
httpmock.RegisterResponder(
"GET",
`=~^https://api\.snyk\.io/rest/orgs/[a-z0-9-]+/packages/pkg%3Apypi%2Fpandas%400.15.0/issues`,
httpmock.NewJsonResponderOrPanic(200, httpmock.File("testdata/pandas_issues.json")),
)
httpmock.RegisterResponder(
"GET",
`=~^https://api\.snyk\.io/rest/orgs/[a-z0-9-]+/packages/.*/issues`,
httpmock.NewJsonResponderOrPanic(200, httpmock.File("testdata/no_issues.json")),
)

return func() {
httpmock.DeactivateAndReset()
}
mux := http.NewServeMux()

mux.HandleFunc(
"GET /rest/self",
func(w http.ResponseWriter, r *http.Request) {
respond(w, selfBody)
})

mux.HandleFunc(
"GET /rest/orgs/{org_id}/packages/{purl}/issues",
func(w http.ResponseWriter, r *http.Request) {
respond(w, noIssues)
})

mux.HandleFunc(
"GET /rest/orgs/{org_id}/packages/pkg%3Apypi%2Fnumpy%401.16.0/issues",
func(w http.ResponseWriter, r *http.Request) {
respond(w, numpyIssues)
})

mux.HandleFunc(
"GET /rest/orgs/{org_id}/packages/pkg%3Apypi%2Fpandas%400.15.0/issues",
func(w http.ResponseWriter, r *http.Request) {
respond(w, pandasIssues)
})

srv := httptest.NewServer(mux)
t.Cleanup(srv.Close)

cfg := DefaultConfig()
cfg.APIToken = "asdf"
cfg.SnykAPIURL = srv.URL

logger := zerolog.Nop()
svc := NewService(cfg, &logger)

return svc
}

func newTestConfig(t *testing.T) *Config {
t.Helper()
c := DefaultConfig()
c.APIToken = "asdf"
return c
func respond(w http.ResponseWriter, data []byte) {
w.Header().Set("content-type", "application/vnd.api+json")
if _, err := w.Write(data); err != nil {
panic(err)
}
}
44 changes: 26 additions & 18 deletions lib/snyk/self_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,43 +17,51 @@
package snyk

import (
_ "embed"
"net/http"
"net/http/httptest"
"testing"

"github.com/deepmap/oapi-codegen/pkg/securityprovider"
"github.com/google/uuid"
"github.com/jarcoal/httpmock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

//go:embed testdata/self.json
var selfBody []byte

func TestSnykOrgID_Success(t *testing.T) {
expectedOrg := uuid.MustParse("00000000-0000-0000-0000-000000000000")
auth, err := securityprovider.NewSecurityProviderApiKey("header", "name", "value")
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
respond(w, selfBody)
}))
defer srv.Close()

cfg := DefaultConfig()
cfg.SnykAPIURL = srv.URL
auth, err := securityprovider.NewSecurityProviderApiKey("header", "authorization", "asdf")
require.NoError(t, err)

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", "https://api.snyk.io/rest/self",
httpmock.NewJsonResponderOrPanic(http.StatusOK, httpmock.File("testdata/self.json")),
)
actualOrg, err := SnykOrgID(cfg, auth)

actualOrg, err := SnykOrgID(DefaultConfig(), auth)
assert.NoError(t, err)
assert.Equal(t, expectedOrg, *actualOrg)
assert.Equal(t, uuid.MustParse("00000000-0000-0000-0000-000000000000"), *actualOrg)
}

func TestSnykOrgID_Unauthorized(t *testing.T) {
auth, err := securityprovider.NewSecurityProviderApiKey("header", "name", "value")
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusUnauthorized)
respond(w, []byte(`{"msg":"unauthorized"}`))
}))
defer srv.Close()

cfg := DefaultConfig()
cfg.SnykAPIURL = srv.URL
auth, err := securityprovider.NewSecurityProviderApiKey("header", "authorization", "asdf")
require.NoError(t, err)

httpmock.Activate()
defer httpmock.DeactivateAndReset()
httpmock.RegisterResponder("GET", "https://api.snyk.io/rest/self",
httpmock.NewJsonResponderOrPanic(http.StatusUnauthorized, []byte(`{"msg":"unauthorized"}`)),
)
actualOrg, err := SnykOrgID(cfg, auth)

actualOrg, err := SnykOrgID(DefaultConfig(), auth)
assert.ErrorContains(t, err, "Failed to get user info (401)")
assert.ErrorContains(t, err, "Failed to get user info (401 Unauthorized)")
assert.Nil(t, actualOrg)
}

0 comments on commit 5b23f91

Please sign in to comment.