Skip to content
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

Introduce DefaultStatusCodeResponse #2002

Merged
merged 30 commits into from
Jun 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
75eebc7
Introduced new default status code response type
TharmiganK May 13, 2024
a1ba51b
Add default status code response binding support
TharmiganK May 13, 2024
9ead5cd
Fix check style issue
TharmiganK May 13, 2024
7369c6d
[Automated] Update the native jar versions
TharmiganK May 13, 2024
53a9e86
[Automated] Update the native jar versions
TharmiganK May 13, 2024
0f49f1e
Fix data-binding issue with no content
TharmiganK May 13, 2024
1000597
[Automated] Update the native jar versions
TharmiganK May 13, 2024
12eae0f
Merge branch 'master' into default-status-res
TharmiganK May 14, 2024
d803971
Fix default status code object creation
TharmiganK May 14, 2024
d75bf4c
Add client test cases
TharmiganK May 14, 2024
8ed3431
Add service test cases
TharmiganK May 14, 2024
64407e8
Update change log
TharmiganK May 14, 2024
4ddaf25
Update ballerina/http_status_code_types.bal
TharmiganK May 16, 2024
1c2cd5e
Merge branch 'master' into default-status-res
TharmiganK May 16, 2024
0bf9b02
Map the most specific first and then map to default
TharmiganK May 17, 2024
91bafe8
Fix the test case
TharmiganK May 17, 2024
17f0cf3
Remove unnecessary document comment
TharmiganK May 17, 2024
b67cabd
Add response details to data-binding errors
TharmiganK May 22, 2024
cf203b6
Fix test cases
TharmiganK May 22, 2024
bfbbd34
Merge branch 'master' into default-status-res
TharmiganK May 22, 2024
3f98b24
Fix duplicate code segments
TharmiganK May 22, 2024
90ee339
Change error message
TharmiganK May 27, 2024
f6148d4
Change detail field name
TharmiganK May 27, 2024
c0cf215
Fix check failures
TharmiganK May 27, 2024
3ed8b32
Address review suggestions
TharmiganK May 28, 2024
b9d3292
Merge branch 'master' into default-status-res
TharmiganK May 28, 2024
750bd0f
Merge remote-tracking branch 'refs/remotes/origin/master' into defaul…
TharmiganK May 30, 2024
9e6e0c6
[Automated] Update the native jar versions
TharmiganK May 30, 2024
75e31ac
[Automated] Update the native jar versions
TharmiganK May 30, 2024
ba35fb1
Merge branch 'master' into default-status-res
TharmiganK Jun 3, 2024
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
6 changes: 3 additions & 3 deletions ballerina-tests/http-advanced-tests/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_advanced_tests"
version = "2.11.1"
version = "2.11.2"

