Skip to content
Open
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
57 changes: 57 additions & 0 deletions internal/logger/logger_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,60 @@ func TestLoggerDefaultsToInfoLevelOnInvalidLevel(t *testing.T) {

assert.Equal(t, zapLogger.zap.Level().String(), "info")
}

func TestNoOpLoggerMethods(t *testing.T) {
noop := &NoOpLogger{}

// Verify none of the methods panic
t.Run("Debug", func(t *testing.T) {
noop.Debug("test message", "key", "value")
})
t.Run("Debugf", func(t *testing.T) {
noop.Debugf("test %s", "message")
})
t.Run("Info", func(t *testing.T) {
noop.Info("test message", "key", "value")
})
t.Run("Warn", func(t *testing.T) {
noop.Warn("test message", "key", "value")
})
t.Run("Warnf", func(t *testing.T) {
noop.Warnf("test %s", "message")
})
t.Run("Error", func(t *testing.T) {
noop.Error("test message", assert.AnError, "key", "value")
})
}

func TestZapLoggerMethods(t *testing.T) {
tmpDir := t.TempDir()
fileLocation := path.Join(tmpDir, "test.log")

zapLogger := InitZapLogger(LogConfig{Level: "debug", FileLocation: fileLocation})

t.Run("Debug", func(t *testing.T) {
zapLogger.Debug("debug message", "key", "value")
})
t.Run("Debugf", func(t *testing.T) {
zapLogger.Debugf("debugf %s", "message")
})
t.Run("Info", func(t *testing.T) {
zapLogger.Info("info message", "key", "value")
})
t.Run("Warn", func(t *testing.T) {
zapLogger.Warn("warn message", "key", "value")
})
t.Run("Warnf", func(t *testing.T) {
zapLogger.Warnf("warnf %s", "message")
})
t.Run("Error", func(t *testing.T) {
zapLogger.Error("error message", assert.AnError, "key", "value")
})

// Verify log file was written to
b, err := os.ReadFile(fileLocation)
assert.NoError(t, err)
assert.Contains(t, string(b), "debug message")
assert.Contains(t, string(b), "warn message")
assert.Contains(t, string(b), "error message")
}
21 changes: 21 additions & 0 deletions internal/tracker/time_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package tracker

import (
"testing"
"time"

"github.com/anchore/ecs-inventory/internal/logger"
)

func TestTrackFunctionTime(t *testing.T) {
// Initialize the logger so the function can log without panicking
logger.Log = logger.InitZapLogger(logger.LogConfig{Level: "debug", FileLocation: ""})

t.Run("does not panic with current time", func(t *testing.T) {
TrackFunctionTime(time.Now(), "test function")
})

t.Run("does not panic with past time", func(t *testing.T) {
TrackFunctionTime(time.Now().Add(-5*time.Second), "past time test")
})
}
73 changes: 73 additions & 0 deletions pkg/connection/connection_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package connection

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestAnchoreInfo_IsValid(t *testing.T) {
tests := []struct {
name string
info AnchoreInfo
want bool
}{
{
name: "all fields populated",
info: AnchoreInfo{
URL: "https://ancho.re",
User: "admin",
Password: "foobar",
Account: "test",
},
want: true,
},
{
name: "empty URL",
info: AnchoreInfo{
URL: "",
User: "admin",
Password: "foobar",
},
want: false,
},
{
name: "empty User",
info: AnchoreInfo{
URL: "https://ancho.re",
User: "",
Password: "foobar",
},
want: false,
},
{
name: "empty Password",
info: AnchoreInfo{
URL: "https://ancho.re",
User: "admin",
Password: "",
},
want: false,
},
{
name: "all empty",
info: AnchoreInfo{},
want: false,
},
{
name: "Account empty but URL User Password set",
info: AnchoreInfo{
URL: "https://ancho.re",
User: "admin",
Password: "foobar",
Account: "",
},
want: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assert.Equal(t, tt.want, tt.info.IsValid())
})
}
}
89 changes: 89 additions & 0 deletions pkg/inventory/ecs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,95 @@ func Test_constructServiceARN(t *testing.T) {
}
}

