From a5dcc85474f6818b6d55f63e3e16eefe16480337 Mon Sep 17 00:00:00 2001 From: Simon Zelazny Date: Tue, 30 Sep 2014 15:17:48 +0200 Subject: [PATCH 1/7] Add https procol support for sns --- include/erlcloud_aws.hrl | 1 + src/erlcloud_sns.erl | 20 +++++++------- test/erlcloud_sns_tests.erl | 52 +++++++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+), 9 deletions(-) create mode 100644 test/erlcloud_sns_tests.erl diff --git a/include/erlcloud_aws.hrl b/include/erlcloud_aws.hrl index 66cf555ce..d7eb80aa2 100644 --- a/include/erlcloud_aws.hrl +++ b/include/erlcloud_aws.hrl @@ -10,6 +10,7 @@ elb_host="elasticloadbalancing.amazonaws.com"::string(), ses_host="email.us-east-1.amazonaws.com"::string(), sqs_host="queue.amazonaws.com"::string(), + sns_protocol="http"::string(), sns_host="sns.amazonaws.com"::string(), mturk_host="mechanicalturk.amazonaws.com"::string(), mon_host="monitoring.amazonaws.com"::string(), diff --git a/src/erlcloud_sns.erl b/src/erlcloud_sns.erl index 3b9a78dad..b271bbc6e 100644 --- a/src/erlcloud_sns.erl +++ b/src/erlcloud_sns.erl @@ -8,7 +8,7 @@ create_platform_endpoint/2, create_platform_endpoint/3, create_platform_endpoint/4, create_platform_endpoint/5, create_platform_endpoint/6, - create_topic/1, create_topic/2, + create_topic/1, create_topic/2, delete_endpoint/1, delete_endpoint/2, delete_endpoint/3, delete_topic/1, delete_topic/2, list_endpoints_by_platform_application/1, @@ -144,7 +144,7 @@ create_platform_endpoint(PlatformApplicationArn, Token, CustomUserData, Attribut create_topic(TopicName) -> create_topic(TopicName, default_config()). -create_topic(TopicName, Config) +create_topic(TopicName, Config) when is_record(Config, aws_config) -> Doc = sns_xml_request(Config, "CreateTopic", [{"Name", TopicName}]), erlcloud_xml:get_text("/CreateTopicResponse/CreateTopicResult/TopicArn", Doc). @@ -204,7 +204,7 @@ delete_endpoint(EndpointArn, AccessKeyID, SecretAccessKey) -> delete_topic(TopicArn) -> delete_topic(TopicArn, default_config()). -delete_topic(TopicArn, Config) +delete_topic(TopicArn, Config) when is_record(Config, aws_config) -> sns_simple_request(Config, "DeleteTopic", [{"TopicArn", TopicArn}]). @@ -470,9 +470,10 @@ sns_simple_request(Config, Action, Params) -> sns_xml_request(Config, Action, Params) -> case erlcloud_aws:aws_request_xml2( - post, "http", Config#aws_config.sns_host, undefined, "/", - [{"Action", Action}, {"Version", ?API_VERSION} | Params], - Config) of + post, Config#aws_config.sns_protocol, Config#aws_config.sns_host, + undefined, "/", + [{"Action", Action}, {"Version", ?API_VERSION} | Params], + Config) of {ok, XML} -> XML; {error, {http_error, 400, _BadRequest, Body}} -> XML = element(1, xmerl_scan:string(binary_to_list(Body))), @@ -485,9 +486,10 @@ sns_xml_request(Config, Action, Params) -> sns_request(Config, Action, Params) -> case erlcloud_aws:aws_request2( - post, "http", Config#aws_config.sns_host, undefined, "/", - [{"Action", Action}, {"Version", ?API_VERSION} | Params], - Config) of + post, Config#aws_config.sns_protocol, Config#aws_config.sns_host, + undefined, "/", + [{"Action", Action}, {"Version", ?API_VERSION} | Params], + Config) of {ok, _Response} -> ok; {error, {http_error, 400, _BadRequest, Body}} -> XML = element(1, xmerl_scan:string(binary_to_list(Body))), diff --git a/test/erlcloud_sns_tests.erl b/test/erlcloud_sns_tests.erl new file mode 100644 index 000000000..4c3ad7ccc --- /dev/null +++ b/test/erlcloud_sns_tests.erl @@ -0,0 +1,52 @@ +-module(erlcloud_sns_tests). +-include_lib("eunit/include/eunit.hrl"). +-include_lib("erlcloud/include/erlcloud_aws.hrl"). + +request_test_() -> + {foreach, + fun start/0, + fun stop/1, + [fun sns_publish_defaults_to_http/1, + fun sns_publish_supports_https/1 + ]}. + +start() -> + meck:new(erlcloud_aws, [passthrough]), + meck:expect(erlcloud_aws, aws_request_xml2, + fun(_,_,_,_,_,_,_) -> mock_response() end). + +stop(_) -> + meck:unload(erlcloud_aws). + +sns_publish_defaults_to_http(_) -> + Config = erlcloud_aws:default_config(), + catch(erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config)), + ?_assertMatch({post, "http", "sns.amazonaws.com", _, _, _, Config}, + get_values_from_history(meck:history(erlcloud_aws))). + +sns_publish_supports_https(_) -> + Config = (erlcloud_aws:default_config())#aws_config{sns_protocol="https"}, + erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), + ?_assertMatch({post, "https", "sns.amazonaws.com", _, _, _, Config}, + get_values_from_history(meck:history(erlcloud_aws))). + + +% ================== +% Internal functions +% ================== + +get_values_from_history(Plist) -> + [Call1] = [ Params || {_, {erlcloud_aws, aws_request_xml2, Params}, _} <- Plist ], + list_to_tuple(Call1). + + +mock_response() -> + R = <<" + + 94f20ce6-13c5-43a0-9a9e-ca52d816e90b + + + f187a3c1-376f-11df-8963-01868b7c937a + +">>, + {ok, element(1, xmerl_scan:string(binary_to_list(R)))}. From 6b9e120bac8357adf608ad2d3be95099fe643e49 Mon Sep 17 00:00:00 2001 From: Simon Zelazny Date: Tue, 30 Sep 2014 16:04:54 +0200 Subject: [PATCH 2/7] Remove unnecessary catch() --- test/erlcloud_sns_tests.erl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/erlcloud_sns_tests.erl b/test/erlcloud_sns_tests.erl index 4c3ad7ccc..d8c695c52 100644 --- a/test/erlcloud_sns_tests.erl +++ b/test/erlcloud_sns_tests.erl @@ -20,7 +20,7 @@ stop(_) -> sns_publish_defaults_to_http(_) -> Config = erlcloud_aws:default_config(), - catch(erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config)), + erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), ?_assertMatch({post, "http", "sns.amazonaws.com", _, _, _, Config}, get_values_from_history(meck:history(erlcloud_aws))). From d0a51e74159a00ad4065406aacc0bb4c0ec5b295 Mon Sep 17 00:00:00 2001 From: Simon Zelazny Date: Wed, 1 Oct 2014 11:32:24 +0200 Subject: [PATCH 3/7] Change sns_protocol config field to sns_scheme --- include/erlcloud_aws.hrl | 2 +- src/erlcloud_sns.erl | 16 ++++++++++++---- test/erlcloud_sns_tests.erl | 35 +++++++++++++++++++++++++++-------- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/include/erlcloud_aws.hrl b/include/erlcloud_aws.hrl index d7eb80aa2..c9eaca8c3 100644 --- a/include/erlcloud_aws.hrl +++ b/include/erlcloud_aws.hrl @@ -10,7 +10,7 @@ elb_host="elasticloadbalancing.amazonaws.com"::string(), ses_host="email.us-east-1.amazonaws.com"::string(), sqs_host="queue.amazonaws.com"::string(), - sns_protocol="http"::string(), + sns_scheme="http://"::string(), sns_host="sns.amazonaws.com"::string(), mturk_host="mechanicalturk.amazonaws.com"::string(), mon_host="monitoring.amazonaws.com"::string(), diff --git a/src/erlcloud_sns.erl b/src/erlcloud_sns.erl index b271bbc6e..871224a13 100644 --- a/src/erlcloud_sns.erl +++ b/src/erlcloud_sns.erl @@ -470,8 +470,8 @@ sns_simple_request(Config, Action, Params) -> sns_xml_request(Config, Action, Params) -> case erlcloud_aws:aws_request_xml2( - post, Config#aws_config.sns_protocol, Config#aws_config.sns_host, - undefined, "/", + post, scheme_to_protocol(Config#aws_config.sns_scheme), + Config#aws_config.sns_host, undefined, "/", [{"Action", Action}, {"Version", ?API_VERSION} | Params], Config) of {ok, XML} -> XML; @@ -486,8 +486,8 @@ sns_xml_request(Config, Action, Params) -> sns_request(Config, Action, Params) -> case erlcloud_aws:aws_request2( - post, Config#aws_config.sns_protocol, Config#aws_config.sns_host, - undefined, "/", + post, scheme_to_protocol(Config#aws_config.sns_scheme), + Config#aws_config.sns_host, undefined, "/", [{"Action", Action}, {"Version", ?API_VERSION} | Params], Config) of {ok, _Response} -> ok; @@ -526,3 +526,11 @@ parse_key("EventEndpointDeleted") -> event_endpoint_deleted; parse_key("EventEndpointUpdated") -> event_endpoint_updated; parse_key("EVentDeliveryFailure") -> event_delivery_failure; parse_key(OtherKey) -> list_to_atom(string:to_lower(OtherKey)). + +scheme_to_protocol(S) when is_list(S) -> s2p(string:to_lower(S)); +scheme_to_protocol(_) -> erlang:error({sns_error, badarg}). + +s2p("http://") -> "http"; +s2p("https://") -> "https"; +s2p(X) -> erlang:error({sns_error, {unsupported_scheme, X}}). + diff --git a/test/erlcloud_sns_tests.erl b/test/erlcloud_sns_tests.erl index d8c695c52..0cf3fbfc8 100644 --- a/test/erlcloud_sns_tests.erl +++ b/test/erlcloud_sns_tests.erl @@ -2,12 +2,15 @@ -include_lib("eunit/include/eunit.hrl"). -include_lib("erlcloud/include/erlcloud_aws.hrl"). -request_test_() -> +sns_publish_test_() -> {foreach, fun start/0, fun stop/1, - [fun sns_publish_defaults_to_http/1, - fun sns_publish_supports_https/1 + [fun defaults_to_http/1, + fun supports_explicit_http/1, + fun supports_https/1, + fun doesnt_support_gopher/1, + fun doesnt_accept_non_strings/1 ]}. start() -> @@ -18,18 +21,34 @@ start() -> stop(_) -> meck:unload(erlcloud_aws). -sns_publish_defaults_to_http(_) -> +defaults_to_http(_) -> Config = erlcloud_aws:default_config(), erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), - ?_assertMatch({post, "http", "sns.amazonaws.com", _, _, _, Config}, + ?_assertMatch({_, "http", _, _, _, _, Config}, get_values_from_history(meck:history(erlcloud_aws))). -sns_publish_supports_https(_) -> - Config = (erlcloud_aws:default_config())#aws_config{sns_protocol="https"}, +supports_explicit_http(_) -> + Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="http://"}, erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), - ?_assertMatch({post, "https", "sns.amazonaws.com", _, _, _, Config}, + ?_assertMatch({_, "http", _, _, _, _, Config}, get_values_from_history(meck:history(erlcloud_aws))). +supports_https(_) -> + Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="https://"}, + erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), + ?_assertMatch({_, "https", _, _, _, _, Config}, + get_values_from_history(meck:history(erlcloud_aws))). + +doesnt_support_gopher(_) -> + Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="gopher://"}, + ?_assertError({sns_error, {unsupported_scheme,"gopher://"}}, + erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config)). + +doesnt_accept_non_strings(_) -> + Config = (erlcloud_aws:default_config())#aws_config{sns_scheme=https}, + ?_assertError({sns_error, badarg}, + erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config)). + % ================== % Internal functions From 31300aa847a7586f18fe6c3d72a8a5fedaecfbb0 Mon Sep 17 00:00:00 2001 From: Simon Zelazny Date: Wed, 1 Oct 2014 11:41:45 +0200 Subject: [PATCH 4/7] Add test for case-insensitivity --- test/erlcloud_sns_tests.erl | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/test/erlcloud_sns_tests.erl b/test/erlcloud_sns_tests.erl index 0cf3fbfc8..dc28ba7b6 100644 --- a/test/erlcloud_sns_tests.erl +++ b/test/erlcloud_sns_tests.erl @@ -9,6 +9,7 @@ sns_publish_test_() -> [fun defaults_to_http/1, fun supports_explicit_http/1, fun supports_https/1, + fun is_case_insensitive/1, fun doesnt_support_gopher/1, fun doesnt_accept_non_strings/1 ]}. @@ -39,6 +40,12 @@ supports_https(_) -> ?_assertMatch({_, "https", _, _, _, _, Config}, get_values_from_history(meck:history(erlcloud_aws))). +is_case_insensitive(_) -> + Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="HTTPS://"}, + erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), + ?_assertMatch({_, "https", _, _, _, _, Config}, + get_values_from_history(meck:history(erlcloud_aws))). + doesnt_support_gopher(_) -> Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="gopher://"}, ?_assertError({sns_error, {unsupported_scheme,"gopher://"}}, @@ -58,7 +65,6 @@ get_values_from_history(Plist) -> [Call1] = [ Params || {_, {erlcloud_aws, aws_request_xml2, Params}, _} <- Plist ], list_to_tuple(Call1). - mock_response() -> R = <<" From 2cc5e37547557aaa87293fc9b5a424beb63f4a00 Mon Sep 17 00:00:00 2001 From: Simon Zelazny Date: Wed, 1 Oct 2014 12:18:39 +0200 Subject: [PATCH 5/7] Mock request at the erlcloud_httpc level --- test/erlcloud_sns_tests.erl | 40 ++++++++++++++++++++----------------- 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/test/erlcloud_sns_tests.erl b/test/erlcloud_sns_tests.erl index dc28ba7b6..e82a3451c 100644 --- a/test/erlcloud_sns_tests.erl +++ b/test/erlcloud_sns_tests.erl @@ -15,36 +15,35 @@ sns_publish_test_() -> ]}. start() -> - meck:new(erlcloud_aws, [passthrough]), - meck:expect(erlcloud_aws, aws_request_xml2, - fun(_,_,_,_,_,_,_) -> mock_response() end). + %% meck:new(erlcloud_aws, [passthrough]), + %% meck:expect(erlcloud_aws, aws_request_xml2, + %% fun(_,_,_,_,_,_,_) -> mock_response() end). + meck:new(erlcloud_httpc), + meck:expect(erlcloud_httpc, request, + fun(_,_,_,_,_,_) -> mock_httpc_response() end). stop(_) -> - meck:unload(erlcloud_aws). + meck:unload(erlcloud_httpc). defaults_to_http(_) -> Config = erlcloud_aws:default_config(), erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), - ?_assertMatch({_, "http", _, _, _, _, Config}, - get_values_from_history(meck:history(erlcloud_aws))). + ?_assertMatch({"http://sns.amazonaws.com/", _, _, _, _, Config}, request_params()). supports_explicit_http(_) -> Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="http://"}, erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), - ?_assertMatch({_, "http", _, _, _, _, Config}, - get_values_from_history(meck:history(erlcloud_aws))). + ?_assertMatch({"http://sns.amazonaws.com/", _, _, _, _, Config}, request_params()). supports_https(_) -> Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="https://"}, erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), - ?_assertMatch({_, "https", _, _, _, _, Config}, - get_values_from_history(meck:history(erlcloud_aws))). + ?_assertMatch({"https://sns.amazonaws.com/", _, _, _, _, Config}, request_params()). is_case_insensitive(_) -> - Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="HTTPS://"}, + Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="HTTP://"}, erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), - ?_assertMatch({_, "https", _, _, _, _, Config}, - get_values_from_history(meck:history(erlcloud_aws))). + ?_assertMatch({"http://sns.amazonaws.com/", _, _, _, _, Config}, request_params()). doesnt_support_gopher(_) -> Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="gopher://"}, @@ -62,16 +61,21 @@ doesnt_accept_non_strings(_) -> % ================== get_values_from_history(Plist) -> - [Call1] = [ Params || {_, {erlcloud_aws, aws_request_xml2, Params}, _} <- Plist ], + [Call1] = [ Params || {_, {erlcloud_httpc, request, Params}, _} <- Plist ], list_to_tuple(Call1). -mock_response() -> - R = <<" +request_params() -> + get_values_from_history(meck:history(erlcloud_httpc)). + +mock_httpc_response() -> + {ok, {{200, "ok"}, [], response_body()}}. + +response_body() -> + <<" 94f20ce6-13c5-43a0-9a9e-ca52d816e90b f187a3c1-376f-11df-8963-01868b7c937a -">>, - {ok, element(1, xmerl_scan:string(binary_to_list(R)))}. +">>. From 3e83d8baaa01ade844eb4d33484a53e71e6af6b5 Mon Sep 17 00:00:00 2001 From: Simon Zelazny Date: Wed, 1 Oct 2014 12:20:50 +0200 Subject: [PATCH 6/7] Test for HTTPS uppercase conversion --- test/erlcloud_sns_tests.erl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/erlcloud_sns_tests.erl b/test/erlcloud_sns_tests.erl index e82a3451c..384538b2f 100644 --- a/test/erlcloud_sns_tests.erl +++ b/test/erlcloud_sns_tests.erl @@ -41,9 +41,9 @@ supports_https(_) -> ?_assertMatch({"https://sns.amazonaws.com/", _, _, _, _, Config}, request_params()). is_case_insensitive(_) -> - Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="HTTP://"}, + Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="HTTPS://"}, erlcloud_sns:publish_to_topic("topicarn", "message", "subject", Config), - ?_assertMatch({"http://sns.amazonaws.com/", _, _, _, _, Config}, request_params()). + ?_assertMatch({"https://sns.amazonaws.com/", _, _, _, _, Config}, request_params()). doesnt_support_gopher(_) -> Config = (erlcloud_aws:default_config())#aws_config{sns_scheme="gopher://"}, From e8a6fdf6541d0676518e1e0a3dbf0444d8bf6102 Mon Sep 17 00:00:00 2001 From: Simon Zelazny Date: Wed, 1 Oct 2014 12:27:56 +0200 Subject: [PATCH 7/7] Cleanup commented debris --- test/erlcloud_sns_tests.erl | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/erlcloud_sns_tests.erl b/test/erlcloud_sns_tests.erl index 384538b2f..d646a1945 100644 --- a/test/erlcloud_sns_tests.erl +++ b/test/erlcloud_sns_tests.erl @@ -15,9 +15,6 @@ sns_publish_test_() -> ]}. start() -> - %% meck:new(erlcloud_aws, [passthrough]), - %% meck:expect(erlcloud_aws, aws_request_xml2, - %% fun(_,_,_,_,_,_,_) -> mock_response() end). meck:new(erlcloud_httpc), meck:expect(erlcloud_httpc, request, fun(_,_,_,_,_,_) -> mock_httpc_response() end).