231 lines
5.1 KiB
Go
231 lines
5.1 KiB
Go
package cameradar_test
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"sync"
|
|
"testing"
|
|
|
|
"github.com/Ullaakut/cameradar/v6"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func TestNew(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
scanner cameradar.StreamScanner
|
|
attacker cameradar.StreamAttacker
|
|
wantErr require.ErrorAssertionFunc
|
|
wantMsg string
|
|
}{
|
|
{
|
|
name: "missing scanner",
|
|
scanner: nil,
|
|
attacker: &fakeAttacker{},
|
|
wantErr: require.Error,
|
|
wantMsg: "stream scanner is required",
|
|
},
|
|
{
|
|
name: "missing attacker",
|
|
scanner: &fakeScanner{},
|
|
attacker: nil,
|
|
wantErr: require.Error,
|
|
wantMsg: "stream attacker is required",
|
|
},
|
|
{
|
|
name: "valid",
|
|
scanner: &fakeScanner{},
|
|
attacker: &fakeAttacker{},
|
|
wantErr: require.NoError,
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
app, err := cameradar.New(test.scanner, test.attacker, []string{"target"}, []string{"554"}, &recordingReporter{})
|
|
test.wantErr(t, err)
|
|
if test.wantMsg != "" {
|
|
assert.ErrorContains(t, err, test.wantMsg)
|
|
}
|
|
if err == nil {
|
|
require.NotNil(t, app)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestApp_Run(t *testing.T) {
|
|
ctx := t.Context()
|
|
streams := []cameradar.Stream{{Port: 554}}
|
|
attacked := []cameradar.Stream{{Port: 8554}}
|
|
|
|
tests := []struct {
|
|
name string
|
|
scanner *fakeScanner
|
|
attacker *fakeAttacker
|
|
wantErrContains string
|
|
wantErrorCalls int
|
|
wantDoneCalls int
|
|
wantSummaryErr string
|
|
wantSummary []cameradar.Stream
|
|
}{
|
|
{
|
|
name: "success",
|
|
scanner: &fakeScanner{
|
|
streams: streams,
|
|
},
|
|
attacker: &fakeAttacker{
|
|
streams: attacked,
|
|
},
|
|
wantDoneCalls: 1,
|
|
wantSummary: attacked,
|
|
wantSummaryErr: "",
|
|
},
|
|
{
|
|
name: "scan error",
|
|
scanner: &fakeScanner{
|
|
streams: streams,
|
|
err: errors.New("scan failed"),
|
|
},
|
|
attacker: &fakeAttacker{},
|
|
wantErrContains: "discovering devices",
|
|
wantErrorCalls: 1,
|
|
wantSummary: streams,
|
|
wantSummaryErr: "discovering devices",
|
|
},
|
|
{
|
|
name: "attack error",
|
|
scanner: &fakeScanner{
|
|
streams: streams,
|
|
},
|
|
attacker: &fakeAttacker{
|
|
err: errors.New("attack failed"),
|
|
},
|
|
wantErrContains: "attacking devices",
|
|
wantDoneCalls: 1,
|
|
wantSummary: streams,
|
|
wantSummaryErr: "attacking devices",
|
|
},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
t.Run(test.name, func(t *testing.T) {
|
|
reporter := &recordingReporter{}
|
|
scanner := test.scanner
|
|
attacker := test.attacker
|
|
|
|
app, err := cameradar.New(scanner, attacker, []string{"target"}, []string{"554"}, reporter)
|
|
require.NoError(t, err)
|
|
|
|
err = app.Run(ctx)
|
|
if test.wantErrContains != "" {
|
|
require.Error(t, err)
|
|
assert.ErrorContains(t, err, test.wantErrContains)
|
|
} else {
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
assert.Equal(t, 1, scanner.calls)
|
|
assert.Same(t, ctx, scanner.gotCtx)
|
|
|
|
if test.wantErrContains == "discovering devices" {
|
|
assert.Equal(t, 0, attacker.calls)
|
|
} else {
|
|
assert.Equal(t, 1, attacker.calls)
|
|
assert.Equal(t, streams, attacker.gotStreams)
|
|
}
|
|
|
|
assert.Equal(t, 1, reporter.startCalls)
|
|
assert.Equal(t, test.wantDoneCalls, reporter.doneCalls)
|
|
assert.Equal(t, test.wantErrorCalls, reporter.errorCalls)
|
|
require.Equal(t, 1, reporter.summaryCalls)
|
|
assert.Equal(t, test.wantSummary, reporter.summaryStreams)
|
|
if test.wantSummaryErr == "" {
|
|
assert.NoError(t, reporter.summaryErr)
|
|
} else {
|
|
require.Error(t, reporter.summaryErr)
|
|
assert.ErrorContains(t, reporter.summaryErr, test.wantSummaryErr)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type fakeScanner struct {
|
|
streams []cameradar.Stream
|
|
err error
|
|
|
|
calls int
|
|
gotCtx context.Context
|
|
gotTargets []string
|
|
gotPorts []string
|
|
}
|
|
|
|
func (f *fakeScanner) Scan(ctx context.Context) ([]cameradar.Stream, error) {
|
|
f.calls++
|
|
f.gotCtx = ctx
|
|
return f.streams, f.err
|
|
}
|
|
|
|
type fakeAttacker struct {
|
|
streams []cameradar.Stream
|
|
err error
|
|
|
|
calls int
|
|
gotStreams []cameradar.Stream
|
|
}
|
|
|
|
func (f *fakeAttacker) Attack(_ context.Context, streams []cameradar.Stream) ([]cameradar.Stream, error) {
|
|
f.calls++
|
|
f.gotStreams = append([]cameradar.Stream(nil), streams...)
|
|
if f.err != nil {
|
|
return streams, f.err
|
|
}
|
|
if f.streams != nil {
|
|
return f.streams, nil
|
|
}
|
|
return streams, nil
|
|
}
|
|
|
|
type recordingReporter struct {
|
|
mu sync.Mutex
|
|
startCalls int
|
|
doneCalls int
|
|
errorCalls int
|
|
summaryCalls int
|
|
summaryStreams []cameradar.Stream
|
|
summaryErr error
|
|
}
|
|
|
|
func (r *recordingReporter) Start(cameradar.Step, string) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.startCalls++
|
|
}
|
|
|
|
func (r *recordingReporter) Done(cameradar.Step, string) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.doneCalls++
|
|
}
|
|
|
|
func (r *recordingReporter) Progress(cameradar.Step, string) {}
|
|
|
|
func (r *recordingReporter) Debug(cameradar.Step, string) {}
|
|
|
|
func (r *recordingReporter) Error(cameradar.Step, error) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.errorCalls++
|
|
}
|
|
|
|
func (r *recordingReporter) Summary(streams []cameradar.Stream, err error) {
|
|
r.mu.Lock()
|
|
defer r.mu.Unlock()
|
|
r.summaryCalls++
|
|
r.summaryStreams = append([]cameradar.Stream(nil), streams...)
|
|
r.summaryErr = err
|
|
}
|
|
|
|
func (r *recordingReporter) Close() {}
|