harbor/src/pkg/scan/rest/v1/client_test.go

193 lines
4.8 KiB
Go

// Copyright Project Harbor Authors
//
// 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 v1
import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/stretchr/testify/suite"
)
// ClientTestSuite tests the v1 client
type ClientTestSuite struct {
suite.Suite
testServer *httptest.Server
client Client
}
// TestClient is the entry of ClientTestSuite
func TestClient(t *testing.T) {
suite.Run(t, new(ClientTestSuite))
}
// SetupSuite prepares the test suite env
func (suite *ClientTestSuite) SetupSuite() {
suite.testServer = httptest.NewServer(&mockHandler{})
c, err := NewClient(suite.testServer.URL, "", "", true)
require.NoError(suite.T(), err)
require.NotNil(suite.T(), c)
suite.client = c
}
// TestClientMetadata tests the metadata of the client
func (suite *ClientTestSuite) TestClientMetadata() {
m, err := suite.client.GetMetadata()
require.NoError(suite.T(), err)
require.NotNil(suite.T(), m)
assert.Equal(suite.T(), m.Scanner.Name, "Trivy")
assert.Equal(suite.T(), m.Capabilities[0].Type, "sbom")
}
// TestClientSubmitScan tests the scan submission of client
func (suite *ClientTestSuite) TestClientSubmitScan() {
res, err := suite.client.SubmitScan(&ScanRequest{})
require.NoError(suite.T(), err)
require.NotNil(suite.T(), res)
assert.Equal(suite.T(), res.ID, "123456789")
}
// TestClientGetScanReportError tests getting report failed
func (suite *ClientTestSuite) TestClientGetScanReportError() {
_, err := suite.client.GetScanReport("id1", MimeTypeNativeReport, "")
require.Error(suite.T(), err)
assert.Condition(suite.T(), func() (success bool) {
success = strings.Index(err.Error(), "error") != -1
return
})
}
// TestClientGetScanReport tests getting report
func (suite *ClientTestSuite) TestClientGetScanReport() {
res, err := suite.client.GetScanReport("id2", MimeTypeNativeReport, "")
require.NoError(suite.T(), err)
require.NotEmpty(suite.T(), res)
}
// TestClientGetScanReportNotReady tests the case that the report is not ready
func (suite *ClientTestSuite) TestClientGetScanReportNotReady() {
_, err := suite.client.GetScanReport("id3", MimeTypeNativeReport, "")
require.Error(suite.T(), err)
require.Condition(suite.T(), func() (success bool) {
_, success = err.(*ReportNotReadyError)
return
})
assert.Equal(suite.T(), 10, err.(*ReportNotReadyError).RetryAfter)
}
// TearDownSuite clears the test suite env
func (suite *ClientTestSuite) TearDownSuite() {
suite.testServer.Close()
}
type mockHandler struct{}
// ServeHTTP ...
func (mh *mockHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.RequestURI {
case "/api/v1/metadata":
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusForbidden)
return
}
m := &ScannerAdapterMetadata{
Scanner: &Scanner{
Name: "Trivy",
Vendor: "Harbor",
Version: "0.1.0",
},
Capabilities: []*ScannerCapability{{
Type: "sbom",
ConsumesMimeTypes: []string{
MimeTypeOCIArtifact,
MimeTypeDockerArtifact,
},
ProducesMimeTypes: []string{
MimeTypeNativeReport,
MimeTypeRawReport,
MimeTypeGenericVulnerabilityReport,
},
}},
Properties: ScannerProperties{
"extra": "testing",
},
}
data, _ := json.Marshal(m)
w.WriteHeader(http.StatusOK)
_, _ = w.Write(data)
break
case "/api/v1/scan":
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusForbidden)
return
}
res := &ScanResponse{}
res.ID = "123456789"
data, _ := json.Marshal(res)
w.WriteHeader(http.StatusAccepted)
_, _ = w.Write(data)
break
case "/api/v1/scan/id1/report":
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusForbidden)
return
}
e := &ErrorResponse{
&Error{
Message: "error",
},
}
data, _ := json.Marshal(e)
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write(data)
break
case "/api/v1/scan/id2/report":
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusForbidden)
return
}
w.WriteHeader(http.StatusOK)
_, _ = w.Write([]byte("{}"))
break
case "/api/v1/scan/id3/report":
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusForbidden)
return
}
w.Header().Add(refreshAfterHeader, fmt.Sprintf("%d", 10))
w.Header().Add("Location", "/scan/id3/report")
w.WriteHeader(http.StatusFound)
break
}
}