// Copyright 2017 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/ // // Unless required by applicable law or agreed to in writing, software // distributed under the License 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 ssmdocresource import ( "fmt" "os" "path/filepath" "strings" "testing" "github.com/aws/amazon-ssm-agent/agent/appconfig" filemock "github.com/aws/amazon-ssm-agent/agent/fileutil/filemanager/mock" "github.com/aws/amazon-ssm-agent/agent/log" "github.com/aws/amazon-ssm-agent/agent/mocks/context" "github.com/aws/aws-sdk-go/service/ssm" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" ) var contextMock = context.NewMockDefault() var logMock = contextMock.Log() func TestSSMDocResource_ValidateLocationInfo(t *testing.T) { locationInfo := `{ "name": "AWS-ExecuteCommand" }` ssmDocInfo, err := parseSourceInfo(locationInfo) ssmresource := &SSMDocResource{ context: contextMock, Info: ssmDocInfo, } _, err = ssmresource.ValidateLocationInfo() assert.NoError(t, err) } func TestSSMDocResource_FullARNNameInput(t *testing.T) { depMock := new(ssmDocDepMock) fileMock := filemock.FileSystemMock{} locationInfo := `{ "name": "arn:aws:ssm:us-east-1:1234567890:document/mySharedDocument" }` content := "content" docOutput := ssm.GetDocumentOutput{ Content: &content, } ssmDocInfo, err := parseSourceInfo(locationInfo) ssmresource := &SSMDocResource{ context: contextMock, Info: ssmDocInfo, } dir := "destination" depMock.On("GetDocument", logMock, "arn:aws:ssm:us-east-1:1234567890:document/mySharedDocument", "").Return(&docOutput, nil) fileMock.On("Exists", "destination").Return(true) fileMock.On("IsDirectory", "destination").Return(true) fileMock.On("MakeDirs", dir).Return(nil) fileMock.On("WriteFile", filepath.Join(dir, "mySharedDocument.json"), content).Return(nil) ssmresource.ssmdocdep = depMock err, result := ssmresource.DownloadRemoteResource(&fileMock, "destination") assert.NoError(t, err) depMock.AssertExpectations(t) fileMock.AssertExpectations(t) assert.NotNil(t, result) assert.Equal(t, 1, len(result.Files)) assert.Equal(t, filepath.Join(dir, "mySharedDocument.json"), result.Files[0]) } func TestSSMDocResource_FullARNNameInputWithVersion(t *testing.T) { depMock := new(ssmDocDepMock) fileMock := filemock.FileSystemMock{} locationInfo := `{ "name": "arn:aws:ssm:us-east-1:1234567890:document/mySharedDocument:10" }` content := "content" docOutput := ssm.GetDocumentOutput{ Content: &content, } ssmDocInfo, err := parseSourceInfo(locationInfo) ssmresource := &SSMDocResource{ context: contextMock, Info: ssmDocInfo, } dir := "destination" depMock.On("GetDocument", logMock, "arn:aws:ssm:us-east-1:1234567890:document/mySharedDocument", "10").Return(&docOutput, nil) fileMock.On("Exists", "destination").Return(true) fileMock.On("IsDirectory", "destination").Return(true) fileMock.On("MakeDirs", dir).Return(nil) fileMock.On("WriteFile", filepath.Join(dir, "mySharedDocument.json"), content).Return(nil) ssmresource.ssmdocdep = depMock err, result := ssmresource.DownloadRemoteResource(&fileMock, "destination") assert.NoError(t, err) depMock.AssertExpectations(t) fileMock.AssertExpectations(t) assert.NotNil(t, result) assert.Equal(t, 1, len(result.Files)) assert.Equal(t, filepath.Join(dir, "mySharedDocument.json"), result.Files[0]) } func TestSSMDocResource_ValidateLocationInfoNoName(t *testing.T) { locationInfo := `{ "name": "" }` ssmDocInfo, err := parseSourceInfo(locationInfo) ssmresource := &SSMDocResource{ context: contextMock, Info: ssmDocInfo, } _, err = ssmresource.ValidateLocationInfo() assert.Error(t, err) assert.Equal(t, "SSM Document name in SourceType must be specified", err.Error()) } func TestSSMDocResource_Download(t *testing.T) { depMock := new(ssmDocDepMock) fileMock := filemock.FileSystemMock{} locationInfo := `{ "name": "AWS-ExecuteCommand:10" }` content := "content" docOutput := ssm.GetDocumentOutput{ Content: &content, } ssmDocInfo, err := parseSourceInfo(locationInfo) ssmresource := &SSMDocResource{ context: contextMock, Info: ssmDocInfo, } dir := "destination" depMock.On("GetDocument", logMock, "AWS-ExecuteCommand", "10").Return(&docOutput, nil) fileMock.On("Exists", "destination").Return(true) fileMock.On("IsDirectory", "destination").Return(true) fileMock.On("MakeDirs", dir).Return(nil) fileMock.On("WriteFile", filepath.Join(dir, "AWS-ExecuteCommand.json"), content).Return(nil) ssmresource.ssmdocdep = depMock err, result := ssmresource.DownloadRemoteResource(&fileMock, "destination") assert.NoError(t, err) depMock.AssertExpectations(t) fileMock.AssertExpectations(t) assert.NotNil(t, result) assert.Equal(t, 1, len(result.Files)) assert.Equal(t, filepath.Join(dir, "AWS-ExecuteCommand.json"), result.Files[0]) } func TestSSMDocResource_DownloadNoDestination(t *testing.T) { depMock := new(ssmDocDepMock) fileMock := filemock.FileSystemMock{} locationInfo := `{ "name": "AWS-ExecuteCommand:10" }` content := "content" docOutput := ssm.GetDocumentOutput{ Content: &content, } ssmDocInfo, err := parseSourceInfo(locationInfo) ssmresource := &SSMDocResource{ context: contextMock, Info: ssmDocInfo, } dir := appconfig.DownloadRoot depMock.On("GetDocument", logMock, "AWS-ExecuteCommand", "10").Return(&docOutput, nil) fileMock.On("Exists", appconfig.DownloadRoot).Return(true) fileMock.On("IsDirectory", appconfig.DownloadRoot).Return(true) fileMock.On("MakeDirs", strings.TrimSuffix(dir, string(os.PathSeparator))).Return(nil) fileMock.On("WriteFile", filepath.Join(dir, "AWS-ExecuteCommand.json"), content).Return(fmt.Errorf("Error")) ssmresource.ssmdocdep = depMock err, result := ssmresource.DownloadRemoteResource(&fileMock, "") assert.Error(t, err, "Error") depMock.AssertExpectations(t) fileMock.AssertExpectations(t) assert.Nil(t, result) } func TestSSMDocResource_DownloadToOtherName(t *testing.T) { depMock := new(ssmDocDepMock) fileMock := filemock.FileSystemMock{} locationInfo := `{ "name": "AWS-ExecuteCommand:10" }` content := "content" docOutput := ssm.GetDocumentOutput{ Content: &content, } ssmDocInfo, err := parseSourceInfo(locationInfo) ssmresource := &SSMDocResource{ context: contextMock, Info: ssmDocInfo, } depMock.On("GetDocument", logMock, "AWS-ExecuteCommand", "10").Return(&docOutput, nil) fileMock.On("Exists", "destination").Return(false) fileMock.On("MakeDirs", ".").Return(nil) fileMock.On("WriteFile", "destination", content).Return(nil) ssmresource.ssmdocdep = depMock err, result := ssmresource.DownloadRemoteResource(&fileMock, "destination") assert.NoError(t, err) depMock.AssertExpectations(t) fileMock.AssertExpectations(t) assert.NotNil(t, result) assert.Equal(t, 1, len(result.Files)) assert.Equal(t, "destination", result.Files[0]) } type ssmDocDepMock struct { mock.Mock } func (s *ssmDocDepMock) GetDocument(log log.T, docName string, docVersion string) (response *ssm.GetDocumentOutput, err error) { args := s.Called(log, docName, docVersion) return args.Get(0).(*ssm.GetDocumentOutput), args.Error(1) }