// 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 app represents the core SSM agent object package app import ( "fmt" "testing" "time" "github.com/aws/amazon-ssm-agent/agent/contracts" "github.com/aws/amazon-ssm-agent/agent/mocks/log" contextmocks "github.com/aws/amazon-ssm-agent/core/app/context/mocks" refresherMocks "github.com/aws/amazon-ssm-agent/core/app/credentialrefresher/mocks" selfupdatemocks "github.com/aws/amazon-ssm-agent/core/app/selfupdate/mocks" containermocks "github.com/aws/amazon-ssm-agent/core/workerprovider/longrunningprovider/mocks" "github.com/stretchr/testify/suite" ) // AgentTestSuite define agent test suite, and absorb the built-in basic suite // functionality from testify - including a T() method which // returns the current testing context type AgentTestSuite struct { suite.Suite coreAgent CoreAgent context *contextmocks.ICoreAgentContext mockContainer *containermocks.IContainer mockselfupdate *selfupdatemocks.ISelfUpdate mockCredentialRefresher *refresherMocks.ICredentialRefresher mockIdentity *MockIdentity mockInnerIdentity *MockInnerIdentityRegistrar } // SetupTest makes sure that all the components referenced in the test case are initialized // before each test func (suite *AgentTestSuite) SetupTest() { suite.mockContainer = &containermocks.IContainer{} suite.context = &contextmocks.ICoreAgentContext{} suite.mockselfupdate = &selfupdatemocks.ISelfUpdate{} suite.mockCredentialRefresher = &refresherMocks.ICredentialRefresher{} suite.mockIdentity = &MockIdentity{} suite.mockInnerIdentity = &MockInnerIdentityRegistrar{} suite.coreAgent = &SSMCoreAgent{ context: suite.context, container: suite.mockContainer, selfupdate: suite.mockselfupdate, credsRefresher: suite.mockCredentialRefresher, } mockLog := log.NewMockLog() suite.context.On("Log").Return(mockLog) } // Execute the test suite func TestAgentTestSuite(t *testing.T) { suite.Run(t, new(AgentTestSuite)) } // TestAgentStart tests that agent starts the core manager when it starts func (suite *AgentTestSuite) TestAgentStart() { credentialsReadyChan := make(chan struct{}, 1) suite.mockContainer.On("Monitor").Return() suite.mockContainer.On("Start").Return([]error{}) suite.mockselfupdate.On("Start").Return() suite.mockCredentialRefresher.On("Start").Return(nil) suite.context.On("Identity").Return(suite.mockIdentity) suite.mockIdentity.On("GetInner").Return(suite.mockInnerIdentity) suite.mockInnerIdentity.On("Register").Return() credentialsReadyChan <- struct{}{} suite.mockCredentialRefresher.On("GetCredentialsReadyChan").Return(credentialsReadyChan) statusComm := &contracts.StatusComm{ TerminationChan: make(chan struct{}, 1), DoneChan: make(chan struct{}, 1), } suite.coreAgent.Start(statusComm) time.Sleep(10 * time.Millisecond) suite.Equal(len(statusComm.DoneChan), 1) suite.NotNil(<-statusComm.DoneChan) time.Sleep(10 * time.Millisecond) suite.Equal(len(statusComm.DoneChan), 0) suite.mockContainer.AssertExpectations(suite.T()) } func (suite *AgentTestSuite) TestAgentStart_WithStartWorkerError() { credentialsReadyChan := make(chan struct{}, 1) suite.mockContainer.On("Monitor").Return() suite.mockContainer.On("Start").Return( []error{fmt.Errorf("test1"), fmt.Errorf("test2")}) suite.mockselfupdate.On("Start").Return() suite.mockCredentialRefresher.On("Start").Return(nil) suite.context.On("Identity").Return(suite.mockIdentity) suite.mockIdentity.On("GetInner").Return(suite.mockInnerIdentity) suite.mockInnerIdentity.On("Register").Return() credentialsReadyChan <- struct{}{} suite.mockCredentialRefresher.On("GetCredentialsReadyChan").Return(credentialsReadyChan) statusComm := &contracts.StatusComm{ TerminationChan: make(chan struct{}, 1), DoneChan: make(chan struct{}, 1), } suite.coreAgent.Start(statusComm) time.Sleep(10 * time.Millisecond) suite.Equal(len(statusComm.DoneChan), 1) suite.NotNil(<-statusComm.DoneChan) time.Sleep(10 * time.Millisecond) suite.Equal(len(statusComm.DoneChan), 0) suite.mockContainer.AssertExpectations(suite.T()) } func (suite *AgentTestSuite) TestAgentStart_WithCredentialRefresherError() { suite.mockContainer.On("Monitor").Return() suite.mockContainer.On("Start").Return([]error{}) suite.mockselfupdate.On("Start").Return() suite.mockCredentialRefresher.On("Start").Return(fmt.Errorf("SomeStartError")) suite.context.On("Identity").Return(suite.mockIdentity) suite.mockIdentity.On("GetInner").Return(suite.mockInnerIdentity) suite.mockInnerIdentity.On("Register").Return() statusComm := &contracts.StatusComm{ TerminationChan: make(chan struct{}, 1), DoneChan: make(chan struct{}, 1), } suite.coreAgent.Start(statusComm) time.Sleep(10 * time.Millisecond) suite.Equal(len(statusComm.DoneChan), 0) suite.mockCredentialRefresher.AssertExpectations(suite.T()) } func (suite *AgentTestSuite) TestAgentStart_StopsModules_WhenSignalledToTerminate() { credentialsReadyChan := make(chan struct{}, 1) suite.mockCredentialRefresher.On("Start").Return(nil) suite.context.On("Identity").Return(suite.mockIdentity) suite.mockIdentity.On("GetInner").Return(suite.mockInnerIdentity) suite.mockInnerIdentity.On("Register").Return() suite.mockCredentialRefresher.On("GetCredentialsReadyChan").Return(credentialsReadyChan) statusComm := &contracts.StatusComm{ TerminationChan: make(chan struct{}, 1), DoneChan: make(chan struct{}, 1), } go suite.coreAgent.Start(statusComm) statusComm.TerminationChan <- struct{}{} time.Sleep(10 * time.Millisecond) suite.Equal(len(statusComm.DoneChan), 1) suite.NotNil(<-statusComm.DoneChan) suite.mockCredentialRefresher.AssertExpectations(suite.T()) }