// 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 telemetry is used to schedule and send the audit logs to MGS package telemetry import ( "fmt" "os" "path/filepath" "strconv" "testing" "time" "github.com/aws/amazon-ssm-agent/agent/log/logger" "github.com/aws/amazon-ssm-agent/agent/mocks/context" commMock "github.com/aws/amazon-ssm-agent/agent/session/communicator/mocks" cloudWatchMock "github.com/aws/amazon-ssm-agent/agent/session/telemetry/metrics/mocks" "github.com/aws/amazon-ssm-agent/core/workerprovider/longrunningprovider/datastore/filesystem" "github.com/aws/aws-sdk-go/service/cloudwatch" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/mock" "github.com/stretchr/testify/suite" ) type TelemetrySchedulerTestSuite struct { suite.Suite EventLog *logger.EventLog TelemetryScheduler *AuditLogTelemetry FileSystem filesystem.IFileSystem } // Execute the test suite func TestTelemetrySchedulerTestSuite(t *testing.T) { suite.Run(t, new(TelemetrySchedulerTestSuite)) } // Setup func (suite *TelemetrySchedulerTestSuite) SetupTest() { contextMock := context.NewMockDefault() mockWsChannel := &commMock.IWebSocketChannel{} mockWsChannel.On("SendMessage", mock.Anything, mock.Anything, mock.Anything).Return(nil) path, _ := os.Getwd() suite.EventLog = logger.GetEventLog(path, "testEventLog") cwMock := &cloudWatchMock.ICloudWatchService{} cwMock.On("GenerateUpdateMetrics", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.MetricDatum{}) cwMock.On("GenerateBasicTelemetryMetrics", mock.Anything, mock.Anything, mock.Anything).Return(&cloudwatch.MetricDatum{}) cwMock.On("PutMetrics", mock.Anything).Return(nil) cwMock.On("IsCloudWatchEnabled").Return(true) suite.TelemetryScheduler = GetAuditLogTelemetryInstance(contextMock, mockWsChannel) suite.TelemetryScheduler.eventLogDelayFactor = 1 suite.TelemetryScheduler.eventLogDelayBase = 0 suite.TelemetryScheduler.isMGSTelemetryTransportEnable = true suite.TelemetryScheduler.mgsDelay = 1 suite.TelemetryScheduler.cloudWatchService = cwMock suite.FileSystem = suite.EventLog.GetFileSystem() } // Test case for checking event counts in the file func (suite *TelemetrySchedulerTestSuite) TestWrite_SendEventToMGS() { timeStamp := "15:04:05" nextTimeStamp := "23:00:00" nextFilePath := suite.EventLog.GetAuditFileName() + "-2020-03-01" filePath := filepath.Join(suite.EventLog.GetAuditFilePath(), nextFilePath) defer os.Remove(filePath) fileInput1 := "SchemaVersion=1\nEventType1 Test 2.0.0.0 " + timeStamp + "\nEventType1 Test 2.0.0.0 " + nextTimeStamp + "\n" suite.FileSystem.AppendToFile(filePath, fileInput1, 0600) suite.TelemetryScheduler.SendAuditMessage() time.Sleep(1500 * time.Millisecond) byteMarker := fmt.Sprintf("%0"+strconv.Itoa(logger.BytePatternLen)+"d", len(fileInput1)) output := fileInput1 + logger.AuditSentSuccessFooter + byteMarker fileContentBytes, err := suite.FileSystem.ReadFile(filePath) assert.Equal(suite.T(), string(fileContentBytes), output) assert.Nil(suite.T(), err) } // Test case for checking the send event to MGS with "audit sent" file func (suite *TelemetrySchedulerTestSuite) TestWrite_SendEventToMGSWithAuditSuccessFile() { timeStamp := "22:59:59" nextTimeStamp := "23:00:00" file1 := filepath.Join(suite.EventLog.GetAuditFilePath(), suite.EventLog.GetAuditFileName()+"-2020-03-01") file2 := filepath.Join(suite.EventLog.GetAuditFilePath(), suite.EventLog.GetAuditFileName()+"-2020-03-02") file3 := filepath.Join(suite.EventLog.GetAuditFilePath(), suite.EventLog.GetTodayAuditFileName()) defer func() { os.Remove(file1) os.Remove(file2) os.Remove(file3) }() fileInput1 := "SchemaVersion=1\nagent_telemetry amazon-ssm-agent.start 2.0.0.0 " + timeStamp + "\nagent_telemetry ssm-agent-worker.start 2.0.0.0 " + timeStamp + "\n" fileInput2 := "SchemaVersion=1\nagent_telemetry amazon-ssm-agent.start 2.0.0.0 " + timeStamp + "\nagent_telemetry ssm-agent-worker.start 2.0.0.1 " + nextTimeStamp + "\n" fileInput3 := "SchemaVersion=1\nagent_telemetry amazon-ssm-agent.start 2.0.0.0 " + timeStamp byteMarker := fmt.Sprintf("%0"+strconv.Itoa(logger.BytePatternLen)+"d", len(fileInput1)) suite.FileSystem.AppendToFile(file1, fileInput1+logger.AuditSentSuccessFooter+byteMarker, 0600) suite.FileSystem.AppendToFile(file2, fileInput2, 0600) suite.FileSystem.AppendToFile(file3, fileInput3, 0600) suite.TelemetryScheduler.SendAuditMessage() time.Sleep(2 * time.Second) firstFileOutput := fileInput1 + logger.AuditSentSuccessFooter + byteMarker byteMarker = fmt.Sprintf("%0"+strconv.Itoa(logger.BytePatternLen)+"d", len(fileInput2)) SecondFileOutput := fileInput2 + logger.AuditSentSuccessFooter + byteMarker thirdFileOutput := fileInput3 fileContentBytes, err := suite.FileSystem.ReadFile(file1) assert.Equal(suite.T(), string(fileContentBytes), firstFileOutput, "2020-03-01 audit file is not matching") assert.Nil(suite.T(), err) fileContentBytes, err = suite.FileSystem.ReadFile(file2) assert.Equal(suite.T(), string(fileContentBytes), SecondFileOutput, "2020-03-02 audit file is not matching") assert.Nil(suite.T(), err) fileContentBytes, err = suite.FileSystem.ReadFile(file3) assert.Contains(suite.T(), string(fileContentBytes), thirdFileOutput) assert.Nil(suite.T(), err) } // for update send event func (suite *TelemetrySchedulerTestSuite) TestWrite_SendUpdateEventToMGS() { timeStamp := "22:59:59" nextTimeStamp := "23:00:00" file1 := filepath.Join(suite.EventLog.GetAuditFilePath(), suite.EventLog.GetAuditFileName()+"-2020-03-01") file2 := filepath.Join(suite.EventLog.GetAuditFilePath(), suite.EventLog.GetAuditFileName()+"-2020-03-02") defer func() { os.Remove(file1) os.Remove(file2) }() file1Input := "SchemaVersion=1\nagent_telemetry amazon-ssm-agent.start 2.0.0.0 " + timeStamp + "\nagent_telemetry ssm-agent-worker.start 2.0.0.0 " + timeStamp + "\nagent_update_result UpdateError_2.3.2.2 2.0.3.2 " + nextTimeStamp + "\n" file2Input := "SchemaVersion=1\n" + "agent_telemetry amazon-ssm-agent.start 2.0.0.0 " + timeStamp + "\nagent_telemetry ssm-agent-worker.start 2.0.0.1 " + timeStamp + "\nagent_update_result UpdateError1-2.3.2.2 2.0.3.2 " + timeStamp + "\nagent_update_result UpdateError2-2.3.2.2 2.0.3.2 " + timeStamp + "\nagent_update_result UpdateError3-2.3.2.2 2.0.3.2 " + nextTimeStamp + "\n" byteMarker := fmt.Sprintf("%0"+strconv.Itoa(logger.BytePatternLen)+"d", len(file1Input)) suite.FileSystem.AppendToFile(file1, file1Input+logger.AuditSentSuccessFooter+byteMarker, 0600) suite.FileSystem.AppendToFile(file2, file2Input, 0600) suite.TelemetryScheduler.SendAuditMessage() time.Sleep(1500 * time.Millisecond) byteMarker = fmt.Sprintf("%0"+strconv.Itoa(logger.BytePatternLen)+"d", len(file1Input)) firstFileOutput := file1Input + logger.AuditSentSuccessFooter + byteMarker byteMarker = fmt.Sprintf("%0"+strconv.Itoa(logger.BytePatternLen)+"d", len(file2Input)) SecondFileOutput := file2Input + logger.AuditSentSuccessFooter + byteMarker fileContentBytes, err := suite.FileSystem.ReadFile(file1) assert.Equal(suite.T(), string(fileContentBytes), firstFileOutput, "2020-03-01 audit file is not matching") assert.Nil(suite.T(), err) fileContentBytes, err = suite.FileSystem.ReadFile(file2) assert.Equal(suite.T(), string(fileContentBytes), SecondFileOutput, "2020-03-02 audit file is not matching") assert.Nil(suite.T(), err) } // for event log with incorrect event for the message type func (suite *TelemetrySchedulerTestSuite) TestWrite_SendUpdateEventWithInvalidMessageTypes() { timeStamp := "22:59:59" nextTimeStamp := "23:00:00" file1 := filepath.Join(suite.EventLog.GetAuditFilePath(), suite.EventLog.GetAuditFileName()+"-2020-03-02") defer func() { os.Remove(file1) }() file1InValidInput := "SchemaVersion=1\n" + "agent_telemetry amazon-ssm-agent.start 2.0.0.0 " + timeStamp + "\n" + "agent_telemetry ssm-agent-worker.start 2.0.0.1 " + timeStamp + "\n" + "invalid_event_type dfsfsdfsdsdsdsdffdsfdds 2.0.3.2 " + timeStamp + "\nagent_update_result UpdateError2-2.3.2.2 2.0.3.2 " + timeStamp + "\nagent_update_result UpdateError3-2.3.2.2 2.0.3.2 " + nextTimeStamp + "\n" suite.FileSystem.AppendToFile(file1, file1InValidInput, 0600) suite.TelemetryScheduler.SendAuditMessage() time.Sleep(1500 * time.Millisecond) byteMarker := fmt.Sprintf("%0"+strconv.Itoa(logger.BytePatternLen)+"d", len(file1InValidInput)) firstFileOutput := file1InValidInput + logger.AuditSentSuccessFooter + byteMarker fileContentBytes, err := suite.FileSystem.ReadFile(file1) assert.Equal(suite.T(), string(fileContentBytes), firstFileOutput, "2020-03-02 audit file is not matching") assert.Nil(suite.T(), err) } // for event log with incorrect event for the message type func (suite *TelemetrySchedulerTestSuite) TestWrite_SendEventCountCheck() { file1 := filepath.Join(suite.EventLog.GetAuditFilePath(), suite.EventLog.GetAuditFileName()+"-2020-03-02") defer func() { os.Remove(file1) }() file1ValidInput := "SchemaVersion=1\n" + "\nagent_telemetry amazon-ssm-agent.start 9.5.0.0 04:38:04" + "\nagent_telemetry ssm-agent-worker.start 9.5.0.0 04:38:08" + "\nagent_update_result UpdateSucceeded-8.0.0.0 9.5.0.0 04:38:10" + "\nagent_telemetry ssm-agent-worker.start 9.5.0.0 04:38:14" + "\nagent_update_result UpdateSucceeded-8.0.0.0 9.5.0.0 04:38:15" + "\nagent_telemetry amazon-ssm-agent.start 9.5.0.0 05:23:10" + "\nagent_telemetry ssm-agent-worker.start 9.5.0.0 05:23:14" + "\n" lenVal := len(file1ValidInput) file1ValidInput += "agent_update_result UpdateSucceeded-8.0.0.0 9.5.0.0 05:23:16" + "\n" suite.FileSystem.AppendToFile(file1, file1ValidInput, 0600) suite.TelemetryScheduler.SendAuditMessage() time.Sleep(1500 * time.Millisecond) byteMarker := fmt.Sprintf("%0"+strconv.Itoa(logger.BytePatternLen)+"d", lenVal) firstFileOutput := file1ValidInput + logger.AuditSentSuccessFooter + byteMarker fileContentBytes, err := suite.FileSystem.ReadFile(file1) assert.Equal(suite.T(), string(fileContentBytes), firstFileOutput, "2020-03-02 audit file is not matching") assert.Nil(suite.T(), err) }