driftctl/pkg/cmd/scan/output/html_test.go

386 lines
9.4 KiB
Go

package output
import (
"io/ioutil"
"path"
"testing"
"time"
"github.com/r3labs/diff/v2"
"github.com/snyk/driftctl/pkg/resource"
"github.com/stretchr/testify/assert"
"github.com/snyk/driftctl/pkg/analyser"
"github.com/snyk/driftctl/test/goldenfile"
)
func TestHTML_Write(t *testing.T) {
tests := []struct {
name string
goldenfile string
analysis func() *analyser.Analysis
err error
}{
{
name: "test html output when there's no resources",
goldenfile: "output_empty.html",
analysis: func() *analyser.Analysis {
a := &analyser.Analysis{}
a.Date = time.Date(2021, 06, 10, 0, 0, 0, 0, &time.Location{})
a.ProviderName = "AWS"
a.ProviderVersion = "3.19.0"
return a
},
err: nil,
},
{
name: "test html output when infrastructure is in sync",
goldenfile: "output_sync.html",
analysis: func() *analyser.Analysis {
a := &analyser.Analysis{}
a.Date = time.Date(2021, 06, 10, 0, 0, 0, 0, &time.Location{})
a.Duration = 72 * time.Second
a.AddManaged(
&resource.Resource{
Id: "deleted-id-3",
Type: "aws_deleted_resource",
},
)
a.ProviderName = "AWS"
a.ProviderVersion = "3.19.0"
return a
},
err: nil,
},
{
name: "test html output",
goldenfile: "output.html",
analysis: func() *analyser.Analysis {
a := fakeAnalysisWithAlerts()
a.Date = time.Date(2021, 06, 10, 0, 0, 0, 0, &time.Location{})
a.Duration = 91 * time.Second
a.AddManaged(
&resource.Resource{
Id: "diff-id-2",
Type: "aws_diff_resource",
Source: &resource.TerraformStateSource{
State: "tfstate://state.tfstate",
Name: "diff-id-2",
Module: "module",
},
},
&resource.Resource{
Id: "diff-id-3",
Type: "aws_diff_resource",
Source: &resource.TerraformStateSource{
State: "tfstate+s3://state2.tfstate",
Name: "b",
},
},
)
a.AddDeleted(
&resource.Resource{
Id: "deleted-id-3",
Type: "aws_deleted_resource",
Source: &resource.TerraformStateSource{
State: "tfstate://deleted/terraform.tfstate",
Name: "deleted-id-3",
},
},
&resource.Resource{
Id: "deleted-id-4",
Type: "aws_deleted_resource",
Source: &resource.TerraformStateSource{
State: "tfstate://deleted/terraform.tfstate",
Name: "deleted-id-3",
},
},
&resource.Resource{
Id: "deleted-id-5",
Type: "aws_deleted_resource",
Source: &resource.TerraformStateSource{
State: "tfstate://deleted/terraform.tfstate",
Name: "deleted-id-3",
Module: "module-1",
},
},
&resource.Resource{
Id: "deleted-id-6",
Type: "aws_deleted_resource",
},
)
a.AddUnmanaged(
&resource.Resource{
Id: "unmanaged-id-3",
Type: "aws_unmanaged_resource",
},
&resource.Resource{
Id: "unmanaged-id-4",
Type: "aws_unmanaged_resource",
},
&resource.Resource{
Id: "unmanaged-id-5",
Type: "aws_unmanaged_resource",
},
)
a.AddDifference(analyser.Difference{
Res: &resource.Resource{
Id: "diff-id-2",
Type: "aws_diff_resource",
Source: &resource.TerraformStateSource{
State: "tfstate://state.tfstate",
Name: "diff-id-2",
Module: "module",
},
}, Changelog: []analyser.Change{
{
Change: diff.Change{
Type: diff.DELETE,
Path: []string{"path", "to", "fields", "0"},
From: "value",
To: nil,
},
},
{
Change: diff.Change{
Type: diff.UPDATE,
Path: []string{"path", "to", "fields", "1"},
From: 12,
To: "12",
},
},
{
Change: diff.Change{
Type: diff.DELETE,
Path: []string{"group_ids"},
From: []string{"a071314398026"},
To: nil,
},
},
{
JsonString: true,
Change: diff.Change{
Type: diff.UPDATE,
Path: []string{"policy"},
From: `{"Statement":[{"Action":["s3:GetObjectVersion"],"Effect":"Allow","Principal":"*","Resource":"arn:aws:s3:::tmxxrn.foobar.driftctl-test.com/*","Sid":"PublicRead"}],"Version":"2012-10-17"}`,
To: `{"Statement":[{"Action":["*"],"Effect":"Deny","Principal":"*","Resource":"arn:aws:s3:::tmxxrn.foobar.driftctl-test.com/b/*","Sid":"PublicReadWrite"},{"Effect":"Deny","Sid":"PublicReadWrite"}],"Version":"2021-10-17","Test":[]}`,
},
},
{
Change: diff.Change{
Type: diff.CREATE,
Path: []string{"Tags", "0", "Name"},
From: nil,
To: "test",
},
},
{
Change: diff.Change{
Type: diff.UPDATE,
Path: []string{"InstanceInitiatedShutdownBehavior"},
From: "",
To: nil,
},
},
}})
a.ProviderName = "AWS"
a.ProviderVersion = "3.19.0"
return a
},
err: nil,
},
{
name: "test html output when coverage is 100",
goldenfile: "output_coverage_100.html",
analysis: func() *analyser.Analysis {
a := &analyser.Analysis{}
a.Date = time.Date(2021, 06, 10, 0, 0, 0, 0, &time.Location{})
a.Duration = 91 * time.Second
a.AddManaged(
&resource.Resource{
Id: "resource-id-1",
Type: "aws_resource",
Source: &resource.TerraformStateSource{
State: "tfstate://state.tfstate",
Module: "module",
Name: "name",
},
},
)
a.AddDifference(analyser.Difference{
Res: &resource.Resource{
Id: "resource-id-1",
Type: "aws_resource",
Source: &resource.TerraformStateSource{
State: "tfstate://state.tfstate",
Module: "module",
Name: "name",
},
}, Changelog: []analyser.Change{
{
Change: diff.Change{
Type: diff.DELETE,
Path: []string{"path", "to", "fields", "0"},
From: "value",
To: nil,
},
},
}})
a.ProviderName = "AWS"
a.ProviderVersion = "3.19.0"
return a
},
err: nil,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tempDir := t.TempDir()
tempFile, err := ioutil.TempFile(tempDir, "result")
if err != nil {
t.Fatal(err)
}
c := NewHTML(tempFile.Name())
err = c.Write(tt.analysis())
if tt.err != nil {
assert.EqualError(t, err, tt.err.Error())
} else {
assert.NoError(t, err)
}
got, err := ioutil.ReadFile(tempFile.Name())
if err != nil {
t.Fatal(err)
}
expectedFilePath := path.Join("./testdata/", tt.goldenfile)
if *goldenfile.Update == tt.goldenfile {
if err := ioutil.WriteFile(expectedFilePath, got, 0600); err != nil {
t.Fatal(err)
}
}
expected, err := ioutil.ReadFile(expectedFilePath)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, string(expected), string(got))
})
}
}
func TestHTML_DistinctResourceTypes(t *testing.T) {
tests := []struct {
name string
resources []*resource.Resource
value []string
}{
{
name: "should return empty array",
resources: []*resource.Resource{},
value: []string{},
},
{
name: "should return distinct list of resource types",
resources: []*resource.Resource{
{
Id: "deleted-id-1",
Type: "aws_deleted_resource",
},
{
Id: "unmanaged-id-1",
Type: "aws_unmanaged_resource",
},
{
Id: "unmanaged-id-2",
Type: "aws_unmanaged_resource",
},
{
Id: "diff-id-1",
Type: "aws_diff_resource",
},
{
Id: "deleted-id-2",
Type: "aws_deleted_resource",
},
},
value: []string{"aws_deleted_resource", "aws_unmanaged_resource", "aws_diff_resource"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := distinctResourceTypes(tt.resources)
assert.Equal(t, tt.value, got)
})
}
}
func TestHTML_DistinctIaCSources(t *testing.T) {
tests := []struct {
name string
resources []*resource.Resource
value []string
}{
{
name: "should return empty array",
resources: []*resource.Resource{},
value: []string{},
},
{
name: "should return distinct list of iac sources",
resources: []*resource.Resource{
{
Id: "deleted-id-1",
Type: "aws_deleted_resource",
Source: &resource.TerraformStateSource{
Module: "module",
Name: "test",
State: "tfstate://terraform.tfstate",
},
},
{
Id: "unmanaged-id-1",
Type: "aws_unmanaged_resource",
Source: &resource.TerraformStateSource{
Module: "module",
Name: "test",
State: "tfstate://terraform2.tfstate",
},
},
{
Id: "unmanaged-id-2",
Type: "aws_unmanaged_resource",
Source: &resource.TerraformStateSource{
Module: "module",
Name: "test",
State: "tfstate+s3://test/terraform.tfstate",
},
},
{
Id: "diff-id-1",
Type: "aws_diff_resource",
Source: &resource.TerraformStateSource{
Module: "module",
Name: "test",
State: "tfstate://terraform.tfstate",
},
},
{
Id: "deleted-id-2",
Type: "aws_deleted_resource",
},
},
value: []string{"tfstate://terraform.tfstate", "tfstate://terraform2.tfstate", "tfstate+s3://test/terraform.tfstate"},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := distinctIaCSources(tt.resources)
assert.Equal(t, tt.value, got)
})
}
}