// Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"). You may not // use this file except in compliance with the License. A copy of the // License is located at // // http://aws.amazon.com/apache2.0/ // // or in the "license" file accompanying this file. This file is distributed // on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, // either express or implied. See the License for the specific language governing // permissions and limitations under the License. package fileutil import ( "fmt" "os" "path/filepath" "testing" "github.com/aws/amazon-ssm-agent/agent/mocks/log" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/suite" ) type FileUtilTestSuite struct { suite.Suite log *log.Mock fileutil *Fileutil } func (suite *FileUtilTestSuite) SetupTest() { suite.log = log.NewMockLog() suite.fileutil = NewFileUtil(suite.log) } func (suite *FileUtilTestSuite) TestLocalFileExist() { // file exists path := filepath.Join("testdata", "test.txt") isExist, err := suite.fileutil.LocalFileExist(path) if err != nil { suite.log.Errorf("error: %v", err) } assert.Nil(suite.T(), err) assert.Equal(suite.T(), true, isExist) // file does not exist path = filepath.Join("testdata", "blah") isExist, err = suite.fileutil.LocalFileExist(path) if err != nil { suite.log.Errorf("error: %v", err) } assert.Equal(suite.T(), false, isExist) } func (suite *FileUtilTestSuite) TestExists() { path := filepath.Join("testdata", "test.txt") isExist := suite.fileutil.Exists(path) assert.Equal(suite.T(), true, isExist) } func (suite *FileUtilTestSuite) TestReadAllText() { // valid file path := filepath.Join("testdata", "test.txt") expectContent := "This is a test file" content, err := suite.fileutil.ReadAllText(path) if err != nil { suite.log.Errorf("error: %v", err) } assert.Nil(suite.T(), err) assert.Equal(suite.T(), content, expectContent) // invalid file path = filepath.Join("testdata", "invalid.txt") content, err = suite.fileutil.ReadAllText(path) if err != nil { suite.log.Errorf("error: %v", err) } assert.Equal(suite.T(), content, "") } func (suite *FileUtilTestSuite) TestMakeDirs() { // No error test dir := "sampledir" err := suite.fileutil.MakeDirs(dir) assert.NoError(suite.T(), err, "expected no error") // error test suite.fileutil.fs = osFSStub{err: fmt.Errorf("someerror")} dir = "sampledir" err = suite.fileutil.MakeDirs(dir) assert.Error(suite.T(), err, "expected some error") } func (suite *FileUtilTestSuite) TestDeleteFile() { file := "samplefile" // No error test suite.fileutil.fs = osFSStub{} err := suite.fileutil.DeleteFile(file) assert.NoError(suite.T(), err, "expected no error") // error test suite.fileutil.fs = osFSStub{err: fmt.Errorf("someerror")} err = suite.fileutil.MakeDirs(file) assert.Error(suite.T(), err, "expected some error") } func (suite *FileUtilTestSuite) TestUnderDir() { // Remove one or more directory levels assert.True(suite.T(), suite.fileutil.isUnderDir(`~/foo/bar/../`, `~/foo`)) assert.True(suite.T(), suite.fileutil.isUnderDir(`~/foo/bar/..`, `~/foo`)) assert.False(suite.T(), suite.fileutil.isUnderDir(`~/foo/bar/../..`, `~/foo`)) // Remove one or more directory levels and add some levels assert.True(suite.T(), suite.fileutil.isUnderDir(`~/foo/bar/../../foo`, `~/foo`)) assert.False(suite.T(), suite.fileutil.isUnderDir(`~/foo/bar/../../bar`, `~/foo`)) assert.True(suite.T(), suite.fileutil.isUnderDir(`~/foo/bar/../../foo/bar`, `~/foo/bar`)) assert.False(suite.T(), suite.fileutil.isUnderDir(`~/foo/bar/../../bar`, `~/foo/bar`)) // Ensure partial hex and unicode encoded strings also work assert.True(suite.T(), suite.fileutil.isUnderDir("~\x2ffoo\x2fbar", `~/foo`)) assert.True(suite.T(), suite.fileutil.isUnderDir("~/foo/bar\x2f\x2e\x2e", `~/foo`)) assert.False(suite.T(), suite.fileutil.isUnderDir("~/foo/bar\x2f\x2e\x2e", `~/foo/bar`)) assert.False(suite.T(), suite.fileutil.isUnderDir("~/foo/bar\x2f\x2e\u002e", `~/foo/bar`)) // Ensure handling of trailing separators and substrings that are different directories works correctly assert.True(suite.T(), suite.fileutil.isUnderDir("/foo/bar/", "/foo/bar")) assert.True(suite.T(), suite.fileutil.isUnderDir("/foo/bar", "/foo/bar/")) assert.False(suite.T(), suite.fileutil.isUnderDir("/foo/barbaz", "/foo/bar")) // Assert behavior involving ~ (it is treated as a single directory level) assert.True(suite.T(), suite.fileutil.isUnderDir(`~/../foo`, `foo`)) assert.True(suite.T(), suite.fileutil.isUnderDir(`~/../../foo`, `../foo`)) } // Execute the test suite func TestFileUtilTestSuite(t *testing.T) { suite.Run(t, new(FileUtilTestSuite)) } type osFSStub struct { exists bool file *os.File fileInfo os.FileInfo err error } // TODO: optimize the test with Mock func (a osFSStub) IsNotExist(err error) bool { return a.exists } func (a osFSStub) MkdirAll(path string, perm os.FileMode) error { return a.err } func (a osFSStub) Open(name string) (*os.File, error) { return a.file, a.err } func (a osFSStub) Stat(name string) (os.FileInfo, error) { return a.fileInfo, a.err } func (a osFSStub) Remove(name string) error { return a.err } func (a osFSStub) Rename(oldpath string, newpath string) error { return a.err } func (a osFSStub) WriteFile(filename string, data []byte, perm os.FileMode) error { return a.err }