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 {
|
||||
// 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"
|
||||
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 free_body = false;
|
||||
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("8f0d54da-1230-40f7-b4ac-95015c4b84cd", call.response_metadata.request_id);
|
||||
}
|
||||
test "query_with_input: sqs listQueues runtime" {
|
||||
if (true) return error.SkipZigTest; // sqs switched from query to json recently
|
||||
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 = allocator,
|
||||
.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{
|
||||
.{ "Content-Type", "application/json" },
|
||||
.{ "x-amzn-RequestId", "a85e390b-b866-590e-8cae-645f2bbe59c5" },
|
||||
.{ "Content-Type", "text/xml" },
|
||||
.{ "x-amzn-RequestId", "ec85bf29-1ef0-459a-930e-6446dd14a286" },
|
||||
}),
|
||||
});
|
||||
defer test_harness.deinit();
|
||||
const options = try test_harness.start();
|
||||
const sqs = (Services(.{.sqs}){}).sqs;
|
||||
const call = try test_harness.client.call(sqs.list_queues.Request{
|
||||
.queue_name_prefix = "s",
|
||||
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();
|
||||
|
@ -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.expectEqualStrings("/", test_harness.request_options.request_target);
|
||||
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);
|
||||
// Response expectations
|
||||
// TODO: We can get a lot better with this under test
|
||||
try std.testing.expect(call.response.queue_urls == null);
|
||||
try std.testing.expectEqualStrings("a85e390b-b866-590e-8cae-645f2bbe59c5", call.response_metadata.request_id);
|
||||
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;
|
||||
|
|
|
@ -4,6 +4,8 @@ const date = @import("date.zig");
|
|||
|
||||
const log = std.log.scoped(.xml_shaper);
|
||||
|
||||
pub const Element = xml.Element;
|
||||
|
||||
pub fn Parsed(comptime T: type) type {
|
||||
return struct {
|
||||
// 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 {
|
||||
allocator: ?std.mem.Allocator = 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) {
|
||||
|
@ -86,7 +90,8 @@ pub fn parse(comptime T: type, source: []const u8, options: ParseOptions) !Parse
|
|||
.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 {
|
||||
|
@ -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"
|
||||
// in the if statement above will trigger assertion failure
|
||||
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);
|
||||
@field(r, field.name) = null;
|
||||
fields_set = fields_set + 1;
|
||||
|
@ -625,12 +631,65 @@ test "can parse something serious" {
|
|||
\\</DescribeRegionsResponse>
|
||||
;
|
||||
// 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();
|
||||
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("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" {
|
||||
// std.testing.log_level = .debug;
|
||||
|
|
Loading…
Reference in New Issue
Block a user