1410 lines
67 KiB
Zig
1410 lines
67 KiB
Zig
const builtin = @import("builtin");
|
|
const std = @import("std");
|
|
|
|
const date = @import("date");
|
|
const json = @import("json");
|
|
|
|
const aws = @import("aws.zig");
|
|
const awshttp = @import("aws_http.zig");
|
|
|
|
const services = aws.servicemodel.services;
|
|
const Services = aws.servicemodel.Services;
|
|
|
|
const log = std.log.scoped(.aws_test);
|
|
|
|
pub var buildQuery: u8 = undefined;
|
|
pub var buildPath: u8 = undefined;
|
|
|
|
// TODO: Where does this belong really?
|
|
fn typeForField(comptime T: type, comptime field_name: []const u8) !type {
|
|
const ti = @typeInfo(T);
|
|
switch (ti) {
|
|
.@"struct" => {
|
|
inline for (ti.@"struct".fields) |field| {
|
|
if (std.mem.eql(u8, field.name, field_name))
|
|
return field.type;
|
|
}
|
|
},
|
|
else => return error.TypeIsNotAStruct, // should not hit this
|
|
}
|
|
return error.FieldNotFound;
|
|
}
|
|
|
|
test "custom serialization for map objects" {
|
|
const allocator = std.testing.allocator;
|
|
var buffer = std.Io.Writer.Allocating.init(allocator);
|
|
defer buffer.deinit();
|
|
var tags = try std.ArrayList(@typeInfo(try typeForField(services.lambda.tag_resource.Request, "tags")).pointer.child).initCapacity(allocator, 2);
|
|
defer tags.deinit(allocator);
|
|
tags.appendAssumeCapacity(.{ .key = "Foo", .value = "Bar" });
|
|
tags.appendAssumeCapacity(.{ .key = "Baz", .value = "Qux" });
|
|
const req = services.lambda.TagResourceRequest{ .resource = "hello", .tags = tags.items };
|
|
try buffer.writer.print("{f}", .{std.json.fmt(req, .{ .whitespace = .indent_4 })});
|
|
|
|
const parsed_body = try std.json.parseFromSlice(struct {
|
|
Resource: []const u8,
|
|
Tags: struct {
|
|
Foo: []const u8,
|
|
Baz: []const u8,
|
|
},
|
|
}, testing.allocator, buffer.written(), .{});
|
|
defer parsed_body.deinit();
|
|
|
|
try testing.expectEqualStrings("hello", parsed_body.value.Resource);
|
|
try testing.expectEqualStrings("Bar", parsed_body.value.Tags.Foo);
|
|
try testing.expectEqualStrings("Qux", parsed_body.value.Tags.Baz);
|
|
}
|
|
|
|
test "proper serialization for kms" {
|
|
// Github issue #8
|
|
// https://github.com/elerch/aws-sdk-for-zig/issues/8
|
|
const allocator = std.testing.allocator;
|
|
var buffer = std.Io.Writer.Allocating.init(allocator);
|
|
defer buffer.deinit();
|
|
const req = services.kms.encrypt.Request{
|
|
.encryption_algorithm = "SYMMETRIC_DEFAULT",
|
|
// Since encryption_context is not null, we expect "{}" to be the value
|
|
// here, not "[]", because this is our special AWS map pattern
|
|
.encryption_context = &.{},
|
|
.key_id = "42",
|
|
.plaintext = "foo",
|
|
.dry_run = false,
|
|
.grant_tokens = &[_][]const u8{},
|
|
};
|
|
try buffer.writer.print("{f}", .{std.json.fmt(req, .{ .whitespace = .indent_4 })});
|
|
|
|
{
|
|
const parsed_body = try std.json.parseFromSlice(struct {
|
|
KeyId: []const u8,
|
|
Plaintext: []const u8,
|
|
EncryptionContext: struct {},
|
|
GrantTokens: [][]const u8,
|
|
EncryptionAlgorithm: []const u8,
|
|
DryRun: bool,
|
|
}, testing.allocator, buffer.written(), .{});
|
|
defer parsed_body.deinit();
|
|
|
|
try testing.expectEqualStrings("42", parsed_body.value.KeyId);
|
|
try testing.expectEqualStrings("foo", parsed_body.value.Plaintext);
|
|
try testing.expectEqual(0, parsed_body.value.GrantTokens.len);
|
|
try testing.expectEqualStrings("SYMMETRIC_DEFAULT", parsed_body.value.EncryptionAlgorithm);
|
|
try testing.expectEqual(false, parsed_body.value.DryRun);
|
|
}
|
|
|
|
var buffer_null = std.Io.Writer.Allocating.init(allocator);
|
|
defer buffer_null.deinit();
|
|
const req_null = services.kms.encrypt.Request{
|
|
.encryption_algorithm = "SYMMETRIC_DEFAULT",
|
|
// Since encryption_context here *IS* null, we expect simply "null" to be the value
|
|
.encryption_context = null,
|
|
.key_id = "42",
|
|
.plaintext = "foo",
|
|
.dry_run = false,
|
|
.grant_tokens = &[_][]const u8{},
|
|
};
|
|
|
|
try buffer_null.writer.print("{f}", .{std.json.fmt(req_null, .{ .whitespace = .indent_4 })});
|
|
|
|
{
|
|
const parsed_body = try std.json.parseFromSlice(struct {
|
|
KeyId: []const u8,
|
|
Plaintext: []const u8,
|
|
EncryptionContext: ?struct {},
|
|
GrantTokens: [][]const u8,
|
|
EncryptionAlgorithm: []const u8,
|
|
DryRun: bool,
|
|
}, testing.allocator, buffer_null.written(), .{});
|
|
defer parsed_body.deinit();
|
|
|
|
try testing.expectEqualStrings("42", parsed_body.value.KeyId);
|
|
try testing.expectEqualStrings("foo", parsed_body.value.Plaintext);
|
|
try testing.expectEqual(null, parsed_body.value.EncryptionContext);
|
|
try testing.expectEqual(0, parsed_body.value.GrantTokens.len);
|
|
try testing.expectEqualStrings("SYMMETRIC_DEFAULT", parsed_body.value.EncryptionAlgorithm);
|
|
try testing.expectEqual(false, parsed_body.value.DryRun);
|
|
}
|
|
}
|
|
|
|
test "REST Json v1 builds proper queries" {
|
|
const allocator = std.testing.allocator;
|
|
const svs = Services(.{.lambda}){};
|
|
const request = svs.lambda.list_functions.Request{
|
|
.max_items = 1,
|
|
};
|
|
const query = try buildQuery(allocator, request);
|
|
defer allocator.free(query);
|
|
try std.testing.expectEqualStrings("?MaxItems=1", query);
|
|
}
|
|
test "REST Json v1 handles reserved chars in queries" {
|
|
const allocator = std.testing.allocator;
|
|
const svs = Services(.{.lambda}){};
|
|
var keys = [_][]const u8{"Foo?I'm a crazy%dude"}; // Would love to have a way to express this without burning a var here
|
|
const request = svs.lambda.untag_resource.Request{
|
|
.tag_keys = keys[0..],
|
|
.resource = "hello",
|
|
};
|
|
const query = try buildQuery(allocator, request);
|
|
defer allocator.free(query);
|
|
try std.testing.expectEqualStrings("?tagKeys=Foo%3FI%27m a crazy%25dude", query);
|
|
}
|
|
test "REST Json v1 serializes lists in queries" {
|
|
const allocator = std.testing.allocator;
|
|
const svs = Services(.{.lambda}){};
|
|
var keys = [_][]const u8{ "Foo", "Bar" }; // Would love to have a way to express this without burning a var here
|
|
const request = svs.lambda.untag_resource.Request{
|
|
.tag_keys = keys[0..],
|
|
.resource = "hello",
|
|
};
|
|
const query = try buildQuery(allocator, request);
|
|
defer allocator.free(query);
|
|
try std.testing.expectEqualStrings("?tagKeys=Foo&tagKeys=Bar", query);
|
|
}
|
|
test "REST Json v1 buildpath substitutes" {
|
|
const allocator = std.testing.allocator;
|
|
var al = std.ArrayList([]const u8){};
|
|
defer al.deinit(allocator);
|
|
const svs = Services(.{.lambda}){};
|
|
const request = svs.lambda.list_functions.Request{
|
|
.max_items = 1,
|
|
};
|
|
const input_path = "https://myhost/{MaxItems}/";
|
|
const output_path = try buildPath(allocator, input_path, @TypeOf(request), request, true, &al);
|
|
defer allocator.free(output_path);
|
|
try std.testing.expectEqualStrings("https://myhost/1/", output_path);
|
|
}
|
|
test "REST Json v1 buildpath handles restricted characters" {
|
|
const allocator = std.testing.allocator;
|
|
var al = std.ArrayList([]const u8){};
|
|
defer al.deinit(allocator);
|
|
const svs = Services(.{.lambda}){};
|
|
const request = svs.lambda.list_functions.Request{
|
|
.marker = ":",
|
|
};
|
|
const input_path = "https://myhost/{Marker}/";
|
|
const output_path = try buildPath(allocator, input_path, @TypeOf(request), request, true, &al);
|
|
defer allocator.free(output_path);
|
|
try std.testing.expectEqualStrings("https://myhost/%3A/", output_path);
|
|
}
|
|
test "basic json request serialization" {
|
|
const allocator = std.testing.allocator;
|
|
const svs = Services(.{.dynamo_db}){};
|
|
const request = svs.dynamo_db.list_tables.Request{
|
|
.limit = 1,
|
|
};
|
|
var buffer = std.Io.Writer.Allocating.init(allocator);
|
|
defer buffer.deinit();
|
|
|
|
// The transformer needs to allocate stuff out of band, but we
|
|
// can guarantee we don't need the memory after this call completes,
|
|
// so we'll use an arena allocator to whack everything.
|
|
// TODO: Determine if sending in null values is ok, or if we need another
|
|
// tweak to the stringify function to exclude. According to the
|
|
// smithy spec, "A null value MAY be provided or omitted
|
|
// for a boxed member with no observable difference." But we're
|
|
// seeing a lot of differences here between spec and reality
|
|
//
|
|
try buffer.writer.print("{f}", .{std.json.fmt(request, .{ .whitespace = .indent_4 })});
|
|
try std.testing.expectEqualStrings(
|
|
\\{
|
|
\\ "ExclusiveStartTableName": null,
|
|
\\ "Limit": 1
|
|
\\}
|
|
, buffer.written());
|
|
}
|
|
test "layer object only" {
|
|
const TestResponse = struct {
|
|
arn: ?[]const u8 = null,
|
|
// uncompressed_code_size: ?i64 = null,
|
|
|
|
pub fn jsonFieldNameFor(_: @This(), comptime field_name: []const u8) []const u8 {
|
|
const mappings = .{
|
|
.arn = "Arn",
|
|
};
|
|
return @field(mappings, field_name);
|
|
}
|
|
};
|
|
const response =
|
|
\\ {
|
|
\\ "UncompressedCodeSize": 2,
|
|
\\ "Arn": "blah"
|
|
\\ }
|
|
;
|
|
// const response =
|
|
// \\ {
|
|
// \\ "UncompressedCodeSize": 22599541,
|
|
// \\ "Arn": "arn:aws:lambda:us-west-2:123456789012:layer:PollyNotes-lib:4"
|
|
// \\ }
|
|
// ;
|
|
const allocator = std.testing.allocator;
|
|
var stream = json.TokenStream.init(response);
|
|
const parser_options = json.ParseOptions{
|
|
.allocator = allocator,
|
|
.allow_camel_case_conversion = true, // new option
|
|
.allow_snake_case_conversion = true, // new option
|
|
.allow_unknown_fields = true, // new option. Cannot yet handle non-struct fields though
|
|
.allow_missing_fields = false, // new option. Cannot yet handle non-struct fields though
|
|
};
|
|
const r = try json.parse(TestResponse, &stream, parser_options);
|
|
json.parseFree(TestResponse, r, parser_options);
|
|
}
|
|
|
|
// Use for debugging json responses of specific requests
|
|
// test "dummy request" {
|
|
// const allocator = std.testing.allocator;
|
|
// const svs = Services(.{.sts}){};
|
|
// const request = svs.sts.get_session_token.Request{
|
|
// .duration_seconds = 900,
|
|
// };
|
|
// const FullR = FullResponse(request);
|
|
// const response =
|
|
// var stream = json.TokenStream.init(response);
|
|
//
|
|
// const parser_options = json.ParseOptions{
|
|
// .allocator = allocator,
|
|
// .allow_camel_case_conversion = true, // new option
|
|
// .allow_snake_case_conversion = true, // new option
|
|
// .allow_unknown_fields = true, // new option. Cannot yet handle non-struct fields though
|
|
// .allow_missing_fields = false, // new option. Cannot yet handle non-struct fields though
|
|
// };
|
|
// const SResponse = ServerResponse(request);
|
|
// const r = try json.parse(SResponse, &stream, parser_options);
|
|
// json.parseFree(SResponse, r, parser_options);
|
|
|
|
test {
|
|
// To run nested container tests, either, call `refAllDecls` which will
|
|
// reference all declarations located in the given argument.
|
|
// `@This()` is a builtin function that returns the innermost container it is called from.
|
|
// In this example, the innermost container is this file (implicitly a struct).
|
|
std.testing.refAllDecls(@This());
|
|
std.testing.refAllDecls(awshttp);
|
|
std.testing.refAllDecls(json);
|
|
std.testing.refAllDecls(@import("url.zig"));
|
|
std.testing.refAllDecls(@import("case"));
|
|
std.testing.refAllDecls(date);
|
|
std.testing.refAllDecls(@import("servicemodel.zig"));
|
|
std.testing.refAllDecls(@import("xml_shaper.zig"));
|
|
}
|
|
const TestOptions = struct {
|
|
allocator: std.mem.Allocator,
|
|
arena: ?*std.mem.ArenaAllocator = null,
|
|
server_port: ?u16 = null,
|
|
server_remaining_requests: usize = 1,
|
|
server_response: []const u8 = "unset",
|
|
server_response_status: std.http.Status = .ok,
|
|
server_response_headers: []const std.http.Header = &.{},
|
|
server_response_transfer_encoding: ?std.http.TransferEncoding = null,
|
|
request_body: []u8 = "",
|
|
request_method: std.http.Method = undefined,
|
|
request_target: []const u8 = undefined,
|
|
request_headers: []std.http.Header = undefined,
|
|
test_server_runtime_uri: ?[]u8 = null,
|
|
server_ready: std.Thread.Semaphore = .{},
|
|
requests_processed: usize = 0,
|
|
|
|
const Self = @This();
|
|
|
|
/// Builtin hashmap for strings as keys.
|
|
/// Key memory is managed by the caller. Keys and values
|
|
/// will not automatically be freed.
|
|
pub fn StringCaseInsensitiveHashMap(comptime V: type) type {
|
|
return std.HashMap([]const u8, V, StringInsensitiveContext, std.hash_map.default_max_load_percentage);
|
|
}
|
|
|
|
pub const StringInsensitiveContext = struct {
|
|
pub fn hash(self: @This(), s: []const u8) u64 {
|
|
_ = self;
|
|
return hashString(s);
|
|
}
|
|
pub fn eql(self: @This(), a: []const u8, b: []const u8) bool {
|
|
_ = self;
|
|
return eqlString(a, b);
|
|
}
|
|
};
|
|
|
|
pub fn eqlString(a: []const u8, b: []const u8) bool {
|
|
return std.ascii.eqlIgnoreCase(a, b);
|
|
}
|
|
|
|
pub fn hashString(s: []const u8) u64 {
|
|
var buf: [1024]u8 = undefined;
|
|
if (s.len > buf.len) unreachable; // tolower has a debug assert, but we want non-debug check too
|
|
const lower_s = std.ascii.lowerString(buf[0..], s);
|
|
return std.hash.Wyhash.hash(0, lower_s);
|
|
}
|
|
|
|
fn expectNoDuplicateHeaders(self: *Self) !void {
|
|
// As header keys are
|
|
var hm = StringCaseInsensitiveHashMap(void).init(self.allocator);
|
|
try hm.ensureTotalCapacity(@intCast(self.request_headers.len));
|
|
defer hm.deinit();
|
|
for (self.request_headers) |h| {
|
|
if (hm.getKey(h.name)) |_| {
|
|
log.err("Duplicate key detected. Key name: {s}", .{h.name});
|
|
return error.duplicateKeyDetected;
|
|
}
|
|
try hm.put(h.name, {});
|
|
}
|
|
}
|
|
|
|
fn expectHeader(self: *Self, name: []const u8, value: []const u8) !void {
|
|
for (self.request_headers) |h|
|
|
if (std.ascii.eqlIgnoreCase(name, h.name) and
|
|
std.mem.eql(u8, value, h.value)) return;
|
|
return error.HeaderOrValueNotFound;
|
|
}
|
|
fn waitForReady(self: *Self) !void {
|
|
// Set 10s timeout...this is way longer than necessary
|
|
log.debug("waiting for ready", .{});
|
|
try self.server_ready.timedWait(1000 * std.time.ns_per_ms);
|
|
// var deadline = std.Thread.Futex.Deadline.init(1000 * std.time.ns_per_ms);
|
|
// if (self.futex_word.load(.acquire) != 0) return;
|
|
// log.debug("futex zero", .{});
|
|
// // note that this seems backwards from the documentation...
|
|
// deadline.wait(self.futex_word, 1) catch {
|
|
// log.err("futex value {d}", .{self.futex_word.load(.acquire)});
|
|
// return error.TestServerTimeoutWaitingForReady;
|
|
// };
|
|
log.debug("the wait is over!", .{});
|
|
}
|
|
};
|
|
|
|
/// This starts a test server. We're not testing the server itself,
|
|
/// so the main tests will start this thing up and create an arena around the
|
|
/// whole thing so we can just deallocate everything at once at the end,
|
|
/// leaks be damned
|
|
fn threadMain(options: *TestOptions) !void {
|
|
// https://github.com/ziglang/zig/blob/d2be725e4b14c33dbd39054e33d926913eee3cd4/lib/compiler/std-docs.zig#L22-L54
|
|
|
|
options.arena = try options.allocator.create(std.mem.ArenaAllocator);
|
|
options.arena.?.* = std.heap.ArenaAllocator.init(options.allocator);
|
|
const allocator = options.arena.?.allocator();
|
|
options.allocator = allocator;
|
|
|
|
const address = try std.net.Address.parseIp("127.0.0.1", 0);
|
|
var http_server = try address.listen(.{});
|
|
options.server_port = http_server.listen_address.in.getPort();
|
|
// TODO: remove
|
|
options.test_server_runtime_uri = try std.fmt.allocPrint(options.allocator, "http://127.0.0.1:{d}", .{options.server_port.?});
|
|
log.debug("server listening at {s}", .{options.test_server_runtime_uri.?});
|
|
log.info("starting server thread, tid {d}", .{std.Thread.getCurrentId()});
|
|
// var arena = std.heap.ArenaAllocator.init(options.allocator);
|
|
// defer arena.deinit();
|
|
// var aa = arena.allocator();
|
|
// We're in control of all requests/responses, so this flag will tell us
|
|
// when it's time to shut down
|
|
if (options.server_remaining_requests == 0)
|
|
options.server_ready.post(); // This will cause the wait for server to return
|
|
while (options.server_remaining_requests > 0) : (options.server_remaining_requests -= 1) {
|
|
processRequest(options, &http_server) catch |e| {
|
|
log.err("Unexpected error processing request: {any}", .{e});
|
|
if (@errorReturnTrace()) |trace| {
|
|
std.debug.dumpStackTrace(trace.*);
|
|
}
|
|
};
|
|
}
|
|
}
|
|
|
|
fn processRequest(options: *TestOptions, net_server: *std.net.Server) !void {
|
|
log.debug(
|
|
"tid {d} (server): server waiting to accept. requests remaining: {d}",
|
|
.{ std.Thread.getCurrentId(), options.server_remaining_requests },
|
|
);
|
|
// options.futex_word.store(1, .release);
|
|
// errdefer options.futex_word.store(0, .release);
|
|
options.server_ready.post();
|
|
var connection = try net_server.accept();
|
|
defer connection.stream.close();
|
|
var read_buffer: [1024 * 16]u8 = undefined;
|
|
var http_server = std.http.Server.init(connection, &read_buffer);
|
|
while (http_server.state == .ready) {
|
|
var request = http_server.receiveHead() catch |err| switch (err) {
|
|
error.HttpConnectionClosing => return,
|
|
else => {
|
|
std.log.err("closing http connection: {s}", .{@errorName(err)});
|
|
std.log.debug("Error occurred from this request: \n{s}", .{read_buffer[0..http_server.read_buffer_len]});
|
|
return;
|
|
},
|
|
};
|
|
try serveRequest(options, &request);
|
|
}
|
|
}
|
|
|
|
fn serveRequest(options: *TestOptions, request: *std.http.Server.Request) !void {
|
|
options.requests_processed += 1;
|
|
options.request_body = try (try request.reader()).readAllAlloc(options.allocator, std.math.maxInt(usize));
|
|
options.request_method = request.head.method;
|
|
options.request_target = try options.allocator.dupe(u8, request.head.target);
|
|
var req_headers = std.ArrayList(std.http.Header).init(options.allocator);
|
|
defer req_headers.deinit();
|
|
var it = request.iterateHeaders();
|
|
while (it.next()) |f| {
|
|
const h = try options.allocator.create(std.http.Header);
|
|
h.* = .{ .name = try options.allocator.dupe(u8, f.name), .value = try options.allocator.dupe(u8, f.value) };
|
|
try req_headers.append(h.*);
|
|
}
|
|
options.request_headers = try req_headers.toOwnedSlice();
|
|
log.debug(
|
|
"tid {d} (server): {d} bytes read from request",
|
|
.{ std.Thread.getCurrentId(), options.request_body.len },
|
|
);
|
|
|
|
// try response.headers.append("content-type", "text/plain");
|
|
try request.respond(options.server_response, .{
|
|
.status = options.server_response_status,
|
|
.extra_headers = options.server_response_headers,
|
|
});
|
|
|
|
log.debug(
|
|
"tid {d} (server): sent response",
|
|
.{std.Thread.getCurrentId()},
|
|
);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// These will replicate the tests that were in src/main.zig
|
|
// The server_response and server_response_headers come from logs of
|
|
// a previous run of src/main.zig, with redactions
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
const TestSetup = struct {
|
|
allocator: std.mem.Allocator,
|
|
request_options: TestOptions,
|
|
server_thread: std.Thread = undefined,
|
|
creds: aws_auth.Credentials = undefined,
|
|
client: aws.Client = undefined,
|
|
started: bool = false,
|
|
|
|
const Self = @This();
|
|
|
|
const aws_creds = @import("aws_credentials.zig");
|
|
const aws_auth = @import("aws_authentication.zig");
|
|
const signing_time =
|
|
date.dateTimeToTimestamp(date.parseIso8601ToDateTime("20230908T170252Z") catch @compileError("Cannot parse date")) catch @compileError("Cannot parse date");
|
|
|
|
fn init(options: TestOptions) Self {
|
|
return .{
|
|
.request_options = options,
|
|
.allocator = options.allocator,
|
|
};
|
|
}
|
|
|
|
fn start(self: *Self) !aws.Options {
|
|
self.server_thread = try std.Thread.spawn(
|
|
.{},
|
|
threadMain,
|
|
.{&self.request_options},
|
|
);
|
|
self.started = true;
|
|
try self.request_options.waitForReady();
|
|
// Not sure why we're getting sprayed here, but we have an arena allocator, and this
|
|
// is testing, so yolo
|
|
awshttp.endpoint_override = self.request_options.test_server_runtime_uri;
|
|
if (awshttp.endpoint_override == null) return error.TestSetupStartFailure;
|
|
std.log.debug("endpoint override set to {?s}", .{awshttp.endpoint_override});
|
|
self.creds = aws_auth.Credentials.init(
|
|
self.allocator,
|
|
try self.allocator.dupe(u8, "ACCESS"),
|
|
try self.allocator.dupe(u8, "SECRET"),
|
|
null,
|
|
);
|
|
aws_creds.static_credentials = self.creds;
|
|
const client = aws.Client.init(self.allocator, .{});
|
|
self.client = client;
|
|
return .{
|
|
.region = "us-west-2",
|
|
.client = client,
|
|
.signing_time = signing_time,
|
|
};
|
|
}
|
|
|
|
fn stop(self: *Self) void {
|
|
if (self.request_options.server_remaining_requests > 0)
|
|
if (test_error_log_enabled)
|
|
std.log.err(
|
|
"Test server has {d} request(s) remaining to issue! Draining",
|
|
.{self.request_options.server_remaining_requests},
|
|
)
|
|
else
|
|
std.log.info(
|
|
"Test server has {d} request(s) remaining to issue! Draining",
|
|
.{self.request_options.server_remaining_requests},
|
|
);
|
|
|
|
var rr = self.request_options.server_remaining_requests;
|
|
while (rr > 0) : (rr -= 1) {
|
|
std.log.debug("rr: {d}", .{self.request_options.server_remaining_requests});
|
|
// We need to drain all remaining requests, otherwise the server
|
|
// will hang indefinitely
|
|
var client = std.http.Client{ .allocator = self.allocator };
|
|
defer client.deinit();
|
|
_ = client.fetch(.{ .location = .{ .url = self.request_options.test_server_runtime_uri.? } }) catch unreachable;
|
|
}
|
|
self.server_thread.join();
|
|
}
|
|
|
|
fn deinit(self: *Self) void {
|
|
if (self.request_options.arena) |a| {
|
|
a.deinit();
|
|
self.allocator.destroy(a);
|
|
}
|
|
if (!self.started) return;
|
|
awshttp.endpoint_override = null;
|
|
// creds.deinit(); Creds will get deinited in the course of the call. We don't want to do it twice
|
|
aws_creds.static_credentials = null; // we do need to reset the static creds for the next user though
|
|
self.client.deinit();
|
|
}
|
|
};
|
|
|
|
test "query_no_input: sts getCallerIdentity comptime" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{"GetCallerIdentityResponse":{"GetCallerIdentityResult":{"Account":"123456789012","Arn":"arn:aws:iam::123456789012:user/admin","UserId":"AIDAYAM4POHXHRVANDQBQ"},"ResponseMetadata":{"RequestId":"8f0d54da-1230-40f7-b4ac-95015c4b84cd"}}}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "8f0d54da-1230-40f7-b4ac-95015c4b84cd" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const sts = (Services(.{.sts}){}).sts;
|
|
const call = try aws.Request(sts.get_caller_identity).call(.{}, options);
|
|
// const call = try client.call(services.sts.get_caller_identity.Request{}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings(
|
|
\\Action=GetCallerIdentity&Version=2011-06-15
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings(
|
|
"arn:aws:iam::123456789012:user/admin",
|
|
call.response.arn.?,
|
|
);
|
|
try std.testing.expectEqualStrings("AIDAYAM4POHXHRVANDQBQ", call.response.user_id.?);
|
|
try std.testing.expectEqualStrings("123456789012", call.response.account.?);
|
|
try std.testing.expectEqualStrings("8f0d54da-1230-40f7-b4ac-95015c4b84cd", call.response_metadata.request_id);
|
|
}
|
|
test "query_with_input: iam getRole runtime" {
|
|
// sqs switched from query to json in aws sdk for go v2 commit f5a08768ef820ff5efd62a49ba50c61c9ca5dbcb
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\<GetRoleResponse xmlns="https://iam.amazonaws.com/doc/2010-05-08/">
|
|
\\<GetRoleResult>
|
|
\\ <Role>
|
|
\\ <Path>/application_abc/component_xyz/</Path>
|
|
\\ <Arn>arn:aws:iam::123456789012:role/application_abc/component_xyz/S3Access</Arn>
|
|
\\ <RoleName>S3Access</RoleName>
|
|
\\ <AssumeRolePolicyDocument>
|
|
\\ {"Version":"2012-10-17","Statement":[{"Effect":"Allow",
|
|
\\ "Principal":{"Service":["ec2.amazonaws.com"]},"Action":["sts:AssumeRole"]}]}
|
|
\\ </AssumeRolePolicyDocument>
|
|
\\ <CreateDate>2012-05-08T23:34:01Z</CreateDate>
|
|
\\ <RoleId>AROADBQP57FF2AEXAMPLE</RoleId>
|
|
\\ <RoleLastUsed>
|
|
\\ <LastUsedDate>2019-11-20T17:09:20Z</LastUsedDate>
|
|
\\ <Region>us-east-1</Region>
|
|
\\ </RoleLastUsed>
|
|
\\ </Role>
|
|
\\</GetRoleResult>
|
|
\\<ResponseMetadata>
|
|
\\ <RequestId>df37e965-9967-11e1-a4c3-270EXAMPLE04</RequestId>
|
|
\\</ResponseMetadata>
|
|
\\</GetRoleResponse>
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "text/xml" },
|
|
.{ .name = "x-amzn-RequestId", .value = "df37e965-9967-11e1-a4c3-270EXAMPLE04" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const iam = (Services(.{.iam}){}).iam;
|
|
const call = try test_harness.client.call(iam.get_role.Request{
|
|
.role_name = "S3Access",
|
|
}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings(
|
|
\\Action=GetRole&Version=2010-05-08&RoleName=S3Access
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("arn:aws:iam::123456789012:role/application_abc/component_xyz/S3Access", call.response.role.arn);
|
|
try std.testing.expectEqualStrings("df37e965-9967-11e1-a4c3-270EXAMPLE04", call.response_metadata.request_id);
|
|
}
|
|
test "query_with_input: sts getAccessKeyInfo runtime" {
|
|
// sqs switched from query to json in aws sdk for go v2 commit f5a08768ef820ff5efd62a49ba50c61c9ca5dbcb
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\<GetAccessKeyInfoResponse xmlns="https://sts.amazonaws.com/doc/2011-06-15/">
|
|
\\ <GetAccessKeyInfoResult>
|
|
\\ <Account>123456789012</Account>
|
|
\\ </GetAccessKeyInfoResult>
|
|
\\ <ResponseMetadata>
|
|
\\ <RequestId>ec85bf29-1ef0-459a-930e-6446dd14a286</RequestId>
|
|
\\ </ResponseMetadata>
|
|
\\</GetAccessKeyInfoResponse>
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "text/xml" },
|
|
.{ .name = "x-amzn-RequestId", .value = "ec85bf29-1ef0-459a-930e-6446dd14a286" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const sts = (Services(.{.sts}){}).sts;
|
|
const call = try test_harness.client.call(sts.get_access_key_info.Request{
|
|
.access_key_id = "ASIAYAM4POHXJNKTYFUN",
|
|
}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings(
|
|
\\Action=GetAccessKeyInfo&Version=2011-06-15&AccessKeyId=ASIAYAM4POHXJNKTYFUN
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expect(call.response.account != null);
|
|
try std.testing.expectEqualStrings("123456789012", call.response.account.?);
|
|
try std.testing.expectEqualStrings("ec85bf29-1ef0-459a-930e-6446dd14a286", call.response_metadata.request_id);
|
|
}
|
|
test "json_1_0_query_with_input: dynamodb listTables runtime" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{"LastEvaluatedTableName":"Customer","TableNames":["Customer"]}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "QBI72OUIN8U9M9AG6PCSADJL4JVV4KQNSO5AEMVJF66Q9ASUAAJG" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const dynamo_db = services.dynamo_db;
|
|
const call = try test_harness.client.call(dynamo_db.list_tables.Request{
|
|
.limit = 1,
|
|
}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try test_harness.request_options.expectHeader("X-Amz-Target", "DynamoDB_20120810.ListTables");
|
|
|
|
const parsed_body = try std.json.parseFromSlice(struct {
|
|
ExclusiveStartTableName: ?[]const u8,
|
|
Limit: u8,
|
|
}, testing.allocator, test_harness.request_options.request_body, .{});
|
|
defer parsed_body.deinit();
|
|
|
|
try testing.expectEqual(null, parsed_body.value.ExclusiveStartTableName);
|
|
try testing.expectEqual(1, parsed_body.value.Limit);
|
|
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("QBI72OUIN8U9M9AG6PCSADJL4JVV4KQNSO5AEMVJF66Q9ASUAAJG", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 1), call.response.table_names.?.len);
|
|
try std.testing.expectEqualStrings("Customer", call.response.table_names.?[0]);
|
|
}
|
|
|
|
test "json_1_0_query_no_input: dynamodb listTables runtime" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{"AccountMaxReadCapacityUnits":80000,"AccountMaxWriteCapacityUnits":80000,"TableMaxReadCapacityUnits":40000,"TableMaxWriteCapacityUnits":40000}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "QBI72OUIN8U9M9AG6PCSADJL4JVV4KQNSO5AEMVJF66Q9ASUAAJG" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const dynamo_db = (Services(.{.dynamo_db}){}).dynamo_db;
|
|
const call = try test_harness.client.call(dynamo_db.describe_limits.Request{}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try test_harness.request_options.expectHeader("X-Amz-Target", "DynamoDB_20120810.DescribeLimits");
|
|
try std.testing.expectEqualStrings(
|
|
\\{}
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("QBI72OUIN8U9M9AG6PCSADJL4JVV4KQNSO5AEMVJF66Q9ASUAAJG", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(i64, 80000), call.response.account_max_read_capacity_units.?);
|
|
}
|
|
test "json_1_1_query_with_input: ecs listClusters runtime" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{"clusterArns":["arn:aws:ecs:us-west-2:550620852718:cluster/web-applicationehjaf-cluster"],"nextToken":"czE0Og=="}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "b2420066-ff67-4237-b782-721c4df60744" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const ecs = (Services(.{.ecs}){}).ecs;
|
|
const call = try test_harness.client.call(ecs.list_clusters.Request{
|
|
.max_results = 1,
|
|
}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try test_harness.request_options.expectHeader("X-Amz-Target", "AmazonEC2ContainerServiceV20141113.ListClusters");
|
|
|
|
const parsed_body = try std.json.parseFromSlice(struct {
|
|
nextToken: ?[]const u8,
|
|
maxResults: u8,
|
|
}, testing.allocator, test_harness.request_options.request_body, .{});
|
|
defer parsed_body.deinit();
|
|
|
|
try testing.expectEqual(null, parsed_body.value.nextToken);
|
|
try testing.expectEqual(1, parsed_body.value.maxResults);
|
|
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("b2420066-ff67-4237-b782-721c4df60744", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 1), call.response.cluster_arns.?.len);
|
|
try std.testing.expectEqualStrings("arn:aws:ecs:us-west-2:550620852718:cluster/web-applicationehjaf-cluster", call.response.cluster_arns.?[0]);
|
|
}
|
|
test "json_1_1_query_no_input: ecs listClusters runtime" {
|
|
// const old = std.testing.log_level;
|
|
// defer std.testing.log_level = old;
|
|
// std.testing.log_level = .debug;
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{"clusterArns":["arn:aws:ecs:us-west-2:550620852718:cluster/web-applicationehjaf-cluster"],"nextToken":"czE0Og=="}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "e65322b2-0065-45f2-ba37-f822bb5ce395" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const ecs = (Services(.{.ecs}){}).ecs;
|
|
const call = try test_harness.client.call(ecs.list_clusters.Request{}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try test_harness.request_options.expectHeader("X-Amz-Target", "AmazonEC2ContainerServiceV20141113.ListClusters");
|
|
|
|
const parsed_body = try std.json.parseFromSlice(struct {
|
|
nextToken: ?[]const u8,
|
|
maxResults: ?u8,
|
|
}, testing.allocator, test_harness.request_options.request_body, .{});
|
|
defer parsed_body.deinit();
|
|
|
|
try testing.expectEqual(null, parsed_body.value.nextToken);
|
|
try testing.expectEqual(null, parsed_body.value.maxResults);
|
|
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("e65322b2-0065-45f2-ba37-f822bb5ce395", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 1), call.response.cluster_arns.?.len);
|
|
try std.testing.expectEqualStrings("arn:aws:ecs:us-west-2:550620852718:cluster/web-applicationehjaf-cluster", call.response.cluster_arns.?[0]);
|
|
}
|
|
test "rest_json_1_query_with_input: lambda listFunctions runtime" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{"Functions":[{"Description":"AWS CDK resource provider framework - onEvent (DevelopmentFrontendStack-g650u/com.amazonaws.cdk.custom-resources.amplify-asset-deployment-provider/amplify-asset-deployment-handler-provider)","TracingConfig":{"Mode":"PassThrough"},"VpcConfig":null,"SigningJobArn":null,"SnapStart":{"OptimizationStatus":"Off","ApplyOn":"None"},"RevisionId":"0c62fc74-a692-403d-9206-5fcbad406424","LastModified":"2023-03-01T18:13:15.704+0000","FileSystemConfigs":null,"FunctionName":"DevelopmentFrontendStack--amplifyassetdeploymentha-aZqB9IbZLIKU","Runtime":"nodejs14.x","Version":"$LATEST","PackageType":"Zip","LastUpdateStatus":null,"Layers":null,"FunctionArn":"arn:aws:lambda:us-west-2:550620852718:function:DevelopmentFrontendStack--amplifyassetdeploymentha-aZqB9IbZLIKU","KMSKeyArn":null,"MemorySize":128,"ImageConfigResponse":null,"LastUpdateStatusReason":null,"DeadLetterConfig":null,"Timeout":900,"Handler":"framework.onEvent","CodeSha256":"m4tt+M0l3p8bZvxIDj83dwGrwRW6atCfS/q8AiXCD3o=","Role":"arn:aws:iam::550620852718:role/DevelopmentFrontendStack-amplifyassetdeploymentha-1782JF7WAPXZ3","SigningProfileVersionArn":null,"MasterArn":null,"RuntimeVersionConfig":null,"CodeSize":4307,"State":null,"StateReason":null,"Environment":{"Variables":{"USER_ON_EVENT_FUNCTION_ARN":"arn:aws:lambda:us-west-2:550620852718:function:DevelopmentFrontendStack--amplifyassetdeploymenton-X9iZJSCSPYDH","WAITER_STATE_MACHINE_ARN":"arn:aws:states:us-west-2:550620852718:stateMachine:amplifyassetdeploymenthandlerproviderwaiterstatemachineB3C2FCBE-Ltggp5wBcHWO","USER_IS_COMPLETE_FUNCTION_ARN":"arn:aws:lambda:us-west-2:550620852718:function:DevelopmentFrontendStack--amplifyassetdeploymentis-jaHopLrSSARV"},"Error":null},"EphemeralStorage":{"Size":512},"StateReasonCode":null,"LastUpdateStatusReasonCode":null,"Architectures":["x86_64"]}],"NextMarker":"lslTXFcbLQKkb0vP9Kgh5hUL7C3VghELNGbWgZfxrRCk3eiDRMkct7D8EmptWfHSXssPdS7Bo66iQPTMpVOHZgANewpgGgFGGr4pVjd6VgLUO6qPe2EMAuNDBjUTxm8z6N28yhlUwEmKbrAV/m0k5qVzizwoxFwvyruMbuMx9kADFACSslcabxXl3/jDI4rfFnIsUVdzTLBgPF1hzwrE1f3lcdkBvUp+QgY+Pn3w5QuJmwsp/di8COzFemY89GgOHbLNqsrBsgR/ee2eXoJp0ZkKM4EcBK3HokqBzefLfgR02PnfNOdXwqTlhkSPW0TKiKGIYu3Bw7lSNrLd+q3+wEr7ZakqOQf0BVo3FMRhMHlVYgwUJzwi3ActyH2q6fuqGG1sS0B8Oa/prUpe5fmp3VaA3WpazioeHtrKF78JwCi6/nfQsrj/8ZtXGQOxlwEgvT1CIUaF+CdHY3biezrK0tRZNpkCtHnkPtF9lq2U7+UiKXSW9yzxT8P2b0M/Qh4IVdnw4rncQK/doYriAeOdrs1wjMEJnHWq9lAaEyipoxYcVr/z5+yaC6Gwxdg45p9X1vIAaYMf6IZxyFuua43SYi0Ls+IBk4VvpR2io7T0dCxHAr3WAo3D2dm0y8OsbM59"}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "c4025199-226f-4a16-bb1f-48618e9d2ea6" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const lambda = (Services(.{.lambda}){}).lambda;
|
|
const call = try test_harness.client.call(lambda.list_functions.Request{
|
|
.max_items = 1,
|
|
}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.GET, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/2015-03-31/functions?MaxItems=1", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings(
|
|
\\
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("c4025199-226f-4a16-bb1f-48618e9d2ea6", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 1), call.response.functions.?.len);
|
|
try std.testing.expectEqualStrings(
|
|
"DevelopmentFrontendStack--amplifyassetdeploymentha-aZqB9IbZLIKU",
|
|
call.response.functions.?[0].function_name.?,
|
|
);
|
|
}
|
|
test "rest_json_1_query_no_input: lambda listFunctions runtime" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response = @embedFile("test_rest_json_1_query_no_input.response"),
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "b2aad11f-36fc-4d0d-ae92-fe0167fb0f40" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const lambda = (Services(.{.lambda}){}).lambda;
|
|
const call = try test_harness.client.call(lambda.list_functions.Request{}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.GET, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/2015-03-31/functions", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings(
|
|
\\
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("b2aad11f-36fc-4d0d-ae92-fe0167fb0f40", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 24), call.response.functions.?.len);
|
|
try std.testing.expectEqualStrings(
|
|
"DevelopmentFrontendStack--amplifyassetdeploymentha-aZqB9IbZLIKU",
|
|
call.response.functions.?[0].function_name.?,
|
|
);
|
|
try std.testing.expectEqualStrings(
|
|
"amplify-login-create-auth-challenge-b4883e4c",
|
|
call.response.functions.?[12].function_name.?,
|
|
);
|
|
}
|
|
test "rest_json_1_work_with_lambda: lambda tagResource (only), to excercise zig issue 17015" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response = "",
|
|
.server_response_status = .no_content,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "a521e152-6e32-4e67-9fb3-abc94e34551b" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const lambda = (Services(.{.lambda}){}).lambda;
|
|
var tags = try std.ArrayList(@typeInfo(try typeForField(lambda.tag_resource.Request, "tags")).pointer.child).initCapacity(allocator, 1);
|
|
defer tags.deinit(allocator);
|
|
tags.appendAssumeCapacity(.{ .key = "Foo", .value = "Bar" });
|
|
const req = services.lambda.tag_resource.Request{ .resource = "arn:aws:lambda:us-west-2:550620852718:function:awsome-lambda-LambdaStackawsomeLambda", .tags = tags.items };
|
|
const call = try aws.Request(lambda.tag_resource).call(req, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
|
|
const parsed_body = try std.json.parseFromSlice(struct {
|
|
Tags: struct {
|
|
Foo: []const u8,
|
|
},
|
|
}, testing.allocator, test_harness.request_options.request_body, .{ .ignore_unknown_fields = true });
|
|
defer parsed_body.deinit();
|
|
|
|
try testing.expectEqualStrings("Bar", parsed_body.value.Tags.Foo);
|
|
|
|
// Due to 17015, we see %253A instead of %3A
|
|
try std.testing.expectEqualStrings("/2017-03-31/tags/arn%3Aaws%3Alambda%3Aus-west-2%3A550620852718%3Afunction%3Aawsome-lambda-LambdaStackawsomeLambda", test_harness.request_options.request_target);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("a521e152-6e32-4e67-9fb3-abc94e34551b", call.response_metadata.request_id);
|
|
}
|
|
test "rest_json_1_url_parameters_not_in_request: lambda update_function_code" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response = "{\"CodeSize\": 42}",
|
|
.server_response_status = .ok,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "a521e152-6e32-4e67-9fb3-abc94e34551b" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const lambda = (Services(.{.lambda}){}).lambda;
|
|
const architectures = [_][]const u8{"x86_64"};
|
|
const arches: [][]const u8 = @constCast(architectures[0..]);
|
|
const req = services.lambda.update_function_code.Request{
|
|
.function_name = "functionname",
|
|
.architectures = arches,
|
|
.zip_file = "zipfile",
|
|
};
|
|
const call = try aws.Request(lambda.update_function_code).call(req, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.PUT, test_harness.request_options.request_method);
|
|
|
|
const parsed_body = try std.json.parseFromSlice(struct {
|
|
ZipFile: []const u8,
|
|
Architectures: [][]const u8,
|
|
}, testing.allocator, test_harness.request_options.request_body, .{
|
|
.ignore_unknown_fields = true,
|
|
});
|
|
defer parsed_body.deinit();
|
|
|
|
try testing.expectEqualStrings("zipfile", parsed_body.value.ZipFile);
|
|
try testing.expectEqual(1, parsed_body.value.Architectures.len);
|
|
try testing.expectEqualStrings("x86_64", parsed_body.value.Architectures[0]);
|
|
|
|
// Due to 17015, we see %253A instead of %3A
|
|
try std.testing.expectEqualStrings("/2015-03-31/functions/functionname/code", test_harness.request_options.request_target);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("a521e152-6e32-4e67-9fb3-abc94e34551b", call.response_metadata.request_id);
|
|
}
|
|
test "ec2_query_no_input: EC2 describe regions" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response = @embedFile("test_ec2_query_no_input.response"),
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "text/xml;charset=UTF-8" },
|
|
.{ .name = "x-amzn-RequestId", .value = "4cdbdd69-800c-49b5-8474-ae4c17709782" },
|
|
},
|
|
.server_response_transfer_encoding = .chunked,
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const ec2 = (Services(.{.ec2}){}).ec2;
|
|
const call = try test_harness.client.call(ec2.describe_regions.Request{}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/?Action=DescribeRegions&Version=2016-11-15", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings(
|
|
\\Action=DescribeRegions&Version=2016-11-15
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("4cdbdd69-800c-49b5-8474-ae4c17709782", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 17), call.response.regions.?.len);
|
|
}
|
|
// LLVM hates this test. Depending on the platform, it will consume all memory
|
|
// on the compilation host. Windows x86_64 and Linux riscv64 seem to be a problem so far
|
|
// riscv64-linux also seems to have another problem with LLVM basically infinitely
|
|
// doing something. My guess is the @embedFile is freaking out LLVM
|
|
test "ec2_query_with_input: EC2 describe instances" {
|
|
if (builtin.cpu.arch == .riscv64 and builtin.os.tag == .linux) return error.SkipZigTest;
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response = @embedFile("test_ec2_query_with_input.response"),
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "text/xml;charset=UTF-8" },
|
|
.{ .name = "x-amzn-RequestId", .value = "150a14cc-785d-476f-a4c9-2aa4d03b14e2" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const ec2 = (Services(.{.ec2}){}).ec2;
|
|
const call = try test_harness.client.call(ec2.describe_instances.Request{
|
|
.max_results = 6,
|
|
}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/?Action=DescribeInstances&Version=2016-11-15", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings(
|
|
\\Action=DescribeInstances&Version=2016-11-15&MaxResults=6
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("150a14cc-785d-476f-a4c9-2aa4d03b14e2", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 6), call.response.reservations.?.len);
|
|
try std.testing.expectEqualStrings("i-0212d7d1f62b96676", call.response.reservations.?[1].instances.?[0].instance_id.?);
|
|
try std.testing.expectEqualStrings("123456789012:found-me", call.response.reservations.?[1].instances.?[0].tags.?[0].value.?);
|
|
}
|
|
test "rest_xml_with_input_s3: S3 create bucket" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\
|
|
,
|
|
.server_response_headers = &.{ // I don't see content type coming back in actual S3 requests
|
|
.{ .name = "x-amzn-RequestId", .value = "9PEYBAZ9J7TPRX43" },
|
|
.{ .name = "x-amz-id-2", .value = "u7lzgW0tIyRP15vSUsVOXxJ37OfVCO8lZmLIVuqeq5EE4tNp9qebb5fy+/kendlZpR4YQE+y4Xg=" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
errdefer test_harness.creds.deinit();
|
|
const options = try test_harness.start();
|
|
const s3 = (Services(.{.s3}){}).s3;
|
|
const call = try test_harness.client.call(s3.create_bucket.Request{
|
|
.bucket = "",
|
|
.create_bucket_configuration = .{
|
|
.location_constraint = "us-west-2",
|
|
},
|
|
}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.PUT, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings(
|
|
\\<CreateBucketConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
|
|
\\ <LocationConstraint>us-west-2</LocationConstraint>
|
|
\\</CreateBucketConfiguration>
|
|
, test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings(
|
|
"9PEYBAZ9J7TPRX43, host_id: u7lzgW0tIyRP15vSUsVOXxJ37OfVCO8lZmLIVuqeq5EE4tNp9qebb5fy+/kendlZpR4YQE+y4Xg=",
|
|
call.response_metadata.request_id,
|
|
);
|
|
}
|
|
test "rest_xml_no_input: S3 list buckets" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\<ListAllMyBucketsResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>3367189aa775bd98da38e55093705f2051443c1e775fc0971d6d77387a47c8d0</ID><DisplayName>emilerch+sub1</DisplayName></Owner><Buckets><Bucket><Name>550620852718-backup</Name><CreationDate>2020-06-17T16:26:51.000Z</CreationDate></Bucket><Bucket><Name>amplify-letmework-staging-185741-deployment</Name><CreationDate>2023-03-10T18:57:49.000Z</CreationDate></Bucket><Bucket><Name>aws-cloudtrail-logs-550620852718-224022a7</Name><CreationDate>2021-06-21T18:32:44.000Z</CreationDate></Bucket><Bucket><Name>aws-sam-cli-managed-default-samclisourcebucket-1gy0z00mj47xe</Name><CreationDate>2021-10-05T16:38:07.000Z</CreationDate></Bucket><Bucket><Name>awsomeprojectstack-pipelineartifactsbucketaea9a05-1uzwo6c86ecr</Name><CreationDate>2021-10-05T22:55:09.000Z</CreationDate></Bucket><Bucket><Name>cdk-hnb659fds-assets-550620852718-us-west-2</Name><CreationDate>2023-02-28T21:49:36.000Z</CreationDate></Bucket><Bucket><Name>cf-templates-12iy6putgdxtk-us-west-2</Name><CreationDate>2020-06-26T02:31:59.000Z</CreationDate></Bucket><Bucket><Name>codepipeline-us-west-2-46714083637</Name><CreationDate>2021-09-14T18:43:07.000Z</CreationDate></Bucket><Bucket><Name>elasticbeanstalk-us-west-2-550620852718</Name><CreationDate>2022-04-15T16:22:42.000Z</CreationDate></Bucket><Bucket><Name>lobo-west</Name><CreationDate>2021-06-21T17:17:22.000Z</CreationDate></Bucket><Bucket><Name>lobo-west-2</Name><CreationDate>2021-11-19T20:12:31.000Z</CreationDate></Bucket><Bucket><Name>logging-backup-550620852718-us-east-2</Name><CreationDate>2022-05-29T21:55:16.000Z</CreationDate></Bucket><Bucket><Name>mysfitszj3t6webstack-hostingbucketa91a61fe-1ep3ezkgwpxr0</Name><CreationDate>2023-03-01T04:53:55.000Z</CreationDate></Bucket></Buckets></ListAllMyBucketsResult>
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/xml" },
|
|
.{ .name = "x-amzn-RequestId", .value = "9PEYBAZ9J7TPRX43" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const s3 = (Services(.{.s3}){}).s3;
|
|
const call = try test_harness.client.call(s3.list_buckets.Request{}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.GET, test_harness.request_options.request_method);
|
|
// This changed in rev 830202d722c904c7e3da40e8dde7b9338d08752c of the go sdk, and
|
|
// contrary to the documentation, a query string argument was added. My guess is that
|
|
// there is no functional reason, and that this is strictly for some AWS reporting function.
|
|
// Alternatively, it could be to support some customization mechanism, as the commit
|
|
// title of that commit is "Merge customizations for S3"
|
|
try std.testing.expectEqualStrings("/?x-id=ListBuckets", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings("", test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("9PEYBAZ9J7TPRX43", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 13), call.response.buckets.?.len);
|
|
}
|
|
test "rest_xml_anything_but_s3: CloudFront list key groups" {
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{"Items":null,"MaxItems":100,"NextMarker":null,"Quantity":0}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "d3382082-5291-47a9-876b-8df3accbb7ea" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const cloudfront = (Services(.{.cloudfront}){}).cloudfront;
|
|
const call = try test_harness.client.call(cloudfront.list_key_groups.Request{}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.GET, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/2020-05-31/key-group", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings("", test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("d3382082-5291-47a9-876b-8df3accbb7ea", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(i64, 100), call.response.key_group_list.?.max_items);
|
|
}
|
|
test "rest_xml_with_input: S3 put object" {
|
|
// const old = std.testing.log_level;
|
|
// defer std.testing.log_level = old;
|
|
// std.testing.log_level = .debug;
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response = "",
|
|
.server_response_headers = &.{
|
|
// .{ "Content-Type", "application/xml" },
|
|
.{ .name = "x-amzn-RequestId", .value = "9PEYBAZ9J7TPRX43" },
|
|
.{ .name = "x-amz-id-2", .value = "jdRDo30t7Ge9lf6F+4WYpg+YKui8z0mz2+rwinL38xDZzvloJqrmpCAiKG375OSvHA9OBykJS44=" },
|
|
.{ .name = "x-amz-server-side-encryption", .value = "AES256" },
|
|
.{ .name = "ETag", .value = "37b51d194a7513e45b56f6524f2d51f2" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const s3opts = aws.Options{
|
|
.region = "us-west-2",
|
|
.client = options.client,
|
|
.signing_time = TestSetup.signing_time,
|
|
};
|
|
const result = try aws.Request(services.s3.put_object).call(.{
|
|
.bucket = "mysfitszj3t6webstack-hostingbucketa91a61fe-1ep3ezkgwpxr0",
|
|
.key = "i/am/a/teapot/foo",
|
|
.content_type = "text/plain",
|
|
.body = "bar",
|
|
.storage_class = "STANDARD",
|
|
}, s3opts);
|
|
defer result.deinit();
|
|
for (test_harness.request_options.request_headers) |header| {
|
|
std.log.info("Request header: {s}: {s}", .{ header.name, header.value });
|
|
}
|
|
try test_harness.request_options.expectNoDuplicateHeaders();
|
|
std.log.info("PutObject Request id: {s}", .{result.response_metadata.request_id});
|
|
std.log.info("PutObject etag: {s}", .{result.response.e_tag.?});
|
|
//mysfitszj3t6webstack-hostingbucketa91a61fe-1ep3ezkgwpxr0.s3.us-west-2.amazonaws.com
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.PUT, test_harness.request_options.request_method);
|
|
// I don't think this will work since we're overriding the url
|
|
// try test_harness.request_options.expectHeader("Host", "mysfitszj3t6webstack-hostingbucketa91a61fe-1ep3ezkgwpxr0.s3.us-west-2.amazonaws.com");
|
|
try test_harness.request_options.expectHeader("x-amz-storage-class", "STANDARD");
|
|
try std.testing.expectEqualStrings("/mysfitszj3t6webstack-hostingbucketa91a61fe-1ep3ezkgwpxr0/i/am/a/teapot/foo?x-id=PutObject", test_harness.request_options.request_target);
|
|
try std.testing.expectEqualStrings("bar", test_harness.request_options.request_body);
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("9PEYBAZ9J7TPRX43, host_id: jdRDo30t7Ge9lf6F+4WYpg+YKui8z0mz2+rwinL38xDZzvloJqrmpCAiKG375OSvHA9OBykJS44=", result.response_metadata.request_id);
|
|
try std.testing.expectEqualStrings("AES256", result.response.server_side_encryption.?);
|
|
try std.testing.expectEqualStrings("37b51d194a7513e45b56f6524f2d51f2", result.response.e_tag.?);
|
|
}
|
|
test "raw ECR timestamps" {
|
|
// This is a way to test the json parsing. Ultimately the more robust tests
|
|
// should be preferred, but in this case we were tracking down an issue
|
|
// for which the root cause was the incorrect type being passed to the parse
|
|
// routine
|
|
const allocator = std.testing.allocator;
|
|
const ecr = (Services(.{.ecr}){}).ecr;
|
|
const options = json.ParseOptions{
|
|
.allocator = allocator,
|
|
.allow_camel_case_conversion = true, // new option
|
|
.allow_snake_case_conversion = true, // new option
|
|
.allow_unknown_fields = true, // new option. Cannot yet handle non-struct fields though
|
|
.allow_missing_fields = false, // new option. Cannot yet handle non-struct fields though
|
|
};
|
|
var stream = json.TokenStream.init(
|
|
\\{"authorizationData":[{"authorizationToken":"***","expiresAt":1.7385984915E9,"proxyEndpoint":"https://146325435496.dkr.ecr.us-west-2.amazonaws.com"}]}
|
|
);
|
|
const ptr = try json.parse(ecr.get_authorization_token.Response, &stream, options);
|
|
defer json.parseFree(ecr.get_authorization_token.Response, ptr, options);
|
|
}
|
|
test "json_1_1: ECR timestamps" {
|
|
// See: https://github.com/elerch/aws-sdk-for-zig/issues/5
|
|
// const old = std.testing.log_level;
|
|
// defer std.testing.log_level = old;
|
|
// std.testing.log_level = .debug;
|
|
const allocator = std.testing.allocator;
|
|
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{"authorizationData":[{"authorizationToken":"***","expiresAt":"2022-05-17T06:56:13.652000+00:00","proxyEndpoint":"https://146325435496.dkr.ecr.us-west-2.amazonaws.com"}]}
|
|
// \\{"authorizationData":[{"authorizationToken":"***","expiresAt":1.738598491557E9,"proxyEndpoint":"https://146325435496.dkr.ecr.us-west-2.amazonaws.com"}]}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "QBI72OUIN8U9M9AG6PCSADJL4JVV4KQNSO5AEMVJF66Q9ASUAAJG" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
const options = try test_harness.start();
|
|
const ecr = (Services(.{.ecr}){}).ecr;
|
|
std.log.debug("Typeof response {}", .{@TypeOf(ecr.get_authorization_token.Response{})});
|
|
const call = try test_harness.client.call(ecr.get_authorization_token.Request{}, options);
|
|
defer call.deinit();
|
|
test_harness.stop();
|
|
// Request expectations
|
|
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
|
try std.testing.expectEqualStrings("/", test_harness.request_options.request_target);
|
|
try test_harness.request_options.expectHeader("X-Amz-Target", "AmazonEC2ContainerRegistry_V20150921.GetAuthorizationToken");
|
|
// Response expectations
|
|
try std.testing.expectEqualStrings("QBI72OUIN8U9M9AG6PCSADJL4JVV4KQNSO5AEMVJF66Q9ASUAAJG", call.response_metadata.request_id);
|
|
try std.testing.expectEqual(@as(usize, 1), call.response.authorization_data.?.len);
|
|
try std.testing.expectEqualStrings("***", call.response.authorization_data.?[0].authorization_token.?);
|
|
try std.testing.expectEqualStrings("https://146325435496.dkr.ecr.us-west-2.amazonaws.com", call.response.authorization_data.?[0].proxy_endpoint.?);
|
|
// try std.testing.expectEqual(@as(i64, 1.73859841557E9), call.response.authorization_data.?[0].expires_at.?);
|
|
|
|
const zeit = @import("zeit");
|
|
const expected_ins = try zeit.instant(.{
|
|
.source = .{ .iso8601 = "2022-05-17T06:56:13.652000+00:00" },
|
|
});
|
|
const expected_ts: date.Timestamp = @enumFromInt(expected_ins.timestamp);
|
|
|
|
try std.testing.expectEqual(expected_ts, call.response.authorization_data.?[0].expires_at.?);
|
|
}
|
|
var test_error_log_enabled = true;
|
|
test "test server timeout works" {
|
|
// const old = std.testing.log_level;
|
|
// defer std.testing.log_level = old;
|
|
// std.testing.log_level = .debug;
|
|
// defer std.testing.log_level = old;
|
|
// std.testing.log_level = .debug;
|
|
test_error_log_enabled = false;
|
|
defer test_error_log_enabled = true;
|
|
std.log.debug("test start", .{});
|
|
const allocator = std.testing.allocator;
|
|
var test_harness = TestSetup.init(.{
|
|
.allocator = allocator,
|
|
.server_response =
|
|
\\{}
|
|
,
|
|
.server_response_headers = &.{
|
|
.{ .name = "Content-Type", .value = "application/json" },
|
|
.{ .name = "x-amzn-RequestId", .value = "QBI72OUIN8U9M9AG6PCSADJL4JVV4KQNSO5AEMVJF66Q9ASUAAJG" },
|
|
},
|
|
});
|
|
defer test_harness.deinit();
|
|
defer test_harness.creds.deinit(); // Usually this gets done during the call,
|
|
// but we're purposely not making a call
|
|
// here, so we have to deinit() manually
|
|
_ = try test_harness.start();
|
|
std.log.debug("harness started", .{});
|
|
test_harness.stop();
|
|
std.log.debug("test complete", .{});
|
|
}
|
|
|
|
const testing = std.testing;
|
|
|
|
test "jsonStringify: structure + enums" {
|
|
const request = services.media_convert.PutPolicyRequest{
|
|
.policy = .{
|
|
.http_inputs = "foo",
|
|
.https_inputs = "bar",
|
|
.s3_inputs = "baz",
|
|
},
|
|
};
|
|
|
|
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
|
defer arena.deinit();
|
|
|
|
const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
|
|
defer std.testing.allocator.free(request_json);
|
|
|
|
const parsed = try std.json.parseFromSlice(struct {
|
|
policy: struct {
|
|
httpInputs: []const u8,
|
|
httpsInputs: []const u8,
|
|
s3Inputs: []const u8,
|
|
},
|
|
}, testing.allocator, request_json, .{});
|
|
defer parsed.deinit();
|
|
|
|
try testing.expectEqualStrings("foo", parsed.value.policy.httpInputs);
|
|
try testing.expectEqualStrings("bar", parsed.value.policy.httpsInputs);
|
|
try testing.expectEqualStrings("baz", parsed.value.policy.s3Inputs);
|
|
}
|
|
|
|
test "jsonStringify: strings" {
|
|
const request = services.media_convert.AssociateCertificateRequest{
|
|
.arn = "1234",
|
|
};
|
|
|
|
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
|
defer arena.deinit();
|
|
|
|
const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
|
|
defer std.testing.allocator.free(request_json);
|
|
|
|
try testing.expectEqualStrings("{\"arn\":\"1234\"}", request_json);
|
|
}
|
|
|
|
test "jsonStringify" {
|
|
var tags = [_]services.media_convert.MapOfStringKeyValue{
|
|
.{
|
|
.key = "foo",
|
|
.value = "bar",
|
|
},
|
|
};
|
|
|
|
const request = services.media_convert.TagResourceRequest{
|
|
.arn = "1234",
|
|
.tags = &tags,
|
|
};
|
|
|
|
var arena = std.heap.ArenaAllocator.init(testing.allocator);
|
|
defer arena.deinit();
|
|
|
|
const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
|
|
defer std.testing.allocator.free(request_json);
|
|
|
|
const json_parsed = try std.json.parseFromSlice(struct {
|
|
arn: []const u8,
|
|
tags: struct {
|
|
foo: []const u8,
|
|
},
|
|
}, testing.allocator, request_json, .{});
|
|
defer json_parsed.deinit();
|
|
|
|
try testing.expectEqualStrings("1234", json_parsed.value.arn);
|
|
try testing.expectEqualStrings("bar", json_parsed.value.tags.foo);
|
|
}
|
|
|
|
test "jsonStringify nullable object" {
|
|
// structure is not null
|
|
{
|
|
const request = services.lambda.CreateAliasRequest{
|
|
.function_name = "foo",
|
|
.function_version = "bar",
|
|
.name = "baz",
|
|
.routing_config = services.lambda.AliasRoutingConfiguration{
|
|
.additional_version_weights = null,
|
|
},
|
|
};
|
|
|
|
const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
|
|
defer std.testing.allocator.free(request_json);
|
|
|
|
const json_parsed = try std.json.parseFromSlice(struct {
|
|
FunctionName: []const u8,
|
|
FunctionVersion: []const u8,
|
|
Name: []const u8,
|
|
RoutingConfig: struct {
|
|
AdditionalVersionWeights: ?struct {},
|
|
},
|
|
}, testing.allocator, request_json, .{ .ignore_unknown_fields = true });
|
|
defer json_parsed.deinit();
|
|
|
|
try testing.expectEqualStrings("foo", json_parsed.value.FunctionName);
|
|
try testing.expectEqualStrings("bar", json_parsed.value.FunctionVersion);
|
|
try testing.expectEqualStrings("baz", json_parsed.value.Name);
|
|
try testing.expectEqual(null, json_parsed.value.RoutingConfig.AdditionalVersionWeights);
|
|
}
|
|
|
|
// structure is null
|
|
{
|
|
const request = services.kms.DecryptRequest{
|
|
.key_id = "foo",
|
|
.ciphertext_blob = "bar",
|
|
};
|
|
|
|
const request_json = try std.fmt.allocPrint(std.testing.allocator, "{f}", .{std.json.fmt(request, .{})});
|
|
defer std.testing.allocator.free(request_json);
|
|
|
|
const json_parsed = try std.json.parseFromSlice(struct {
|
|
KeyId: []const u8,
|
|
CiphertextBlob: []const u8,
|
|
}, testing.allocator, request_json, .{ .ignore_unknown_fields = true });
|
|
defer json_parsed.deinit();
|
|
|
|
try testing.expectEqualStrings("foo", json_parsed.value.KeyId);
|
|
try testing.expectEqualStrings("bar", json_parsed.value.CiphertextBlob);
|
|
}
|
|
}
|