Initial QSfera import
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
package scanners_test
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
|
||||
ic "github.com/opencloud-eu/icap-client"
|
||||
|
||||
"github.com/qsfera/server/services/antivirus/pkg/scanners"
|
||||
"github.com/qsfera/server/services/antivirus/pkg/scanners/mocks"
|
||||
)
|
||||
|
||||
func TestICAP_Scan(t *testing.T) {
|
||||
var (
|
||||
earlyExitErr = errors.New("stop here")
|
||||
testUrl = "icap://test"
|
||||
client = mocks.NewScanner(t)
|
||||
scanner = &scanners.ICAP{Client: client, URL: testUrl}
|
||||
)
|
||||
|
||||
t.Run("it sends a OPTIONS request to determine details", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, ic.MethodOPTIONS, request.Method)
|
||||
assert.Equal(t, testUrl, request.URL.String())
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{})
|
||||
assert.ErrorIs(t, earlyExitErr, err) // we can exit early, just in case check the error to be identical to the early exit error
|
||||
})
|
||||
|
||||
t.Run("it sends a REQMOD request with all the details", func(t *testing.T) {
|
||||
|
||||
t.Run("request with ContentLength", func(t *testing.T) {
|
||||
t.Run("with size", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, ic.MethodREQMOD, request.Method)
|
||||
assert.Equal(t, testUrl, request.URL.String())
|
||||
assert.EqualValues(t, 999, request.HTTPRequest.ContentLength)
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{Size: 999})
|
||||
assert.ErrorIs(t, earlyExitErr, err)
|
||||
})
|
||||
|
||||
t.Run("without size", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, ic.MethodREQMOD, request.Method)
|
||||
assert.Equal(t, testUrl, request.URL.String())
|
||||
assert.EqualValues(t, 0, request.HTTPRequest.ContentLength)
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{})
|
||||
assert.ErrorIs(t, earlyExitErr, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("request with Content-Type header", func(t *testing.T) {
|
||||
t.Run("name contains known extension", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, "application/pdf", request.HTTPRequest.Header.Get("Content-Type"))
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{Name: "report.pdf"})
|
||||
assert.ErrorIs(t, earlyExitErr, err)
|
||||
})
|
||||
|
||||
t.Run("name with unknown extension", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, "application/octet-stream", request.HTTPRequest.Header.Get("Content-Type"))
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{Name: "report.unknown"})
|
||||
assert.ErrorIs(t, earlyExitErr, err)
|
||||
})
|
||||
|
||||
t.Run("name without extension", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, "httpd/unix-directory", request.HTTPRequest.Header.Get("Content-Type"))
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{Name: "report"})
|
||||
assert.ErrorIs(t, earlyExitErr, err)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("request with the OPTIONS response preview size ", func(t *testing.T) {
|
||||
t.Run("with PreviewBytes set", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{PreviewBytes: 444}, nil).Once()
|
||||
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, 444, request.PreviewBytes)
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{Body: bytes.NewReader(make([]byte, 888))})
|
||||
assert.ErrorIs(t, earlyExitErr, err)
|
||||
})
|
||||
|
||||
t.Run("without PreviewBytes set", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, 0, request.PreviewBytes)
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{Body: bytes.NewReader(make([]byte, 888))})
|
||||
assert.ErrorIs(t, earlyExitErr, err)
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("request with the OPTIONS response preview size ", func(t *testing.T) {
|
||||
t.Run("with PreviewBytes set", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{PreviewBytes: 444}, nil).Once()
|
||||
|
||||
client.EXPECT().Do(mock.Anything).RunAndReturn(func(request ic.Request) (ic.Response, error) {
|
||||
assert.Equal(t, 444, request.PreviewBytes)
|
||||
return ic.Response{}, earlyExitErr
|
||||
}).Once()
|
||||
|
||||
_, err := scanner.Scan(scanners.Input{Body: bytes.NewReader(make([]byte, 888))})
|
||||
assert.ErrorIs(t, earlyExitErr, err)
|
||||
})
|
||||
|
||||
t.Run("it handles virus scan results", func(t *testing.T) {
|
||||
t.Run("no virus", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
|
||||
result, err := scanner.Scan(scanners.Input{})
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, result.Infected)
|
||||
})
|
||||
|
||||
// clamav returns an X-Infection-Found header with the threat description
|
||||
t.Run("X-Infection-Found header ", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{Header: http.Header{"X-Infection-Found": []string{"Threat=bad threat;"}}}, nil).Once()
|
||||
|
||||
result, err := scanner.Scan(scanners.Input{})
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, result.Infected)
|
||||
assert.Equal(t, "bad threat", result.Description)
|
||||
})
|
||||
|
||||
// skyhigh returns the information via the content response
|
||||
t.Run("X-Infection-Found header", func(t *testing.T) {
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{ContentResponse: &http.Response{StatusCode: http.StatusForbidden, Status: "some status"}}, nil).Once()
|
||||
|
||||
result, err := scanner.Scan(scanners.Input{})
|
||||
assert.Nil(t, err)
|
||||
assert.True(t, result.Infected)
|
||||
assert.Equal(t, "some status", result.Description)
|
||||
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{}, nil).Once()
|
||||
client.EXPECT().Do(mock.Anything).Return(ic.Response{ContentResponse: &http.Response{StatusCode: http.StatusOK}}, nil).Once()
|
||||
|
||||
result, err = scanner.Scan(scanners.Input{})
|
||||
assert.Nil(t, err)
|
||||
assert.False(t, result.Infected)
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user