func Test_buildContainerTagMap(t *testing.T) {
tests := []struct {
name string
tasks []ecstypes.Task
want map[string]string
}{
{
name: "empty task list",
tasks: []ecstypes.Task{},
want: map[string]string{},
},
{
name: "containers with @ in image are excluded",
tasks: []ecstypes.Task{
{
Containers: []ecstypes.Container{
{
Image: aws.String("image-1@sha256:abc123"),
ImageDigest: aws.String("sha256:abc123"),
},
},
},
},
want: map[string]string{},
},
{
name: "containers with clean image tags are included",
tasks: []ecstypes.Task{
{
Containers: []ecstypes.Container{
{
Image: aws.String("nginx:latest"),
ImageDigest: aws.String("sha256:abc123"),
},
{
Image: aws.String("redis:7.0"),
ImageDigest: aws.String("sha256:def456"),
},
},
},
},
want: map[string]string{
"sha256:abc123": "nginx:latest",
"sha256:def456": "redis:7.0",
},
},
{
name: "mix of clean and @ images",
tasks: []ecstypes.Task{
{
Containers: []ecstypes.Container{
{
Image: aws.String("nginx:latest"),
ImageDigest: aws.String("sha256:abc123"),
},
{
Image: aws.String("redis@sha256:def456"),
ImageDigest: aws.String("sha256:def456"),
},
},
},
},
want: map[string]string{
"sha256:abc123": "nginx:latest",
},
},
{
name: "nil image digest is skipped",
tasks: []ecstypes.Task{
{
Containers: []ecstypes.Container{
{
Image: aws.String("nginx:latest"),
ImageDigest: nil,
},
},
},
},
want: map[string]string{},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := buildContainerTagMap(tt.tasks)
assert.Equal(t, tt.want, got)
})
}
}

func Test_getContainerImageTag(t *testing.T) {
type args struct {
containerTagMap map[string]string
Expand Down
117 changes: 117 additions & 0 deletions pkg/inventory/report_test.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
package inventory

import (
"bytes"
"context"
"encoding/json"
"os"
"testing"

"github.com/h2non/gock"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/anchore/ecs-inventory/internal/logger"
"github.com/anchore/ecs-inventory/pkg/connection"
"github.com/anchore/ecs-inventory/pkg/reporter"
)

func init() {
logger.Log = &logger.NoOpLogger{}
}

func TestGetInventoryReportForCluster(t *testing.T) {
mockSvc := &mockECSClient{}

Expand All @@ -18,6 +29,112 @@ func TestGetInventoryReportForCluster(t *testing.T) {
assert.Equal(t, 4, len(report.Containers))
}

func TestHandleReport(t *testing.T) {
testReport := reporter.Report{
Timestamp: "2024-01-01T00:00:00Z",
ClusterARN: "arn:aws:ecs:us-east-1:123456789012:cluster/test",
Containers: []reporter.Container{
{
ARN: "arn:aws:ecs:us-east-1:123456789012:container/abc",
ImageTag: "nginx:latest",
ImageDigest: "sha256:abc123",
TaskARN: "arn:aws:ecs:us-east-1:123456789012:task/test/task1",
},
},
}

validAnchore := connection.AnchoreInfo{
URL: "https://ancho.re",
User: "admin",
Password: "foobar",
Account: "test",
HTTP: connection.HTTPConfig{
TimeoutSeconds: 10,
Insecure: true,
},
}

invalidAnchore := connection.AnchoreInfo{}

t.Run("dry run does not post or print", func(t *testing.T) {
err := HandleReport(testReport, validAnchore, true, true)
assert.NoError(t, err)
})

t.Run("valid anchore quiet posts to anchore", func(t *testing.T) {
defer gock.Off()
gock.New("https://ancho.re").
Post("v2/ecs-inventory").
Reply(201).
JSON(map[string]interface{}{})

err := HandleReport(testReport, validAnchore, true, false)
assert.NoError(t, err)
assert.True(t, gock.IsDone())
})

t.Run("invalid anchore not quiet prints to stdout", func(t *testing.T) {
oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

err := HandleReport(testReport, invalidAnchore, false, false)

w.Close()
os.Stdout = oldStdout

var buf bytes.Buffer
buf.ReadFrom(r)
output := buf.String()

assert.NoError(t, err)
assert.Contains(t, output, testReport.ClusterARN)
})

t.Run("invalid anchore quiet does not print", func(t *testing.T) {
err := HandleReport(testReport, invalidAnchore, true, false)
assert.NoError(t, err)
})
}

func Test_reportToStdout(t *testing.T) {
testReport := reporter.Report{
Timestamp: "2024-01-01T00:00:00Z",
ClusterARN: "arn:aws:ecs:us-east-1:123456789012:cluster/test",
Containers: []reporter.Container{
{
ARN: "arn:aws:ecs:us-east-1:123456789012:container/abc",
ImageTag: "nginx:latest",
ImageDigest: "sha256:abc123",
TaskARN: "arn:aws:ecs:us-east-1:123456789012:task/test/task1",
},
},
}

oldStdout := os.Stdout
r, w, _ := os.Pipe()
os.Stdout = w

err := reportToStdout(testReport)

w.Close()
os.Stdout = oldStdout

var buf bytes.Buffer
buf.ReadFrom(r)
output := buf.String()

require.NoError(t, err)

var decoded reporter.Report
err = json.Unmarshal([]byte(output), &decoded)
require.NoError(t, err)
assert.Equal(t, testReport.ClusterARN, decoded.ClusterARN)
assert.Equal(t, testReport.Timestamp, decoded.Timestamp)
assert.Len(t, decoded.Containers, 1)
assert.Equal(t, "nginx:latest", decoded.Containers[0].ImageTag)
}

func Test_ensureReferencedObjectsExist(t *testing.T) {
type args struct {
report reporter.Report
Expand Down
Loading
Loading