[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
version = "2.11.1"
version = "2.11.2"

[platform.java17]
graalvmCompatible = true

[[platform.java17.dependency]]
scope = "testOnly"
path = "../../test-utils/build/libs/http-test-utils-2.11.1.jar"
path = "../../test-utils/build/libs/http-test-utils-2.11.2-SNAPSHOT.jar"
6 changes: 3 additions & 3 deletions ballerina-tests/http-advanced-tests/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http"
version = "2.11.1"
version = "2.11.2"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
Expand Down Expand Up @@ -105,7 +105,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_advanced_tests"
version = "2.11.1"
version = "2.11.2"
dependencies = [
{org = "ballerina", name = "crypto"},
{org = "ballerina", name = "file"},
Expand All @@ -125,7 +125,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
version = "2.11.1"
version = "2.11.2"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
Expand Down
6 changes: 3 additions & 3 deletions ballerina-tests/http-client-tests/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
[package]
org = "ballerina"
name = "http_client_tests"
version = "2.11.1"
version = "2.11.2"

[[dependency]]
org = "ballerina"
name = "http_test_common"
repository = "local"
version = "2.11.1"
version = "2.11.2"

[platform.java17]
graalvmCompatible = true

[[platform.java17.dependency]]
scope = "testOnly"
path = "../../test-utils/build/libs/http-test-utils-2.11.1.jar"
path = "../../test-utils/build/libs/http-test-utils-2.11.2-SNAPSHOT.jar"
6 changes: 3 additions & 3 deletions ballerina-tests/http-client-tests/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ dependencies = [
[[package]]
org = "ballerina"
name = "http"
version = "2.11.1"
version = "2.11.2"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "auth"},
Expand Down Expand Up @@ -102,7 +102,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_client_tests"
version = "2.11.1"
version = "2.11.2"
dependencies = [
{org = "ballerina", name = "constraint"},
{org = "ballerina", name = "http"},
Expand All @@ -121,7 +121,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http_test_common"
version = "2.11.1"
version = "2.11.2"
scope = "testOnly"
dependencies = [
{org = "ballerina", name = "lang.string"},
Expand Down
195 changes: 145 additions & 50 deletions ballerina-tests/http-client-tests/tests/sc_res_binding_tests.bal
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,24 @@ type AlbumNotFound record {|
Headers headers;
|};

type AlbumNotFoundDefault record {|
*http:DefaultStatusCodeResponse;
ErrorMessage body;
Headers headers;
|};

type AlbumFound record {|
*http:Ok;
Album body;
Headers headers;
|};

type AlbumFoundDefault record {|
*http:DefaultStatusCodeResponse;
Album body;
Headers headers;
|};

type AlbumFoundMock1 record {|
*http:Ok;
Album|MockAlbum body;
Expand Down Expand Up @@ -251,28 +263,75 @@ function testGetSuccessStatusCodeResponse() returns error? {
test:assertEquals(albumFound.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(albumFound.mediaType, "application/json", "Invalid media type");

AlbumFound|AlbumNotFound res4 = check albumClient->/albums/'1;
if res4 is AlbumFound {
test:assertEquals(res4.body, expectedAlbum, "Invalid album returned");
test:assertEquals(res4.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res4.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res4.mediaType, "application/json", "Invalid media type");
AlbumFound|AlbumNotFound res1 = check albumClient->/albums/'1;
if res1 is AlbumFound {
test:assertEquals(res1.body, expectedAlbum, "Invalid album returned");
test:assertEquals(res1.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res1.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res1.mediaType, "application/json", "Invalid media type");
} else {
test:assertFail("Invalid response type");
}

AlbumNotFound|error res8 = albumClient->/albums/'1;
if res8 is error {
test:assertTrue(res8 is http:StatusCodeResponseBindingError);
test:assertEquals(res8.message(), "incompatible AlbumNotFound found for response with 200",
AlbumNotFound|error res2 = albumClient->/albums/'1;
if res2 is error {
test:assertTrue(res2 is http:StatusCodeResponseBindingError);
test:assertEquals(res2.message(), "incompatible type: AlbumNotFound found for the response with status code: 200",
"Invalid error message");
error? cause = res8.cause();
error? cause = res2.cause();
if cause is error {
test:assertEquals(cause.message(), "no 'anydata' type found in the target type", "Invalid cause error message");
}
} else {
test:assertFail("Invalid response type");
}

AlbumFoundDefault albumFoundDefault = check albumClient->get("/albums/1");
test:assertEquals(albumFoundDefault.body, expectedAlbum, "Invalid album returned");
test:assertEquals(albumFoundDefault.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(albumFoundDefault.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(albumFoundDefault.mediaType, "application/json", "Invalid media type");
test:assertEquals(albumFoundDefault.status.code, 200, "Invalid status code");

AlbumFoundDefault|error res3 = albumClient->get("/albums/1");
if res3 is AlbumFoundDefault {
test:assertEquals(res3.body, expectedAlbum, "Invalid album returned");
test:assertEquals(res3.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res3.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res3.mediaType, "application/json", "Invalid media type");
test:assertEquals(res3.status.code, 200, "Invalid status code");
} else {
test:assertFail("Invalid response type");
}

AlbumNotFound|AlbumFoundDefault res4 = check albumClient->/albums/'1;
if res4 is AlbumFoundDefault {
test:assertEquals(res4.body, expectedAlbum, "Invalid album returned");
test:assertEquals(res4.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res4.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res4.mediaType, "application/json", "Invalid media type");
test:assertEquals(res4.status.code, 200, "Invalid status code");
} else {
test:assertFail("Invalid response type");
}

http:DefaultStatusCodeResponse res5 = check albumClient->get("/albums/1");
test:assertEquals(res5?.body, expectedAlbum, "Invalid album returned");
test:assertEquals(res5.headers["user-id"], "user-1", "Invalid user-id header");
test:assertEquals(res5.headers["req-id"], "1", "Invalid req-id header");
test:assertEquals(res5.mediaType, "application/json", "Invalid media type");
test:assertEquals(res5.status.code, 200, "Invalid status code");

http:DefaultStatusCodeResponse|AlbumFound|AlbumFoundDefault res6 = check albumClient->get("/albums/1");
if res6 is AlbumFound {
test:assertEquals(res6?.body, expectedAlbum, "Invalid album returned");
test:assertEquals(res6?.headers["user-id"], "user-1", "Invalid user-id header");
test:assertEquals(res6?.headers["req-id"], 1, "Invalid req-id header");
test:assertEquals(res6.mediaType, "application/json", "Invalid media type");
test:assertEquals(res6.status.code, 200, "Invalid status code");
} else {
test:assertFail("Invalid response type");
}
}

@test:Config {}
Expand All @@ -284,15 +343,15 @@ function testGetFailureStatusCodeResponse() returns error? {
test:assertEquals(albumNotFound.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(albumNotFound.mediaType, "application/json", "Invalid media type");

AlbumFound|error res6 = albumClient->get("/albums/4");
if res6 is error {
test:assertTrue(res6 is http:ClientRequestError);
test:assertTrue(res6 is http:StatusCodeResponseBindingError);
test:assertEquals(res6.message(), "incompatible AlbumFound found for response with 404", "Invalid error message");
test:assertEquals(res6.detail()["statusCode"], 404, "Invalid status code");
test:assertEquals(res6.detail()["body"], expectedErrorMessage, "Invalid error message");
if res6.detail()["headers"] is map<string[]> {
map<string[]> headers = check res6.detail()["headers"].ensureType();
AlbumFound|error res1 = albumClient->get("/albums/4");
if res1 is error {
test:assertTrue(res1 is http:ClientRequestError);
test:assertTrue(res1 is http:StatusCodeResponseBindingError);
test:assertEquals(res1.message(), "incompatible type: AlbumFound found for the response with status code: 404", "Invalid error message");
test:assertEquals(res1.detail()["statusCode"], 404, "Invalid status code");
test:assertEquals(res1.detail()["body"], expectedErrorMessage, "Invalid error message");
if res1.detail()["headers"] is map<string[]> {
map<string[]> headers = check res1.detail()["headers"].ensureType();
test:assertEquals(headers.get("user-id")[0], "user-1", "Invalid user-id header");
test:assertEquals(headers.get("req-id")[0], "1", "Invalid req-id header");
} else {
Expand All @@ -301,54 +360,82 @@ function testGetFailureStatusCodeResponse() returns error? {
} else {
test:assertFail("Invalid response type");
}

AlbumNotFoundDefault albumNotFoundDefault = check albumClient->get("/albums/4");
test:assertEquals(albumNotFoundDefault.body, expectedErrorMessage, "Invalid error message");
test:assertEquals(albumNotFoundDefault.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(albumNotFoundDefault.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(albumNotFoundDefault.mediaType, "application/json", "Invalid media type");
test:assertEquals(albumNotFoundDefault.status.code, 404, "Invalid status code");

AlbumFound|http:DefaultStatusCodeResponse|error res2 = albumClient->get("/albums/4");
if res2 is http:DefaultStatusCodeResponse {
test:assertEquals(res2?.body, expectedErrorMessage, "Invalid error message");
test:assertEquals(res2.headers["user-id"], "user-1", "Invalid user-id header");
test:assertEquals(res2.headers["req-id"], "1", "Invalid req-id header");
test:assertEquals(res2.mediaType, "application/json", "Invalid media type");
test:assertEquals(res2.status.code, 404, "Invalid status code");
} else {
test:assertFail("Invalid response type");
}

AlbumFound|AlbumNotFound|http:DefaultStatusCodeResponse res3 = check albumClient->get("/albums/4");
if res3 is AlbumNotFound {
test:assertEquals(res3.body, expectedErrorMessage, "Invalid error message");
test:assertEquals(res3.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res3.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res3.mediaType, "application/json", "Invalid media type");
} else {
test:assertFail("Invalid response type");
}
}

@test:Config {}
function testUnionPayloadBindingWithStatusCodeResponse() returns error? {
AlbumFound|AlbumNotFound|AlbumFoundMock1 res7 = check albumClient->/albums/'1;
if res7 is AlbumFound {
test:assertEquals(res7.body, albums.get("1"), "Invalid album returned");
test:assertEquals(res7.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res7.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res7.mediaType, "application/json", "Invalid media type");
AlbumFound|AlbumNotFound|AlbumFoundMock1 res1 = check albumClient->/albums/'1;
if res1 is AlbumFound {
test:assertEquals(res1.body, albums.get("1"), "Invalid album returned");
test:assertEquals(res1.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res1.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res1.mediaType, "application/json", "Invalid media type");
} else {
test:assertFail("Invalid response type");
}

AlbumFoundMock1|AlbumFound|AlbumNotFound res8 = check albumClient->get("/albums/1");
if res8 is AlbumFoundMock1 {
test:assertEquals(res8.body, albums.get("1"), "Invalid album returned");
test:assertEquals(res8.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res8.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res8.mediaType, "application/json", "Invalid media type");
AlbumFoundMock1|AlbumFound|AlbumNotFound res2 = check albumClient->get("/albums/1");
if res2 is AlbumFoundMock1 {
test:assertEquals(res2.body, albums.get("1"), "Invalid album returned");
test:assertEquals(res2.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res2.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res2.mediaType, "application/json", "Invalid media type");
} else {
test:assertFail("Invalid response type");
}

AlbumFoundMock2|AlbumFound|AlbumFoundMock1|AlbumNotFound res9 = check albumClient->/albums/'1;
if res9 is AlbumFoundMock2 {
test:assertEquals(res9.body, albums.get("1"), "Invalid album returned");
test:assertEquals(res9.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res9.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res9.mediaType, "application/json", "Invalid media type");
AlbumFoundMock2|AlbumFound|AlbumFoundMock1|AlbumNotFound res3 = check albumClient->/albums/'1;
if res3 is AlbumFoundMock2 {
test:assertEquals(res3.body, albums.get("1"), "Invalid album returned");
test:assertEquals(res3.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res3.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res3.mediaType, "application/json", "Invalid media type");
} else {
test:assertFail("Invalid response type");
}

AlbumFoundMock3|AlbumFound|AlbumFoundMock1|AlbumFoundMock2|AlbumNotFound res10 = check albumClient->get("/albums/1");
if res10 is AlbumFoundMock3 {
test:assertEquals(res10.body, {...albums.get("1"), "type": "mock"}, "Invalid album returned");
test:assertEquals(res10.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res10.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res10.mediaType, "application/json", "Invalid media type");
AlbumFoundMock3|AlbumFound|AlbumFoundMock1|AlbumFoundMock2|AlbumNotFound res4 = check albumClient->get("/albums/1");
if res4 is AlbumFoundMock3 {
test:assertEquals(res4.body, {...albums.get("1"), "type": "mock"}, "Invalid album returned");
test:assertEquals(res4.headers.user\-id, "user-1", "Invalid user-id header");
test:assertEquals(res4.headers.req\-id, 1, "Invalid req-id header");
test:assertEquals(res4.mediaType, "application/json", "Invalid media type");
} else {
test:assertFail("Invalid response type");
}

AlbumFoundInvalid|AlbumFound|AlbumNotFound|error res11 = albumClient->/albums/'1;
if res11 is error {
test:assertTrue(res11 is http:PayloadBindingError);
test:assertTrue(res11.message().includes("Payload binding failed: 'map<json>' value cannot be" +
AlbumFoundInvalid|AlbumFound|AlbumNotFound|error res5 = albumClient->/albums/'1;
if res5 is error {
test:assertTrue(res5 is http:PayloadBindingError);
test:assertTrue(res5.message().includes("Payload binding failed: 'map<json>' value cannot be" +
" converted to 'http_client_tests:AlbumInvalid"), "Invalid error message");
} else {
test:assertFail("Invalid response type");
Expand Down Expand Up @@ -392,8 +479,16 @@ function testStatusCodeBindingWithDifferentHeaders() returns error? {

record {|*http:Ok; AdditionalMissingHeaders headers;|}|error res6 = albumClient->/albums/'1;
if res6 is error {
test:assertTrue(res6 is http:HeaderNotFoundError);
test:assertEquals(res6.message(), "no header value found for 'x-content-type'", "Invalid error message");
test:assertTrue(res6 is http:HeaderBindingError);
test:assertTrue(res6 is http:StatusCodeResponseBindingError);
test:assertEquals(res6.message(), "header binding failed");
error? cause = res6.cause();
if cause is error {
test:assertTrue(cause is http:HeaderNotFoundError);
test:assertEquals(cause.message(), "no header value found for 'x-content-type'", "Invalid cause error message");
} else {
test:assertFail("Invalid cause error type");
}
} else {
test:assertFail("Invalid response type");
}
Expand Down
Loading
Loading