Skip to content

Updated S3.Event #195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 18 commits into from
Apr 15, 2021
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion Sources/AWSLambdaEvents/S3.swift
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@ public enum S3 {

public struct Object: Codable {
public let key: String
public let size: UInt64
/// The object's size in bytes.
///
/// Note: This property is available for all event types except "ObjectRemoved:*"
public let size: UInt64?
public let urlDecodedKey: String?
public let versionId: String?
public let eTag: String
Expand Down
2 changes: 1 addition & 1 deletion Sources/AWSLambdaEvents/Utils/HTTP.swift
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ extension HTTPResponseStatus: Codable {
}

extension String {
internal var isValidHTTPToken: Bool {
var isValidHTTPToken: Bool {
self.utf8.allSatisfy { (char) -> Bool in
switch char {
case UInt8(ascii: "a") ... UInt8(ascii: "z"),
Expand Down
2 changes: 1 addition & 1 deletion Sources/AWSLambdaRuntimeCore/Lambda+LocalServer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension Lambda {
/// - body: Code to run within the context of the mock server. Typically this would be a Lambda.run function call.
///
/// - note: This API is designed stricly for local testing and is behind a DEBUG flag
internal static func withLocalServer<Value>(invocationEndpoint: String? = nil, _ body: @escaping () -> Value) throws -> Value {
static func withLocalServer<Value>(invocationEndpoint: String? = nil, _ body: @escaping () -> Value) throws -> Value {
let server = LocalLambda.Server(invocationEndpoint: invocationEndpoint)
try server.start().wait()
defer { try! server.stop() }
Expand Down
2 changes: 1 addition & 1 deletion Sources/AWSLambdaRuntimeCore/LambdaConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Logging
import NIO

extension Lambda {
internal struct Configuration: CustomStringConvertible {
struct Configuration: CustomStringConvertible {
let general: General
let lifecycle: Lifecycle
let runtimeEngine: RuntimeEngine
Expand Down
2 changes: 1 addition & 1 deletion Sources/AWSLambdaRuntimeCore/LambdaRunner.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import NIO

extension Lambda {
/// LambdaRunner manages the Lambda runtime workflow, or business logic.
internal final class Runner {
final class Runner {
private let runtimeClient: RuntimeClient
private let eventLoop: EventLoop
private let allocator: ByteBufferAllocator
Expand Down
8 changes: 4 additions & 4 deletions Sources/AWSLambdaRuntimeCore/LambdaRuntimeClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import NIOHTTP1
/// * /runtime/invocation/error
/// * /runtime/init/error
extension Lambda {
internal struct RuntimeClient {
struct RuntimeClient {
private let eventLoop: EventLoop
private let allocator = ByteBufferAllocator()
private let httpClient: HTTPClient
Expand Down Expand Up @@ -156,7 +156,7 @@ extension ErrorResponse {
}

extension Lambda {
internal struct Invocation {
struct Invocation {
let requestID: String
let deadlineInMillisSinceEpoch: Int64
let invokedFunctionARN: String
Expand Down Expand Up @@ -194,10 +194,10 @@ extension Lambda {
}

extension Lambda.RuntimeClient {
internal static let defaultHeaders = HTTPHeaders([("user-agent", "Swift-Lambda/Unknown")])
static let defaultHeaders = HTTPHeaders([("user-agent", "Swift-Lambda/Unknown")])

/// These headers must be sent along an invocation or initialization error report
internal static let errorHeaders = HTTPHeaders([
static let errorHeaders = HTTPHeaders([
("user-agent", "Swift-Lambda/Unknown"),
("lambda-runtime-function-error-type", "Unhandled"),
])
Expand Down
2 changes: 1 addition & 1 deletion Sources/AWSLambdaRuntimeCore/Utils.swift
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ extension AmazonHeaders {
/// # References
/// - [Generating trace IDs](https://docs.aws.amazon.com/xray/latest/devguide/xray-api-sendingdata.html#xray-api-traceids)
/// - [Tracing header](https://docs.aws.amazon.com/xray/latest/devguide/xray-concepts.html#xray-concepts-tracingheader)
internal static func generateXRayTraceID() -> String {
static func generateXRayTraceID() -> String {
// The version number, that is, 1.
let version: UInt = 1
// The time of the original request, in Unix epoch time, in 8 hexadecimal digits.
Expand Down
76 changes: 73 additions & 3 deletions Tests/AWSLambdaEventsTests/S3Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
import XCTest

class S3Tests: XCTestCase {
static let eventBody = """
static let eventBodyObjectCreated = """
{
"Records": [
{
Expand Down Expand Up @@ -57,8 +57,49 @@ class S3Tests: XCTestCase {
}
"""

func testSimpleEventFromJSON() {
let data = S3Tests.eventBody.data(using: .utf8)!
// A S3 ObjectRemoved:* event does not contain the object size
static let eventBodyObjectRemoved = """
{
"Records": [
{
"eventVersion":"2.1",
"eventSource":"aws:s3",
"awsRegion":"eu-central-1",
"eventTime":"2020-01-13T09:25:40.621Z",
"eventName":"ObjectRemoved:DeleteMarkerCreated",
"userIdentity":{
"principalId":"AWS:AAAAAAAJ2MQ4YFQZ7AULJ"
},
"requestParameters":{
"sourceIPAddress":"123.123.123.123"
},
"responseElements":{
"x-amz-request-id":"01AFA1430E18C358",
"x-amz-id-2":"JsbNw6sHGFwgzguQjbYcew//bfAeZITyTYLfjuu1U4QYqCq5CPlSyYLtvWQS+gw0RxcroItGwm8="
},
"s3":{
"s3SchemaVersion":"1.0",
"configurationId":"98b55bc4-3c0c-4007-b727-c6b77a259dde",
"bucket":{
"name":"eventsources",
"ownerIdentity":{
"principalId":"AAAAAAAAAAAAAA"
},
"arn":"arn:aws:s3:::eventsources"
},
"object":{
"key":"Hi.md",
"eTag":"91a7f2c3ae81bcc6afef83979b463f0e",
"sequencer":"005E1C37948E783A6E"
}
}
}
]
}
"""

func testObjectCreatedEvent() {
let data = S3Tests.eventBodyObjectCreated.data(using: .utf8)!
var event: S3.Event?
XCTAssertNoThrow(event = try JSONDecoder().decode(S3.Event.self, from: data))

Expand All @@ -85,4 +126,33 @@ class S3Tests: XCTestCase {
XCTAssertEqual(record.s3.object.eTag, "91a7f2c3ae81bcc6afef83979b463f0e")
XCTAssertEqual(record.s3.object.sequencer, "005E1C37948E783A6E")
}

func testObjectRemovedEvent() {
let data = S3Tests.eventBodyObjectRemoved.data(using: .utf8)!
var event: S3.Event?
XCTAssertNoThrow(event = try JSONDecoder().decode(S3.Event.self, from: data))

guard let record = event?.records.first else {
XCTFail("Expected to have one record")
return
}

XCTAssertEqual(record.eventVersion, "2.1")
XCTAssertEqual(record.eventSource, "aws:s3")
XCTAssertEqual(record.awsRegion, .eu_central_1)
XCTAssertEqual(record.eventName, "ObjectRemoved:DeleteMarkerCreated")
XCTAssertEqual(record.eventTime, Date(timeIntervalSince1970: 1_578_907_540.621))
XCTAssertEqual(record.userIdentity, S3.UserIdentity(principalId: "AWS:AAAAAAAJ2MQ4YFQZ7AULJ"))
XCTAssertEqual(record.requestParameters, S3.RequestParameters(sourceIPAddress: "123.123.123.123"))
XCTAssertEqual(record.responseElements.count, 2)
XCTAssertEqual(record.s3.schemaVersion, "1.0")
XCTAssertEqual(record.s3.configurationId, "98b55bc4-3c0c-4007-b727-c6b77a259dde")
XCTAssertEqual(record.s3.bucket.name, "eventsources")
XCTAssertEqual(record.s3.bucket.ownerIdentity, S3.UserIdentity(principalId: "AAAAAAAAAAAAAA"))
XCTAssertEqual(record.s3.bucket.arn, "arn:aws:s3:::eventsources")
XCTAssertEqual(record.s3.object.key, "Hi.md")
XCTAssertNil(record.s3.object.size)
XCTAssertEqual(record.s3.object.eTag, "91a7f2c3ae81bcc6afef83979b463f0e")
XCTAssertEqual(record.s3.object.sequencer, "005E1C37948E783A6E")
}
}