mirror of
https://github.com/kubescape/kubescape.git
synced 2026-02-14 09:59:54 +00:00
* fixed test Signed-off-by: David Wertenteil <dwertent@armosec.io> * update cosign-release version Signed-off-by: David Wertenteil <dwertent@armosec.io> * fixed filepath related tests Signed-off-by: David Wertenteil <dwertent@armosec.io> * failed windows tests Signed-off-by: David Wertenteil <dwertent@armosec.io> * fixed cosign version Signed-off-by: David Wertenteil <dwertent@armosec.io> * update go version Signed-off-by: David Wertenteil <dwertent@armosec.io> * fixed test Signed-off-by: David Wertenteil <dwertent@armosec.io> * change actor Signed-off-by: David Wertenteil <dwertent@armosec.io> * Cosign use secret Signed-off-by: David Wertenteil <dwertent@armosec.io> * update cosign Signed-off-by: David Wertenteil <dwertent@armosec.io> * update cosign Signed-off-by: David Wertenteil <dwertent@armosec.io> --------- Signed-off-by: David Wertenteil <dwertent@armosec.io>
654 lines
16 KiB
Go
654 lines
16 KiB
Go
package fixhandler
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"testing"
|
|
|
|
"github.com/armosec/armoapi-go/armotypes"
|
|
logger "github.com/kubescape/go-logger"
|
|
metav1 "github.com/kubescape/kubescape/v3/core/meta/datastructures/v1"
|
|
"github.com/kubescape/kubescape/v3/internal/testutils"
|
|
reporthandlingv2 "github.com/kubescape/opa-utils/reporthandling/v2"
|
|
"github.com/mikefarah/yq/v4/pkg/yqlib"
|
|
"github.com/stretchr/testify/assert"
|
|
"gopkg.in/op/go-logging.v1"
|
|
)
|
|
|
|
type indentationTestCase struct {
|
|
inputFile string
|
|
yamlExpression string
|
|
expectedFile string
|
|
}
|
|
|
|
func NewFixHandlerMock() (*FixHandler, error) {
|
|
backendLoggerLeveled := logging.AddModuleLevel(logging.NewLogBackend(logger.L().GetWriter(), "", 0))
|
|
backendLoggerLeveled.SetLevel(logging.ERROR, "")
|
|
yqlib.GetLogger().SetBackend(backendLoggerLeveled)
|
|
|
|
return &FixHandler{
|
|
fixInfo: &metav1.FixInfo{},
|
|
reportObj: &reporthandlingv2.PostureReport{},
|
|
localBasePath: "",
|
|
}, nil
|
|
}
|
|
|
|
func getTestCases() []indentationTestCase {
|
|
indentationTestCases := []indentationTestCase{
|
|
// Insertion Scenarios
|
|
{
|
|
"inserts/tc-01-00-input-mapping-insert-mapping.yaml",
|
|
"select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false",
|
|
"inserts/tc-01-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-02-00-input-mapping-insert-mapping-with-list.yaml",
|
|
"select(di==0).spec.containers[0].securityContext.capabilities.drop += [\"NET_RAW\"]",
|
|
"inserts/tc-02-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-03-00-input-list-append-scalar.yaml",
|
|
"select(di==0).spec.containers[0].securityContext.capabilities.drop += [\"SYS_ADM\"]",
|
|
"inserts/tc-03-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-04-00-input-multiple-inserts.yaml",
|
|
|
|
`select(di==0).spec.template.spec.securityContext.allowPrivilegeEscalation |= false |
|
|
select(di==0).spec.template.spec.containers[0].securityContext.capabilities.drop += ["NET_RAW"] |
|
|
select(di==0).spec.template.spec.containers[0].securityContext.seccompProfile.type |= "RuntimeDefault" |
|
|
select(di==0).spec.template.spec.containers[0].securityContext.allowPrivilegeEscalation |= false |
|
|
select(di==0).spec.template.spec.containers[0].securityContext.readOnlyRootFilesystem |= true`,
|
|
|
|
"inserts/tc-04-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-05-00-input-comment-blank-line-single-insert.yaml",
|
|
"select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false",
|
|
"inserts/tc-05-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-06-00-input-list-append-scalar-oneline.yaml",
|
|
"select(di==0).spec.containers[0].securityContext.capabilities.drop += [\"SYS_ADM\"]",
|
|
"inserts/tc-06-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-07-00-input-multiple-documents.yaml",
|
|
|
|
`select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false |
|
|
select(di==1).spec.containers[0].securityContext.allowPrivilegeEscalation |= false`,
|
|
|
|
"inserts/tc-07-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-08-00-input-mapping-insert-mapping-indented.yaml",
|
|
"select(di==0).spec.containers[0].securityContext.capabilities.drop += [\"NET_RAW\"]",
|
|
"inserts/tc-08-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-09-00-input-list-insert-new-mapping-indented.yaml",
|
|
`select(di==0).spec.containers += {"name": "redis", "image": "redis"}`,
|
|
"inserts/tc-09-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-10-00-input-list-insert-new-mapping.yaml",
|
|
`select(di==0).spec.containers += {"name": "redis", "image": "redis"}`,
|
|
"inserts/tc-10-01-expected.yaml",
|
|
},
|
|
{
|
|
"inserts/tc-11-00-input-list-insert-new-mapping-crlf-newlines.yaml",
|
|
`select(di==0).spec.containers += {"name": "redis", "image": "redis"}`,
|
|
"inserts/tc-11-01-expected.yaml",
|
|
},
|
|
|
|
// Starts with ---
|
|
{
|
|
"inserts/tc-12-00-begin-with-document-separator.yaml",
|
|
"select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false",
|
|
"inserts/tc-12-01-expected.yaml",
|
|
},
|
|
|
|
// Removal Scenarios
|
|
{
|
|
"removals/tc-01-00-input.yaml",
|
|
"del(select(di==0).spec.containers[0].securityContext)",
|
|
"removals/tc-01-01-expected.yaml",
|
|
},
|
|
{
|
|
"removals/tc-02-00-input.yaml",
|
|
"del(select(di==0).spec.containers[1])",
|
|
"removals/tc-02-01-expected.yaml",
|
|
},
|
|
{
|
|
"removals/tc-03-00-input.yaml",
|
|
"del(select(di==0).spec.containers[0].securityContext.capabilities.drop[1])",
|
|
"removals/tc-03-01-expected.yaml",
|
|
},
|
|
{
|
|
"removals/tc-04-00-input.yaml",
|
|
`del(select(di==0).spec.containers[0].securityContext) |
|
|
del(select(di==1).spec.containers[1])`,
|
|
"removals/tc-04-01-expected.yaml",
|
|
},
|
|
|
|
// Replace Scenarios
|
|
{
|
|
"replaces/tc-01-00-input.yaml",
|
|
"select(di==0).spec.containers[0].securityContext.runAsRoot |= false",
|
|
"replaces/tc-01-01-expected.yaml",
|
|
},
|
|
{
|
|
"replaces/tc-02-00-input.yaml",
|
|
`select(di==0).spec.containers[0].securityContext.capabilities.drop[0] |= "SYS_ADM" |
|
|
select(di==0).spec.containers[0].securityContext.capabilities.add[0] |= "NET_RAW"`,
|
|
"replaces/tc-02-01-expected.yaml",
|
|
},
|
|
|
|
// Hybrid Scenarios
|
|
{
|
|
"hybrids/tc-01-00-input.yaml",
|
|
`del(select(di==0).spec.containers[0].securityContext) |
|
|
select(di==0).spec.securityContext.runAsRoot |= false`,
|
|
"hybrids/tc-01-01-expected.yaml",
|
|
},
|
|
{
|
|
"hybrids/tc-02-00-input-indented-list.yaml",
|
|
`del(select(di==0).spec.containers[0].securityContext) |
|
|
select(di==0).spec.securityContext.runAsRoot |= false`,
|
|
"hybrids/tc-02-01-expected.yaml",
|
|
},
|
|
{
|
|
"hybrids/tc-03-00-input-comments.yaml",
|
|
`del(select(di==0).spec.containers[0].securityContext) |
|
|
select(di==0).spec.securityContext.runAsRoot |= false`,
|
|
"hybrids/tc-03-01-expected.yaml",
|
|
},
|
|
{
|
|
"hybrids/tc-04-00-input-separated-keys.yaml",
|
|
`del(select(di==0).spec.containers[0].securityContext) |
|
|
select(di==0).spec.securityContext.runAsRoot |= false`,
|
|
"hybrids/tc-04-01-expected.yaml",
|
|
},
|
|
{
|
|
"hybrids/tc-05-00-input-leading-doc-separator.yaml",
|
|
`del(select(di==0).spec.containers[0].securityContext) |
|
|
select(di==0).spec.securityContext.runAsRoot |= false`,
|
|
"hybrids/tc-05-01-expected.yaml",
|
|
},
|
|
}
|
|
|
|
return indentationTestCases
|
|
}
|
|
|
|
func TestApplyFixKeepsFormatting(t *testing.T) {
|
|
testCases := getTestCases()
|
|
getTestDataPath := func(filename string) string {
|
|
currentFile := "testdata/" + filename
|
|
return filepath.Join(testutils.CurrentDir(), currentFile)
|
|
}
|
|
|
|
for _, tc := range testCases {
|
|
t.Run(tc.inputFile, func(t *testing.T) {
|
|
inputFilename := getTestDataPath(tc.inputFile)
|
|
input, err := os.ReadFile(inputFilename)
|
|
if err != nil {
|
|
t.Fatalf(`Unable to open file %s due to: %v`, inputFilename, err)
|
|
}
|
|
expectedFilename := getTestDataPath(tc.expectedFile)
|
|
wantRaw, err := os.ReadFile(expectedFilename)
|
|
if err != nil {
|
|
t.Fatalf(`Unable to open file %s due to: %v`, expectedFilename, err)
|
|
}
|
|
want := string(wantRaw)
|
|
expression := tc.yamlExpression
|
|
|
|
fileAsString := string(input)
|
|
got, _ := ApplyFixToContent(context.TODO(), fileAsString, expression)
|
|
|
|
assert.Equalf(
|
|
t, want, got,
|
|
"Contents of the fixed file don't match the expectation.\n"+
|
|
"Input file: %s\n\n"+
|
|
"Got: <%s>\n\n"+
|
|
"Want: <%s>",
|
|
tc.inputFile, got, want,
|
|
)
|
|
},
|
|
)
|
|
|
|
}
|
|
}
|
|
|
|
func Test_fixPathToValidYamlExpression(t *testing.T) {
|
|
type args struct {
|
|
fixPath string
|
|
value string
|
|
documentIndexInYaml int
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "fix path with boolean value",
|
|
args: args{
|
|
fixPath: "spec.template.spec.containers[0].securityContext.privileged",
|
|
value: "true",
|
|
documentIndexInYaml: 2,
|
|
},
|
|
want: "select(di==2).spec.template.spec.containers[0].securityContext.privileged |= true",
|
|
},
|
|
{
|
|
name: "fix path with string value",
|
|
args: args{
|
|
fixPath: "metadata.namespace",
|
|
value: "YOUR_NAMESPACE",
|
|
documentIndexInYaml: 0,
|
|
},
|
|
want: "select(di==0).metadata.namespace |= \"YOUR_NAMESPACE\"",
|
|
},
|
|
{
|
|
name: "fix path with number",
|
|
args: args{
|
|
fixPath: "xxx.yyy",
|
|
value: "123",
|
|
documentIndexInYaml: 0,
|
|
},
|
|
want: "select(di==0).xxx.yyy |= 123",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := FixPathToValidYamlExpression(tt.args.fixPath, tt.args.value, tt.args.documentIndexInYaml); got != tt.want {
|
|
t.Errorf("fixPathToValidYamlExpression() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestJoinStrings(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
args []string
|
|
want string
|
|
}{
|
|
{
|
|
name: "nil array",
|
|
args: nil,
|
|
want: "",
|
|
},
|
|
{
|
|
name: "empty array",
|
|
args: []string{},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "single element",
|
|
args: []string{"a"},
|
|
want: "a",
|
|
},
|
|
{
|
|
name: "two elements",
|
|
args: []string{"a", "b"},
|
|
want: "ab",
|
|
},
|
|
{
|
|
name: "three elements",
|
|
args: []string{"a", "b", "c"},
|
|
want: "abc",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := joinStrings(tt.args...); got != tt.want {
|
|
t.Errorf("joinStrings() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetFileString(t *testing.T) {
|
|
type args struct {
|
|
filePath string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
wantErr bool
|
|
}{
|
|
{
|
|
name: "file not found",
|
|
args: args{
|
|
filePath: "notfound.yaml",
|
|
},
|
|
want: "",
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "file found",
|
|
args: args{
|
|
filePath: filepath.Join("testdata", "inserts", "tc-01-00-input-mapping-insert-mapping.yaml"),
|
|
},
|
|
want: `# Fix to Apply:
|
|
# "select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false"
|
|
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_1
|
|
|
|
spec:
|
|
containers:
|
|
- name: nginx_container
|
|
image: nginx
|
|
`,
|
|
wantErr: false,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
|
|
got, err := GetFileString(tt.args.filePath)
|
|
if (err != nil) != tt.wantErr {
|
|
t.Errorf("getFileString() error = %v, wantErr %v", err, tt.wantErr)
|
|
return
|
|
}
|
|
if got != tt.want && !tt.wantErr {
|
|
t.Errorf("getFileString() got = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDetermineNewlineSeparator(t *testing.T) {
|
|
type args struct {
|
|
fileString string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
args: args{
|
|
fileString: "",
|
|
},
|
|
want: "\n",
|
|
},
|
|
{
|
|
name: "windows newline",
|
|
args: args{
|
|
fileString: "a\r\nb\r\nc\r\n",
|
|
},
|
|
want: "\r\n",
|
|
},
|
|
{
|
|
name: "linux newline",
|
|
args: args{
|
|
fileString: "a\nb\nc\n",
|
|
},
|
|
want: "\n",
|
|
},
|
|
{
|
|
name: "oldmac newline",
|
|
args: args{
|
|
fileString: "a\rb\rc\r",
|
|
},
|
|
want: "\n",
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := determineNewlineSeparator(tt.args.fileString); got != tt.want {
|
|
t.Errorf("determineNewlineSeparator() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSanitizeYaml(t *testing.T) {
|
|
type args struct {
|
|
fileString string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "empty yaml",
|
|
args: args{
|
|
fileString: "",
|
|
},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "empty yaml with two characters",
|
|
args: args{
|
|
fileString: "##",
|
|
},
|
|
want: "##",
|
|
},
|
|
{
|
|
name: "yaml/v3",
|
|
args: args{
|
|
fileString: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_1
|
|
`,
|
|
},
|
|
want: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_1
|
|
`,
|
|
},
|
|
{
|
|
name: "yaml/v2",
|
|
args: args{
|
|
fileString: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_1
|
|
---
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_2
|
|
`,
|
|
},
|
|
want: `apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_1
|
|
---
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_2
|
|
`,
|
|
},
|
|
{
|
|
name: "yaml/v1",
|
|
args: args{
|
|
fileString: `---
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_1
|
|
`,
|
|
},
|
|
want: `# ---
|
|
apiVersion: v1
|
|
kind: Pod
|
|
metadata:
|
|
name: insert_to_mapping_node_1
|
|
`,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := sanitizeYaml(tt.args.fileString); got != tt.want {
|
|
t.Errorf("sanitizeYaml() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestReduceYamlExpressions(t *testing.T) {
|
|
type args struct {
|
|
yamlExpressions []string
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "empty",
|
|
args: args{
|
|
yamlExpressions: []string{},
|
|
},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "one expression",
|
|
args: args{
|
|
yamlExpressions: []string{
|
|
"select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false",
|
|
},
|
|
},
|
|
want: "select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false",
|
|
},
|
|
{
|
|
name: "two expressions",
|
|
args: args{
|
|
yamlExpressions: []string{
|
|
"select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false",
|
|
"select(di==0).spec.containers[0].securityContext.capabilities.drop += [\"NET_RAW\"]",
|
|
},
|
|
},
|
|
want: "select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false | select(di==0).spec.containers[0].securityContext.capabilities.drop += [\"NET_RAW\"]",
|
|
},
|
|
{
|
|
name: "Duplicate expressions",
|
|
args: args{
|
|
yamlExpressions: []string{
|
|
"select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false",
|
|
"select(di==0).spec.containers[0].securityContext.capabilities.drop += [\"NET_RAW\"]",
|
|
"select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false",
|
|
},
|
|
},
|
|
want: "select(di==0).spec.containers[0].securityContext.allowPrivilegeEscalation |= false | select(di==0).spec.containers[0].securityContext.capabilities.drop += [\"NET_RAW\"]",
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
resource := &ResourceFixInfo{}
|
|
resource.YamlExpressions = make(map[string]armotypes.FixPath)
|
|
|
|
for _, yamlExpression := range tt.args.yamlExpressions {
|
|
resource.YamlExpressions[yamlExpression] = armotypes.FixPath{}
|
|
}
|
|
got := reduceYamlExpressions(resource)
|
|
assert.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestGetLocalPath(t *testing.T) {
|
|
type args struct {
|
|
report *reporthandlingv2.PostureReport
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
want string
|
|
}{
|
|
{
|
|
name: "empty report",
|
|
args: args{
|
|
report: &reporthandlingv2.PostureReport{},
|
|
},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "No scan metadata",
|
|
args: args{
|
|
report: &reporthandlingv2.PostureReport{
|
|
Metadata: reporthandlingv2.Metadata{
|
|
ScanMetadata: reporthandlingv2.ScanMetadata{},
|
|
},
|
|
},
|
|
},
|
|
want: "",
|
|
},
|
|
{
|
|
name: "Scan target GitLocal",
|
|
args: args{
|
|
report: &reporthandlingv2.PostureReport{
|
|
Metadata: reporthandlingv2.Metadata{
|
|
ScanMetadata: reporthandlingv2.ScanMetadata{
|
|
ScanningTarget: reporthandlingv2.ScanningTarget(3),
|
|
},
|
|
ContextMetadata: reporthandlingv2.ContextMetadata{
|
|
RepoContextMetadata: &reporthandlingv2.RepoContextMetadata{
|
|
LocalRootPath: os.TempDir(),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: os.TempDir(),
|
|
},
|
|
{
|
|
name: "Scan target Directory",
|
|
args: args{
|
|
report: &reporthandlingv2.PostureReport{
|
|
Metadata: reporthandlingv2.Metadata{
|
|
ScanMetadata: reporthandlingv2.ScanMetadata{
|
|
ScanningTarget: reporthandlingv2.ScanningTarget(2),
|
|
},
|
|
ContextMetadata: reporthandlingv2.ContextMetadata{
|
|
DirectoryContextMetadata: &reporthandlingv2.DirectoryContextMetadata{
|
|
BasePath: os.TempDir(),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "Scan target File",
|
|
args: args{
|
|
report: &reporthandlingv2.PostureReport{
|
|
Metadata: reporthandlingv2.Metadata{
|
|
ScanMetadata: reporthandlingv2.ScanMetadata{
|
|
ScanningTarget: reporthandlingv2.ScanningTarget(1),
|
|
},
|
|
ContextMetadata: reporthandlingv2.ContextMetadata{
|
|
FileContextMetadata: &reporthandlingv2.FileContextMetadata{
|
|
FilePath: filepath.Join(os.TempDir(), "target.yaml"),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
want: os.TempDir(),
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
if got := getLocalPath(tt.args.report); got != tt.want {
|
|
t.Errorf("getLocalPath() = %v, want %v", got, tt.want)
|
|
}
|
|
})
|
|
}
|
|
}
|