switch sqs query test (json) with sts query test (xml) and fix response parsing
All checks were successful
AWS-Zig Build / build-zig-0.11.0-amd64-host (push) Successful in 5m22s
All checks were successful
AWS-Zig Build / build-zig-0.11.0-amd64-host (push) Successful in 5m22s
This commit is contained in:
parent
55298f7575
commit
6df02b1074
57
src/aws.zig
57
src/aws.zig
|
@ -457,6 +457,30 @@ pub fn Request(comptime request_action: anytype) type {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn findResult(element: *xml_shaper.Element, options: xml_shaper.ParseOptions) *xml_shaper.Element {
|
||||||
|
_ = options;
|
||||||
|
// We're looking for a very specific pattern here. We want only two direct
|
||||||
|
// children. The first one must end with "Result", and the second should
|
||||||
|
// be our ResponseMetadata node
|
||||||
|
var children = element.elements();
|
||||||
|
var found_metadata = false;
|
||||||
|
var result_child: ?*xml_shaper.Element = null;
|
||||||
|
var inx: usize = 0;
|
||||||
|
while (children.next()) |child| : (inx += 1) {
|
||||||
|
if (std.mem.eql(u8, child.tag, "ResponseMetadata")) {
|
||||||
|
found_metadata = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (std.mem.endsWith(u8, child.tag, "Result")) {
|
||||||
|
result_child = child;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inx > 1) return element;
|
||||||
|
return element; // It should only be those two
|
||||||
|
}
|
||||||
|
return result_child orelse element;
|
||||||
|
}
|
||||||
|
|
||||||
fn xmlReturn(request: awshttp.HttpRequest, options: Options, result: awshttp.HttpResult) !FullResponseType {
|
fn xmlReturn(request: awshttp.HttpRequest, options: Options, result: awshttp.HttpResult) !FullResponseType {
|
||||||
// Server shape be all like:
|
// Server shape be all like:
|
||||||
//
|
//
|
||||||
|
@ -481,7 +505,7 @@ pub fn Request(comptime request_action: anytype) type {
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// Big thing is that requestid, which we'll need to fetch "manually"
|
// Big thing is that requestid, which we'll need to fetch "manually"
|
||||||
const xml_options = xml_shaper.ParseOptions{ .allocator = options.client.allocator };
|
const xml_options = xml_shaper.ParseOptions{ .allocator = options.client.allocator, .elementToParse = findResult };
|
||||||
var body: []const u8 = result.body;
|
var body: []const u8 = result.body;
|
||||||
var free_body = false;
|
var free_body = false;
|
||||||
if (result.body.len < 20) {
|
if (result.body.len < 20) {
|
||||||
|
@ -1584,24 +1608,31 @@ test "query_no_input: sts getCallerIdentity comptime" {
|
||||||
try std.testing.expectEqualStrings("123456789012", call.response.account.?);
|
try std.testing.expectEqualStrings("123456789012", call.response.account.?);
|
||||||
try std.testing.expectEqualStrings("8f0d54da-1230-40f7-b4ac-95015c4b84cd", call.response_metadata.request_id);
|
try std.testing.expectEqualStrings("8f0d54da-1230-40f7-b4ac-95015c4b84cd", call.response_metadata.request_id);
|
||||||
}
|
}
|
||||||
test "query_with_input: sqs listQueues runtime" {
|
test "query_with_input: sts getAccessKeyInfo runtime" {
|
||||||
if (true) return error.SkipZigTest; // sqs switched from query to json recently
|
// sqs switched from query to json in aws sdk for go v2 commit f5a08768ef820ff5efd62a49ba50c61c9ca5dbcb
|
||||||
const allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
var test_harness = TestSetup.init(allocator, .{
|
var test_harness = TestSetup.init(allocator, .{
|
||||||
.allocator = allocator,
|
.allocator = allocator,
|
||||||
.server_response =
|
.server_response =
|
||||||
\\{"ListQueuesResponse":{"ListQueuesResult":{"NextExclusiveStartQueueName":null,"NextToken":null,"queueUrls":null},"ResponseMetadata":{"RequestId":"a85e390b-b866-590e-8cae-645f2bbe59c5"}}}
|
\\<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 = @constCast(&[_][2][]const u8{
|
.server_response_headers = @constCast(&[_][2][]const u8{
|
||||||
.{ "Content-Type", "application/json" },
|
.{ "Content-Type", "text/xml" },
|
||||||
.{ "x-amzn-RequestId", "a85e390b-b866-590e-8cae-645f2bbe59c5" },
|
.{ "x-amzn-RequestId", "ec85bf29-1ef0-459a-930e-6446dd14a286" },
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
defer test_harness.deinit();
|
defer test_harness.deinit();
|
||||||
const options = try test_harness.start();
|
const options = try test_harness.start();
|
||||||
const sqs = (Services(.{.sqs}){}).sqs;
|
const sts = (Services(.{.sts}){}).sts;
|
||||||
const call = try test_harness.client.call(sqs.list_queues.Request{
|
const call = try test_harness.client.call(sts.get_access_key_info.Request{
|
||||||
.queue_name_prefix = "s",
|
.access_key_id = "ASIAYAM4POHXJNKTYFUN",
|
||||||
}, options);
|
}, options);
|
||||||
defer call.deinit();
|
defer call.deinit();
|
||||||
test_harness.stop();
|
test_harness.stop();
|
||||||
|
@ -1609,12 +1640,12 @@ test "query_with_input: sqs listQueues runtime" {
|
||||||
try std.testing.expectEqual(std.http.Method.POST, test_harness.request_options.request_method);
|
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("/", test_harness.request_options.request_target);
|
||||||
try std.testing.expectEqualStrings(
|
try std.testing.expectEqualStrings(
|
||||||
\\Action=ListQueues&Version=2012-11-05&QueueNamePrefix=s
|
\\Action=GetAccessKeyInfo&Version=2011-06-15&AccessKeyId=ASIAYAM4POHXJNKTYFUN
|
||||||
, test_harness.request_options.request_body);
|
, test_harness.request_options.request_body);
|
||||||
// Response expectations
|
// Response expectations
|
||||||
// TODO: We can get a lot better with this under test
|
try std.testing.expect(call.response.account != null);
|
||||||
try std.testing.expect(call.response.queue_urls == null);
|
try std.testing.expectEqualStrings("123456789012", call.response.account.?);
|
||||||
try std.testing.expectEqualStrings("a85e390b-b866-590e-8cae-645f2bbe59c5", call.response_metadata.request_id);
|
try std.testing.expectEqualStrings("ec85bf29-1ef0-459a-930e-6446dd14a286", call.response_metadata.request_id);
|
||||||
}
|
}
|
||||||
test "json_1_0_query_with_input: dynamodb listTables runtime" {
|
test "json_1_0_query_with_input: dynamodb listTables runtime" {
|
||||||
const allocator = std.testing.allocator;
|
const allocator = std.testing.allocator;
|
||||||
|
|
|
@ -4,6 +4,8 @@ const date = @import("date.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.xml_shaper);
|
const log = std.log.scoped(.xml_shaper);
|
||||||
|
|
||||||
|
pub const Element = xml.Element;
|
||||||
|
|
||||||
pub fn Parsed(comptime T: type) type {
|
pub fn Parsed(comptime T: type) type {
|
||||||
return struct {
|
return struct {
|
||||||
// Forcing an arean allocator isn't my favorite choice here, but
|
// Forcing an arean allocator isn't my favorite choice here, but
|
||||||
|
@ -70,6 +72,8 @@ fn deinitObject(allocator: std.mem.Allocator, obj: anytype) void {
|
||||||
pub const ParseOptions = struct {
|
pub const ParseOptions = struct {
|
||||||
allocator: ?std.mem.Allocator = null,
|
allocator: ?std.mem.Allocator = null,
|
||||||
match_predicate_ptr: ?*const fn (a: []const u8, b: []const u8, options: xml.PredicateOptions) anyerror!bool = null,
|
match_predicate_ptr: ?*const fn (a: []const u8, b: []const u8, options: xml.PredicateOptions) anyerror!bool = null,
|
||||||
|
/// defines a function to use to locate an element other than the root of the document for parsing
|
||||||
|
elementToParse: ?*const fn (element: *Element, options: ParseOptions) *Element = null,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn parse(comptime T: type, source: []const u8, options: ParseOptions) !Parsed(T) {
|
pub fn parse(comptime T: type, source: []const u8, options: ParseOptions) !Parsed(T) {
|
||||||
|
@ -86,7 +90,8 @@ pub fn parse(comptime T: type, source: []const u8, options: ParseOptions) !Parse
|
||||||
.match_predicate_ptr = options.match_predicate_ptr,
|
.match_predicate_ptr = options.match_predicate_ptr,
|
||||||
};
|
};
|
||||||
|
|
||||||
return Parsed(T).init(arena_allocator, try parseInternal(T, parsed.root, opts), parsed);
|
const root = if (options.elementToParse) |e| e(parsed.root, opts) else parsed.root;
|
||||||
|
return Parsed(T).init(arena_allocator, try parseInternal(T, root, opts), parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parseInternal(comptime T: type, element: *xml.Element, options: ParseOptions) !T {
|
fn parseInternal(comptime T: type, element: *xml.Element, options: ParseOptions) !T {
|
||||||
|
@ -244,6 +249,7 @@ fn parseInternal(comptime T: type, element: *xml.Element, options: ParseOptions)
|
||||||
// Zig compiler bug circa 0.9.0. Using "and !found_value"
|
// Zig compiler bug circa 0.9.0. Using "and !found_value"
|
||||||
// in the if statement above will trigger assertion failure
|
// in the if statement above will trigger assertion failure
|
||||||
if (!found_value) {
|
if (!found_value) {
|
||||||
|
log.debug("Child element not found, but field optional. Setting {s}=null", .{field.name});
|
||||||
// @compileLog("Optional: Field name ", field.name, ", type ", field.type);
|
// @compileLog("Optional: Field name ", field.name, ", type ", field.type);
|
||||||
@field(r, field.name) = null;
|
@field(r, field.name) = null;
|
||||||
fields_set = fields_set + 1;
|
fields_set = fields_set + 1;
|
||||||
|
@ -625,12 +631,65 @@ test "can parse something serious" {
|
||||||
\\</DescribeRegionsResponse>
|
\\</DescribeRegionsResponse>
|
||||||
;
|
;
|
||||||
// const ServerResponse = struct { DescribeRegionsResponse: describe_regions.Response, };
|
// const ServerResponse = struct { DescribeRegionsResponse: describe_regions.Response, };
|
||||||
const parsed_data = try parse(describe_regions.Response, data, .{ .allocator = allocator });
|
const parsed_data = try parse(describe_regions.Response, data, .{ .allocator = allocator, .elementToParse = findResult });
|
||||||
defer parsed_data.deinit();
|
defer parsed_data.deinit();
|
||||||
try testing.expect(parsed_data.parsed_value.regions != null);
|
try testing.expect(parsed_data.parsed_value.regions != null);
|
||||||
try testing.expectEqualStrings("eu-north-1", parsed_data.parsed_value.regions.?[0].region_name.?);
|
try testing.expectEqualStrings("eu-north-1", parsed_data.parsed_value.regions.?[0].region_name.?);
|
||||||
try testing.expectEqualStrings("ec2.eu-north-1.amazonaws.com", parsed_data.parsed_value.regions.?[0].endpoint.?);
|
try testing.expectEqualStrings("ec2.eu-north-1.amazonaws.com", parsed_data.parsed_value.regions.?[0].endpoint.?);
|
||||||
}
|
}
|
||||||
|
const StsGetAccesskeyInfoResponse: type = struct {
|
||||||
|
account: ?[]const u8 = null,
|
||||||
|
|
||||||
|
pub fn fieldNameFor(_: @This(), comptime field_name: []const u8) []const u8 {
|
||||||
|
const mappings = .{
|
||||||
|
.account = "Account",
|
||||||
|
};
|
||||||
|
return @field(mappings, field_name);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
fn findResult(element: *xml.Element, options: ParseOptions) *xml.Element {
|
||||||
|
_ = options;
|
||||||
|
// We're looking for a very specific pattern here. We want only two direct
|
||||||
|
// children. The first one must end with "Result", and the second should
|
||||||
|
// be our ResponseMetadata node
|
||||||
|
var children = element.elements();
|
||||||
|
var found_metadata = false;
|
||||||
|
var result_child: ?*xml.Element = null;
|
||||||
|
var inx: usize = 0;
|
||||||
|
while (children.next()) |child| : (inx += 1) {
|
||||||
|
if (std.mem.eql(u8, child.tag, "ResponseMetadata")) {
|
||||||
|
found_metadata = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (std.mem.endsWith(u8, child.tag, "Result")) {
|
||||||
|
result_child = child;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (inx > 1) return element;
|
||||||
|
return element; // It should only be those two
|
||||||
|
}
|
||||||
|
return result_child orelse element;
|
||||||
|
}
|
||||||
|
test "can parse a result within a response" {
|
||||||
|
log.debug("", .{});
|
||||||
|
|
||||||
|
const allocator = std.testing.allocator;
|
||||||
|
const data =
|
||||||
|
\\<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>
|
||||||
|
;
|
||||||
|
const parsed_data = try parse(StsGetAccesskeyInfoResponse, data, .{ .allocator = allocator, .elementToParse = findResult });
|
||||||
|
defer parsed_data.deinit();
|
||||||
|
// Response expectations
|
||||||
|
try std.testing.expect(parsed_data.parsed_value.account != null);
|
||||||
|
try std.testing.expectEqualStrings("123456789012", parsed_data.parsed_value.account.?);
|
||||||
|
}
|
||||||
|
|
||||||
test "compiler assertion failure 2" {
|
test "compiler assertion failure 2" {
|
||||||
// std.testing.log_level = .debug;
|
// std.testing.log_level = .debug;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user