-
Notifications
You must be signed in to change notification settings - Fork 199
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
test(logging): add logging plugin integration test (#3218)
* test: add logging pluging integration test * test(logging): add logging integration tests * test(logging): add logging integ test * test(logging): add more test cases * chore(logging): clean up build configuration * test: fix integration test in command line * chore: update integration test configuration * test(logging): remove logging integration test from integration test suite * test integration on branch * fix integration test names * introduce delay in getting current user id * resolve issue with parallel integration tests running on multiple platforms * revert base integration workflow to include all integration tests
- Loading branch information
1 parent
0432e8e
commit 0a37e4a
Showing
18 changed files
with
1,770 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
name: Integration Tests | Logging | ||
on: | ||
workflow_dispatch: | ||
workflow_call: | ||
|
||
permissions: | ||
id-token: write | ||
contents: read | ||
|
||
jobs: | ||
logging-integration-test-iOS: | ||
runs-on: macos-12 | ||
environment: IntegrationTest | ||
steps: | ||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b | ||
with: | ||
persist-credentials: false | ||
|
||
- name: Make directory | ||
run: mkdir -p ~/.aws-amplify/amplify-ios/testconfiguration/ | ||
|
||
- name: Copy integration test resouces | ||
uses: ./.github/composite_actions/download_test_configuration | ||
with: | ||
resource_subfolder: logging | ||
aws_role_to_assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} | ||
aws_region: ${{ secrets.AWS_REGION }} | ||
aws_s3_bucket: ${{ secrets.AWS_S3_BUCKET_INTEG_V2 }} | ||
|
||
- name: Run Integration test | ||
uses: ./.github/composite_actions/run_xcodebuild_test | ||
with: | ||
project_path: ./AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginHostApp | ||
scheme: AWSCloudWatchLoggingPluginIntegrationTests | ||
|
||
logging-integration-test-tvOS: | ||
runs-on: macos-13 | ||
environment: IntegrationTest | ||
steps: | ||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b | ||
with: | ||
persist-credentials: false | ||
|
||
- name: Make directory | ||
run: mkdir -p ~/.aws-amplify/amplify-ios/testconfiguration/ | ||
|
||
- name: Copy integration test resouces | ||
uses: ./.github/composite_actions/download_test_configuration | ||
with: | ||
resource_subfolder: logging | ||
aws_role_to_assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} | ||
aws_region: ${{ secrets.AWS_REGION }} | ||
aws_s3_bucket: ${{ secrets.AWS_S3_BUCKET_INTEG_V2 }} | ||
|
||
- name: Run Integration test | ||
uses: ./.github/composite_actions/run_xcodebuild_test | ||
with: | ||
project_path: ./AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginHostApp | ||
scheme: AWSCloudWatchLoggingPluginIntegrationTests | ||
destination: platform=tvOS Simulator,name=Apple TV 4K (3rd generation),OS=latest | ||
sdk: appletvsimulator | ||
xcode_path: '/Applications/Xcode_14.3.app' | ||
|
||
logging-integration-test-watchOS: | ||
runs-on: macos-13 | ||
environment: IntegrationTest | ||
steps: | ||
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b | ||
with: | ||
persist-credentials: false | ||
|
||
- name: Make directory | ||
run: mkdir -p ~/.aws-amplify/amplify-ios/testconfiguration/ | ||
|
||
- name: Copy integration test resouces | ||
uses: ./.github/composite_actions/download_test_configuration | ||
with: | ||
resource_subfolder: logging | ||
aws_role_to_assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} | ||
aws_region: ${{ secrets.AWS_REGION }} | ||
aws_s3_bucket: ${{ secrets.AWS_S3_BUCKET_INTEG_V2 }} | ||
|
||
- name: Run Integration test | ||
uses: ./.github/composite_actions/run_xcodebuild_test | ||
with: | ||
project_path: ./AmplifyPlugins/Logging/Tests/AWSCloudWatchLoggingPluginHostApp | ||
scheme: AWSCloudWatchLoggingPluginIntegrationTestsWatch | ||
destination: platform=watchOS Simulator,name=Apple Watch Series 8 (45mm),OS=latest | ||
sdk: watchsimulator | ||
xcode_path: '/Applications/Xcode_14.3.app' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
23 changes: 23 additions & 0 deletions
23
...gPluginHostApp/AWSCloudWatchLoggingPluginIntegrationTests/AWSCloudWatchClientHelper.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import Foundation | ||
import AWSCloudWatchLogs | ||
|
||
class AWSCloudWatchClientHelper { | ||
static func getFilterLogEventCount(client: CloudWatchLogsClientProtocol?, filterPattern: String?, startTime: Date?, endTime: Date?, logGroupName: String?) async throws -> [CloudWatchLogsClientTypes.FilteredLogEvent]? { | ||
let filterEventInput = FilterLogEventsInput(endTime: endTime?.epochMilliseconds, filterPattern: filterPattern, logGroupName: logGroupName, startTime: startTime?.epochMilliseconds) | ||
let response = try await client?.filterLogEvents(input: filterEventInput) | ||
return response?.events | ||
} | ||
} | ||
|
||
extension Date { | ||
var epochMilliseconds: Int { | ||
Int(self.timeIntervalSince1970 * 1_000) | ||
} | ||
} |
254 changes: 254 additions & 0 deletions
254
...SCloudWatchLoggingPluginIntegrationTests/AWSCloudWatchLoggingPluginIntegrationTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,254 @@ | ||
// | ||
// Copyright Amazon.com Inc. or its affiliates. | ||
// All Rights Reserved. | ||
// | ||
// SPDX-License-Identifier: Apache-2.0 | ||
// | ||
|
||
import XCTest | ||
import AWSCloudWatchLogs | ||
@testable import Amplify | ||
@testable import AWSCognitoAuthPlugin | ||
@testable import AWSCloudWatchLoggingPlugin | ||
|
||
class AWSCloudWatchLoggingPluginIntergrationTests: XCTestCase { | ||
let amplifyConfigurationFile = "testconfiguration/AWSCloudWatchLoggingPluginIntegrationTests-amplifyconfiguration" | ||
let amplifyConfigurationLoggingFile = "testconfiguration/AWSCloudWatchLoggingPluginIntegrationTests-amplifyconfiguration_logging" | ||
var loggingConfiguration: AWSCloudWatchLoggingPluginConfiguration? | ||
|
||
override func setUp() async throws { | ||
continueAfterFailure = false | ||
do { | ||
try Amplify.add(plugin: AWSCognitoAuthPlugin()) | ||
let loggingConfigurationFile = try TestConfigHelper.retrieveLoggingConfiguration(forResource: amplifyConfigurationLoggingFile) | ||
loggingConfiguration = try AWSCloudWatchLoggingPluginConfiguration.loadConfiguration(from: loggingConfigurationFile) | ||
let loggingPlugin = AWSCloudWatchLoggingPlugin(loggingPluginConfiguration: loggingConfiguration) | ||
try Amplify.add(plugin: loggingPlugin) | ||
let configuration = try TestConfigHelper.retrieveAmplifyConfiguration(forResource: amplifyConfigurationFile) | ||
try Amplify.configure(configuration) | ||
try await Task.sleep(seconds: 5) | ||
} catch { | ||
XCTFail("Failed to initialize and configure Amplify: \(error)") | ||
} | ||
XCTAssertNotNil(Amplify.Auth.plugin) | ||
XCTAssertTrue(Amplify.Auth.isConfigured) | ||
} | ||
|
||
override func tearDown() async throws { | ||
await Amplify.reset() | ||
} | ||
|
||
/// - Given: a AWS CloudWatch Logging plugin | ||
/// - When: the escape hatch is requested | ||
/// - Then: the AWS CloudWatch client is returned | ||
func testGetEscapeHatch() throws { | ||
let plugin = try Amplify.Logging.getPlugin(for: "awsCloudWatchLoggingPlugin") | ||
guard let loggingPlugin = plugin as? AWSCloudWatchLoggingPlugin else { | ||
XCTFail("Could not get plugin of type AWSCloudWatchLoggingPlugin") | ||
return | ||
} | ||
let cloudWatchClient = loggingPlugin.getEscapeHatch() | ||
XCTAssertNotNil(cloudWatchClient) | ||
} | ||
|
||
/// - Given: a AWS CloudWatch Logging plugin | ||
/// - When: an error log message is logged and flushed | ||
/// - Then: the error log message is logged and sent to AWS CloudWatch | ||
func testFlushLogWithErrorMessage() async throws { | ||
let category = "Analytics" | ||
let namespace = UUID().uuidString | ||
let message = "this is an error message in the integration test \(Date().epochMilliseconds)" | ||
let logger = Amplify.Logging.logger(forCategory: category, forNamespace: namespace) | ||
logger.error(message) | ||
let plugin = try Amplify.Logging.getPlugin(for: "awsCloudWatchLoggingPlugin") | ||
guard let loggingPlugin = plugin as? AWSCloudWatchLoggingPlugin else { | ||
XCTFail("Could not get plugin of type AWSCloudWatchLoggingPlugin") | ||
return | ||
} | ||
try await loggingPlugin.flushLogs() | ||
try await Task.sleep(seconds: 30) | ||
let cloudWatchClient = loggingPlugin.getEscapeHatch() | ||
try await verifyMessageSent(client: cloudWatchClient, | ||
logGroupName: loggingConfiguration?.logGroupName, | ||
logLevel: "error", | ||
message: message, | ||
category: category, | ||
namespace: namespace) | ||
} | ||
|
||
/// - Given: a AWS CloudWatch Logging plugin | ||
/// - When: an warn log message is logged and flushed | ||
/// - Then: the warn log message is logged and sent to AWS CloudWatch | ||
func testFlushLogWithWarnMessage() async throws { | ||
let category = "API" | ||
let namespace = UUID().uuidString | ||
let message = "this is an warn message in the integration test \(Date().epochMilliseconds)" | ||
let logger = Amplify.Logging.logger(forCategory: category, forNamespace: namespace) | ||
logger.warn(message) | ||
let plugin = try Amplify.Logging.getPlugin(for: "awsCloudWatchLoggingPlugin") | ||
guard let loggingPlugin = plugin as? AWSCloudWatchLoggingPlugin else { | ||
XCTFail("Could not get plugin of type AWSCloudWatchLoggingPlugin") | ||
return | ||
} | ||
try await loggingPlugin.flushLogs() | ||
try await Task.sleep(seconds: 30) | ||
let cloudWatchClient = loggingPlugin.getEscapeHatch() | ||
try await verifyMessageSent(client: cloudWatchClient, | ||
logGroupName: loggingConfiguration?.logGroupName, | ||
logLevel: "warn", | ||
message: message, | ||
category: category, | ||
namespace: namespace) | ||
} | ||
|
||
/// - Given: a AWS CloudWatch Logging plugin | ||
/// - When: an debug log message is logged and flushed | ||
/// - Then: the debug log message is logged and sent to AWS CloudWatch | ||
func testFlushLogWithDebugMessage() async throws { | ||
let category = "Geo" | ||
let namespace = UUID().uuidString | ||
let dateFormatter = DateFormatter() | ||
dateFormatter.dateStyle = .long | ||
dateFormatter.timeStyle = .long | ||
let message = "this is an debug message in the integration test \(Date().epochMilliseconds)" | ||
let logger = Amplify.Logging.logger(forCategory: category, forNamespace: namespace) | ||
logger.debug(message) | ||
let plugin = try Amplify.Logging.getPlugin(for: "awsCloudWatchLoggingPlugin") | ||
guard let loggingPlugin = plugin as? AWSCloudWatchLoggingPlugin else { | ||
XCTFail("Could not get plugin of type AWSCloudWatchLoggingPlugin") | ||
return | ||
} | ||
try await loggingPlugin.flushLogs() | ||
try await Task.sleep(seconds: 30) | ||
let cloudWatchClient = loggingPlugin.getEscapeHatch() | ||
try await verifyMessageSent(client: cloudWatchClient, | ||
logGroupName: loggingConfiguration?.logGroupName, | ||
logLevel: "debug", | ||
message: message, | ||
category: category, | ||
namespace: namespace) | ||
} | ||
|
||
/// - Given: a AWS CloudWatch Logging plugin | ||
/// - When: an info log message is logged and flushed | ||
/// - Then: the info log message is logged and sent to AWS CloudWatch | ||
func testFlushLogWithInfoMessage() async throws { | ||
let category = "Auth" | ||
let namespace = UUID().uuidString | ||
let message = "this is an info message in the integration test \(Date().epochMilliseconds)" | ||
let logger = Amplify.Logging.logger(forCategory: category, forNamespace: namespace) | ||
logger.info(message) | ||
let plugin = try Amplify.Logging.getPlugin(for: "awsCloudWatchLoggingPlugin") | ||
guard let loggingPlugin = plugin as? AWSCloudWatchLoggingPlugin else { | ||
XCTFail("Could not get plugin of type AWSCloudWatchLoggingPlugin") | ||
return | ||
} | ||
try await loggingPlugin.flushLogs() | ||
try await Task.sleep(seconds: 30) | ||
let cloudWatchClient = loggingPlugin.getEscapeHatch() | ||
try await verifyMessageSent(client: cloudWatchClient, | ||
logGroupName: loggingConfiguration?.logGroupName, | ||
logLevel: "info", | ||
message: message, | ||
category: category, | ||
namespace: namespace) | ||
} | ||
|
||
/// - Given: a AWS CloudWatch Logging plugin with logging enabled | ||
/// - When: an error log message is logged and flushed | ||
/// - Then: the eror log message is logged and sent to AWS CloudWatch | ||
func testFlushLogWithVerboseMessageAfterEnablingPlugin() async throws { | ||
let category = "Storage" | ||
let namespace = UUID().uuidString | ||
let message = "this is an verbose message in the integration test after enabling logging \(Date().epochMilliseconds)" | ||
let logger = Amplify.Logging.logger(forCategory: category, forNamespace: namespace) | ||
Amplify.Logging.enable() | ||
logger.verbose(message) | ||
let plugin = try Amplify.Logging.getPlugin(for: "awsCloudWatchLoggingPlugin") | ||
guard let loggingPlugin = plugin as? AWSCloudWatchLoggingPlugin else { | ||
XCTFail("Could not get plugin of type AWSCloudWatchLoggingPlugin") | ||
return | ||
} | ||
try await loggingPlugin.flushLogs() | ||
try await Task.sleep(seconds: 30) | ||
let cloudWatchClient = loggingPlugin.getEscapeHatch() | ||
try await verifyMessageSent(client: cloudWatchClient, | ||
logGroupName: loggingConfiguration?.logGroupName, | ||
logLevel: "verbose", | ||
message: message, | ||
category: category, | ||
namespace: namespace) | ||
} | ||
|
||
/// - Given: a AWS CloudWatch Logging plugin with logging disabled | ||
/// - When: an error log message is logged and flushed | ||
/// - Then: the eror log message is not logged and sent to AWS CloudWatch | ||
func testFlushLogWithVerboseMessageAfterDisablingPlugin() async throws { | ||
let category = "Storage" | ||
let namespace = UUID().uuidString | ||
let message = "this is an verbose message in the integration test after disabling logging \(Date().epochMilliseconds)" | ||
let logger = Amplify.Logging.logger(forCategory: category, forNamespace: namespace) | ||
Amplify.Logging.disable() | ||
logger.verbose(message) | ||
let plugin = try Amplify.Logging.getPlugin(for: "awsCloudWatchLoggingPlugin") | ||
guard let loggingPlugin = plugin as? AWSCloudWatchLoggingPlugin else { | ||
XCTFail("Could not get plugin of type AWSCloudWatchLoggingPlugin") | ||
return | ||
} | ||
try await loggingPlugin.flushLogs() | ||
try await Task.sleep(seconds: 30) | ||
let cloudWatchClient = loggingPlugin.getEscapeHatch() | ||
try await verifyMessageNotSent(client: cloudWatchClient, | ||
logGroupName: loggingConfiguration?.logGroupName, | ||
message: message) | ||
} | ||
|
||
func verifyMessageSent(client: CloudWatchLogsClientProtocol?, | ||
logGroupName: String?, | ||
logLevel: String, | ||
message: String, | ||
category: String, | ||
namespace: String) async throws { | ||
|
||
let events = try await getLastMessageSent(client: client, logGroupName: logGroupName, message: message, requestAttempt: 0) | ||
XCTAssertEqual(events?.count, 1) | ||
guard let sentLogMessage = events?.first?.message else { | ||
XCTFail("Unable to verify last log message") | ||
return | ||
} | ||
XCTAssertTrue(sentLogMessage.lowercased().contains(logLevel)) | ||
XCTAssertTrue(sentLogMessage.contains(message)) | ||
XCTAssertTrue(sentLogMessage.contains(category)) | ||
XCTAssertTrue(sentLogMessage.contains(namespace)) | ||
} | ||
|
||
func verifyMessageNotSent(client: CloudWatchLogsClientProtocol?, | ||
logGroupName: String?, | ||
message: String) async throws { | ||
|
||
let events = try await getLastMessageSent(client: client, logGroupName: logGroupName, message: message, requestAttempt: 0) | ||
XCTAssertEqual(events?.count, 0) | ||
} | ||
|
||
func getLastMessageSent(client: CloudWatchLogsClientProtocol?, | ||
logGroupName: String?, | ||
message: String, | ||
requestAttempt: Int) async throws -> [CloudWatchLogsClientTypes.FilteredLogEvent]? { | ||
let endTime = Date() | ||
let durationInMinutes = requestAttempt+1 | ||
let startTime = endTime.addingTimeInterval(TimeInterval(-durationInMinutes*60)) | ||
var events = try await AWSCloudWatchClientHelper.getFilterLogEventCount(client: client, filterPattern: message, startTime: startTime, endTime: endTime, logGroupName: logGroupName) | ||
|
||
if events?.count == 0 && requestAttempt <= 5 { | ||
try await Task.sleep(seconds: 30) | ||
let attempted = requestAttempt + 1 | ||
events = try await getLastMessageSent( | ||
client: client, | ||
logGroupName: logGroupName, | ||
message: message, | ||
requestAttempt: attempted) | ||
} | ||
|
||
return events | ||
} | ||
} |
Oops, something went wrong.