8000 chore: add basic test for analysis by PeterSchafer · Pull Request #80 · snyk/code-client-go · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

chore: add basic test for analysis #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
336 changes: 289 additions & 47 deletions internal/analysis/analysis_test.go
8000
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,15 @@ import (
"bytes"
"context"
_ "embed"
"encoding/json"
"fmt"
"io"
"net/http"
"testing"
"time"

"github.com/google/uuid"

"github.com/golang/mock/gomock"
"github.com/google/uuid"
"github.com/rs/zerolog"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
Expand All @@ -35,10 +36,84 @@ import (
confMocks "github.com/snyk/code-client-go/config/mocks"
httpmocks "github.com/snyk/code-client-go/http/mocks"
"github.com/snyk/code-client-go/internal/analysis"
v20241221 "github.com/snyk/code-client-go/internal/api/test/2024-12-21"
mocks2 "github.com/snyk/code-client-go/internal/bundle/mocks"
"github.com/snyk/code-client-go/observability/mocks"
"github.com/snyk/code-client-go/sarif"
"github.com/snyk/code-client-go/scan"
trackerMocks "github.com/snyk/code-client-go/scan/mocks"
)

func mockDeriveErrorFromStatusCode(statusCode int) error {
if statusCode >= http.StatusOK && statusCode < http.StatusBadRequest {
return nil
}

return fmt.Errorf("Statuscode: %d", statusCode)
}

func mockGetDocumentResponse(t *testing.T, sarifResponse sarif.SarifDocument, expectedDocumentPath string, mockHTTPClient *httpmocks.MockHTTPClient, responseCode int) {
t.Helper()
responseBodyBytes, err := json.Marshal(sarifResponse)
assert.NoError(t, err)
expectedDocumentUrl := fmt.Sprintf("http://localhost/hidden%s?version=%s", expectedDocumentPath, v20241221.DocumentApiVersion)
mockHTTPClient.EXPECT().Do(mock.MatchedBy(func(i interface{}) bool {
req := i.(*http.Request)
return req.URL.String() == expectedDocumentUrl
})).Times(1).Return(&http.Response{
StatusCode: responseCode,
Header: http.Header{
"Content-Type": []string{"application/json"},
},
Body: io.NopCloser(bytes.NewReader(responseBodyBytes)),
}, mockDeriveErrorFromStatusCode(responseCode))
}

func mockResultCompletedResponse(t *testing.T, mockHTTPClient *httpmocks.MockHTTPClient, expectedWebuilink string, projectId uuid.UUID, orgId string, testId uuid.UUID, documentPath string, responseCode int) {
t.Helper()
response := v20241221.NewTestResponse()
state := v20241221.NewTestCompleteState()
state.Documents.EnrichedSarif = documentPath
state.Results.Webui.Link = &expectedWebuilink
state.Results.Webui.ProjectId = &projectId
stateBytes, err := json.Marshal(state)
assert.NoError(t, err)
response.Data.Attributes.UnmarshalJSON(stateBytes)
responseBodyBytes, err := json.Marshal(response)
assert.NoError(t, err)
expectedRetrieveTestUrl := fmt.Sprintf("http://localhost/hidden/orgs/%s/tests/%s?version=%s", orgId, testId, v20241221.ApiVersion)
mockHTTPClient.EXPECT().Do(mock.MatchedBy(func(i interface{}) bool {
req := i.(*http.Request)
return req.URL.String() == expectedRetrieveTestUrl
})).Times(1).Return(&http.Response{
StatusCode: responseCode,
Header: http.Header{
"Content-Type": []string{"application/json"},
},
Body: io.NopCloser(bytes.NewReader(responseBodyBytes)),
}, mockDeriveErrorFromStatusCode(responseCode))
}

func mockTestCreatedResponse(t *testing.T, mockHTTPClient *httpmocks.MockHTTPClient, testId uuid.UUID, orgId string, responseCode int) {
t.Helper()
response := v20241221.NewTestResponse()
response.Data.Id = testId
responseBodyBytes, err := json.Marshal(response)
assert.NoError(t, err)
expectedTestCreatedUrl := fmt.Sprintf("http://localhost/hidden/orgs/%s/tests?version=%s", orgId, v20241221.ApiVersion)
mockHTTPClient.EXPECT().Do(mock.MatchedBy(func(i interface{}) bool {
req := i.(*http.Request)
return req.URL.String() == expectedTestCreatedUrl &&
req.Method == http.MethodPost
})).Times(1).Return(&http.Response{
StatusCode: responseCode,
Header: http.Header{
"Content-Type": []string{"application/json"},
},
Body: io.NopCloser(bytes.NewReader(responseBodyBytes)),
}, mockDeriveErrorFromStatusCode(responseCode))
}

func setup(t *testing.T, timeout *time.Duration) (*confMocks.MockConfig, *httpmocks.MockHTTPClient, *mocks.MockInstrumentor, *mocks.MockErrorReporter, *trackerMocks.MockTracker, *trackerMocks.MockTrackerFactory, zerolog.Logger) {
t.Helper()
ctrl := gomock.NewController(t)
Expand Down Expand Up @@ -68,58 +143,88 @@ func setup(t *testing.T, timeout *time.Duration) (*confMocks.MockConfig, *httpmo
return mockConfig, mockHTTPClient, mockInstrumentor, mockErrorReporter, mockTracker, mockTrackerFactory, logger
}

//go:embed fake.json
var fakeResponse []byte
func TestAnalysis_RunTest(t *testing.T) {
ctrl := gomock.NewController(t)
mockConfig, mockHTTPClient, mockInstrumentor, mockErrorReporter, mockTracker, mockTrackerFactory, logger := setup(t, nil)
mockTracker.EXPECT().Begin(gomock.Eq("Snyk Code analysis for ../mypath/"), gomock.Eq("Retrieving results...")).Return()
mockTracker.EXPECT().End(gomock.Eq("Analysis completed.")).Return()

orgId := "4a72d1db-b465-4764-99e1-ecedad03b06a"
projectId := uuid.New()
testId := uuid.New()
report := true
inputBundle := mocks2.NewMockBundle(ctrl)
targetId, err := scan.NewRepositoryTarget("../mypath/")
assert.NoError(t, err)

inputBundle.EXPECT().GetBundleHash().Return("").AnyTimes()
inputBundle.EXPECT().GetLimitToFiles().Return([]string{}).AnyTimes()

// Test Created Response
mockTestCreatedResponse(t, mockHTTPClient, testId, orgId, http.StatusCreated)

// Get Test Result Response
expectedWebuilink := ""
expectedDocumentPath := "/1234"
mockResultCompletedResponse(t, mockHTTPClient, expectedWebuilink, projectId, orgId, testId, expectedDocumentPath, http.StatusOK)

// get document
sarifResponse := sarif.SarifDocument{
Version: "42.0",
}
mockGetDocumentResponse(t, sarifResponse, expectedDocumentPath, mockHTTPClient, http.StatusOK)

analysisOrchestrator := analysis.NewAnalysisOrchestrator(
mockConfig,
mockHTTPClient,
analysis.WithLogger(&logger),
analysis.WithInstrumentor(mockInstrumentor),
analysi 10000 s.WithTrackerFactory(mockTrackerFactory),
analysis.WithErrorReporter(mockErrorReporter),
)

// run method under test
result, resultMetadata, err := analysisOrchestrator.RunTest(
context.Background(),
orgId,
inputBundle,
targetId,
analysis.AnalysisConfig{
Report: report,
},
)

require.NoError(t, err)
assert.NotNil(t, result)
assert.NotNil(t, resultMetadata)
assert.Equal(t, expectedWebuilink, resultMetadata.WebUiUrl)
assert.Equal(t, sarifResponse.Version, result.Sarif.Version)
}

func TestAnalysis_RunTestRemote(t *testing.T) {
t.Skip()
mockConfig, mockHTTPClient, mockInstrumentor, mockErrorReporter, mockTracker, mockTrackerFactory, logger := setup(t, nil)

mockTracker.EXPECT().Begin(gomock.Eq("Snyk Code analysis for remote project"), gomock.Eq("Retrieving results...")).Return()
mockTracker.EXPECT().End(gomock.Eq("Analysis complete.")).Return()
mockTracker.EXPECT().End(gomock.Eq("Analysis completed.")).Return()

orgId := "4a72d1db-b465-4764-99e1-ecedad03b06a"
projectId := uuid.New()
testId := uuid.New()
commitId := "abc123"
report := true

// Mock the initial test creation request
mockHTTPClient.EXPECT().Do(mock.MatchedBy(func(i interface{}) bool {
req := i.(*http.Request)
return req.URL.String() == "http://localhost/hidden/orgs/4a72d1db-b465-4764-99e1-ecedad03b06a/tests?version=2024-12-21" &&
req.Method == http.MethodPost
})).Times(1).Return(&http.Response{
StatusCode: http.StatusCreated,
Header: http.Header{
"Content-Type": []string{"application/json"},
},
Body: io.NopCloser(bytes.NewReader([]byte(`{
"data": {
"id": "a6fb2742-b67f-4dc3-bb27-42b67f1dc344",
"type": "test-result",
"attributes": {
"status": "completed",
"documents": {
"enriched_sarif": "/tests/123/sarif"
}
}
},
"jsonapi": {
"version": "1.0"
},
"links": {
"self": "http://localhost/hidden/orgs/4a72d1db-b465-4764-99e1-ecedad03b06a/tests/a6fb2742-b67f-4dc3-bb27-42b67f1dc344"
}
}`))),
}, nil)
// Mock the findings retrieval request
mockHTTPClient.EXPECT().Do(mock.MatchedBy(func(i interface{}) bool {
req := i.(*http.Request)
return req.URL.String() == "http://localhost/tests/123/sarif" &&
req.Method == http.MethodGet
})).Times(1).Return(&http.Response{
StatusCode: http.StatusOK,
Body: io.NopCloser(bytes.NewReader(fakeResponse)),
}, nil)
// Test Created Response
mockTestCreatedResponse(t, mockHTTPClient, testId, orgId, http.StatusCreated)

// Get Test Result Response
expectedWebuilink := ""
expectedDocumentPath := "/1234"
mockResultCompletedResponse(t, mockHTTPClient, expectedWebuilink, projectId, orgId, testId, expectedDocumentPath, http.StatusOK)

// get document
sarifResponse := sarif.SarifDocument{
Version: "42.0",
}
mockGetDocumentResponse(t, sarifResponse, expectedDocumentPath, mockHTTPClient, http.StatusOK)

analysisOrchestrator := analysis.NewAnalysisOrchestrator(
mockConfig,
Expand All @@ -130,9 +235,10 @@ func TestAnalysis_RunTestRemote(t *testing.T) {
analysis.WithErrorReporter(mockErrorReporter),
)

result, _, err := analysisOrchestrator.RunTestRemote(
// run method under test
result, resultMetadata, err := analysisOrchestrator.RunTestRemote(
context.Background(),
"4a72d1db-b465-4764-99e1-ecedad03b06a",
orgId,
analysis.AnalysisConfig{
ProjectId: &projectId,
CommitId: &commitId,
Expand All @@ -142,6 +248,142 @@ func TestAnalysis_RunTestRemote(t *testing.T) {

require.NoError(t, err)
assert.NotNil(t, result)
assert.NotNil(t, resultMetadata)
assert.Equal(t, expectedWebuilink, resultMetadata.WebUiUrl)
assert.Equal(t, sarifResponse.Version, result.Sarif.Version)
}

func TestAnalysis_RunTestRemote_CreateTestFailed(t *testing.T) {
mockConfig, mockHTTPClient, mockInstrumentor, mockErrorReporter, mockTracker, mockTrackerFactory, logger := setup(t, nil)
mockTracker.EXPECT().Begin(gomock.Eq("Snyk Code analysis for remote project"), gomock.Eq("Retrieving results...")).Return()
mockTracker.EXPECT().End(gomock.Eq("Analysis failed.")).Return()

orgId := "4a72d1db-b465-4764-99e1-ecedad03b06a"
projectId := uuid.New()
testId := uuid.New()
commitId := "abc123"
report := true

// Test Created Response
mockTestCreatedResponse(t, mockHTTPClient, testId, orgId, http.StatusInternalServerError)

analysisOrchestrator := analysis.NewAnalysisOrchestrator(
mockConfig,
mockHTTPClient,
analysis.WithLogger(&logger),
analysis.WithInstrumentor(mockInstrumentor),
analysis.WithTrackerFactory(mockTrackerFactory),
analysis.WithErrorReporter(mockErrorReporter),
)

// run method under test
result, resultMetadata, err := analysisOrchestrator.RunTestRemote(
context.Background(),
orgId,
analysis.AnalysisConfig{
ProjectId: &projectId,
CommitId: &commitId,
Report: report,
},
)

require.Error(t, err)
assert.Nil(t, result)
assert.Nil(t, resultMetadata)
}

func TestAnalysis_RunTestRemote_PollingFailed(t *testing.T) {
mockConfig, mockHTTPClient, mockInstrumentor, mockErrorReporter, mockTracker, mockTrackerFactory, logger := setup(t, nil)
mockTracker.EXPECT().Begin(gomock.Eq("Snyk Code analysis for remote project"), gomock.Eq("Retrieving results...")).Return()
mockTracker.EXPECT().End(gomock.Eq("Analysis failed.")).Return()

orgId := "4a72d1db-b465-4764-99e1-ecedad03b06a"
projectId := uuid.New()
testId := uuid.New()
commitId := "abc123"
report := true

// Test Created Response
mockTestCreatedResponse(t, mockHTTPClient, testId, orgId, http.StatusCreated)

// Get Test Result Response
expectedWebuilink := ""
expectedDocumentPath := "/1234"
mockResultCompletedResponse(t, mockHTTPClient, expectedWebuilink, projectId, orgId, testId, expectedDocumentPath, http.StatusInternalServerError)

analysisOrchestrator := analysis.NewAnalysisOrchestrator(
mockConfig,
mockHTTPClient,
analysis.WithLogger(&logger),
analysis.WithInstrumentor(mockInstrumentor),
analysis.WithTrackerFactory(mockTrackerFactory),
analysis.WithErrorReporter(mockErrorReporter),
)

// run method under test
result, resultMetadata, err := analysisOrchestrator.RunTestRemote(
context.Background(),
orgId,
analysis.AnalysisConfig{
ProjectId: &projectId,
CommitId: &commitId,
Report: report,
},
)

require.Error(t, err)
assert.Nil(t, result)
assert.Nil(t, resultMetadata)
}

func TestAnalysis_RunTestRemote_GetDocumentFailed(t *testing.T) {
mockConfig, mockHTTPClient, mockInstrumentor, mockErrorReporter, mockTracker, mockTrackerFactory, logger := setup(t, nil)
mockTracker.EXPECT().Begin(gomock.Eq("Snyk Code analysis for remote project"), gomock.Eq("Retrieving results...")).Return()
mockTracker.EXPECT().End(gomock.Eq("Analysis failed.")).Return()

orgId := "4a72d1db-b465-4764-99e1-ecedad03b06a"
projectId := uuid.New()
testId := uuid.New()
commitId := "abc123"
report := true

// Test Created Response
mockTestCreatedResponse(t, mockHTTPClient, testId, orgId, http.StatusCreated)

// Get Test Result Response
expectedWebuilink := ""
expectedDocumentPath := "/1234"
mockResultCompletedResponse(t, mockHTTPClient, expectedWebuilink, projectId, orgId, testId, expectedDocumentPath, http.StatusOK)

// get document
sarifResponse := sarif.SarifDocument{
Version: "42.0",
}
mockGetDocumentResponse(t, sarifResponse, expectedDocumentPath, mockHTTPClient, http.StatusInternalServerError)

analysisOrchestrator := analysis.NewAnalysisOrchestrator(
mockConfig,
mockHTTPClient,
analysis.WithLogger(&logger),
analysis.WithInstrumentor(mockInstrumentor),
analysis.WithTrackerFactory(mockTrackerFactory),
analysis.WithErrorReporter(mockErrorReporter),
)

// run method under test
result, resultMetadata, err := analysisOrchestrator.RunTestRemote(
context.Background(),
orgId,
analysis.AnalysisConfig{
ProjectId: &projectId,
CommitId: &commitId,
Report: report,
},
)

require.Error(t, err)
assert.Nil(t, result)
assert.Nil(t, resultMetadata)
}

func TestAnalysis_RunTestRemote_MissingRequiredParams(t *testing.T) {
Expand Down
Loading
0