Implement unit-test for scan handler.

It plays wtih channels and goroutines, so having it
behave correctly is not completely trivial and test
worthy.

Signed-off-by: ttimonen <toni.timonen@iki.fi>
This commit is contained in:
ttimonen
2024-07-07 22:40:58 +00:00
parent 2fdec20b28
commit 48ad56a2ef
3 changed files with 64 additions and 9 deletions
@@ -90,7 +90,6 @@ func (handler *HTTPHandler) Status(w http.ResponseWriter, r *http.Request) {
// ============================================== SCAN ========================================================
// Scan API
func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) {
// generate id
scanID := uuid.NewString()
@@ -101,7 +100,6 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) {
return
}
w.Header().Set("Content-Type", "application/json")
scanRequestParams, err := getScanParamsFromRequest(r, scanID)
if err != nil {
handler.writeError(w, err, "")
@@ -110,12 +108,6 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) {
scanRequestParams.ctx = trace.ContextWithSpanContext(context.Background(), trace.SpanContextFromContext(r.Context()))
handler.state.setBusy(scanID)
response := &utilsmetav1.Response{}
response.ID = scanID
response.Type = utilsapisv1.BusyScanResponseType
response.Response = fmt.Sprintf("scanning '%s' is in progress", scanID)
handler.scanResponseChan.set(scanID) // add channel
defer handler.scanResponseChan.delete(scanID)
@@ -126,6 +118,11 @@ func (handler *HTTPHandler) Scan(w http.ResponseWriter, r *http.Request) {
handler.scanRequestChan <- scanRequestParams
}()
response := &utilsmetav1.Response{
ID: scanID,
Type: utilsapisv1.BusyScanResponseType,
Response: fmt.Sprintf("scanning '%s' is in progress", scanID),
}
if scanRequestParams.scanQueryParams.ReturnResults {
// wait for scan to complete
response = <-handler.scanResponseChan.get(scanID)
@@ -1,5 +1,61 @@
package v1
import (
"bytes"
"context"
"encoding/json"
"io"
"net/http/httptest"
"testing"
"github.com/kubescape/kubescape/v3/core/cautils"
utilsmetav1 "github.com/kubescape/opa-utils/httpserver/meta/v1"
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
)
func testBody(t *testing.T) io.Reader {
t.Helper()
b, err := json.Marshal(utilsmetav1.PostScanRequest{Account: "fakeFoobar"})
if err != nil {
t.Fatal("Can not marshal")
}
return bytes.NewReader(b)
}
type scanner func(_ context.Context, _ *cautils.ScanInfo, _ string) (*reporthandlingv2.PostureReport, error)
// TestScan tests that the scan handler passes the scan requests correctly to the underlying scan engine.
func TestScan(t *testing.T) {
// Our scanner is not setting up the k8s connection; the test is covering the rest of the wiring
// that the signaling from the http handler goes all the way to the scanner implementation.
defer func(o scanner) { scanImpl = o }(scanImpl)
scanImpl = func(context.Context, *cautils.ScanInfo, string) (*reporthandlingv2.PostureReport, error) {
return nil, nil
}
var (
h = NewHTTPHandler()
rq = httptest.NewRequest("POST", "/scan?wait=true", testBody(t))
w = httptest.NewRecorder()
)
h.Scan(w, rq)
rs := w.Result()
body, _ := io.ReadAll(rs.Body)
type out struct {
code int
ctype string
body string
}
want := out{200, "application/json", `{"id":"","type":"v1results"}`}
got := out{rs.StatusCode, rs.Header.Get("Content-type"), string(body)}
if got != want {
t.Errorf("Scan result: %v, want %v", got, want)
}
}
// ============================================== STATUS ========================================================
// Status API
// func TestStatus(t *testing.T) {
@@ -25,11 +25,12 @@ import (
"go.opentelemetry.io/otel/trace"
)
var scanImpl = scan // Override for testing
func (handler *HTTPHandler) executeScan(scanReq *scanRequestParams) {
response := &utilsmetav1.Response{}
logger.L().Info("scan triggered", helpers.String("ID", scanReq.scanID))
_, err := scan(scanReq.ctx, scanReq.scanInfo, scanReq.scanID)
_, err := scanImpl(scanReq.ctx, scanReq.scanInfo, scanReq.scanID)
if err != nil {
logger.L().Ctx(scanReq.ctx).Error("scanning failed", helpers.String("ID", scanReq.scanID), helpers.Error(err))
if scanReq.scanQueryParams.ReturnResults {
@@ -39,6 +40,7 @@ func (handler *HTTPHandler) executeScan(scanReq *scanRequestParams) {
} else {
logger.L().Ctx(scanReq.ctx).Success("done scanning", helpers.String("ID", scanReq.scanID))
if scanReq.scanQueryParams.ReturnResults {
//TODO(ttimonen) should we actually pass the PostureReport here somehow?
response.Type = utilsapisv1.ResultsV1ScanResponseType
}
}