From 5e04292e67afd82db5d8745c40a46244cc35a3b8 Mon Sep 17 00:00:00 2001 From: Matthias Wahl Date: Fri, 28 Oct 2016 12:18:57 +0200 Subject: [PATCH] make egithub_webhook:request() type opaque and move creation and extraction into its own module --- src/egithub_webhook.erl | 19 ++++----- src/egithub_webhook_req.erl | 40 ++++++++++++++++++ test/egithub_webhook_req_tests.erl | 68 ++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 src/egithub_webhook_req.erl create mode 100644 test/egithub_webhook_req_tests.erl diff --git a/src/egithub_webhook.erl b/src/egithub_webhook.erl index 040b6e5..a257d40 100644 --- a/src/egithub_webhook.erl +++ b/src/egithub_webhook.erl @@ -10,9 +10,6 @@ -export([event/3, event/6]). --export_type([request/0]). - --type request() :: #{headers => map(), body => binary()}. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% Callbacks @@ -40,14 +37,15 @@ %% @doc Should be called from the endpoint that handles the GitHub's request %% for the webhook. %% @end --spec event(atom(), egithub:credentials(), request()) -> ok | {error, term()}. -event(Module, Cred, #{headers := Headers, body := Body}) -> - case maps:get(<<"x-github-event">>, Headers, undefined) of +-spec event(atom(), egithub:credentials(), egithub_webhook_req:request()) -> + ok | {error, term()}. +event(Module, Cred, Request) -> + case egithub_webhook_req:header(<<"x-github-event">>, Request) of undefined -> {error, missing_header}; <<"ping">> -> ok; <<"pull_request">> -> - EventData = egithub_json:decode(Body), + {_Request2, EventData} = egithub_webhook_req:payload(Request), case do_handle_pull_request(Module, Cred, EventData) of clean -> ok; {clean, _TargetUrl} -> ok; @@ -68,15 +66,14 @@ event(Module, Cred, #{headers := Headers, body := Body}) -> %% @end -spec event( atom(), egithub:credentials(), string(), string(), egithub:credentials(), - request()) -> ok | {error, term()}. + egithub_webhook_req:request()) -> ok | {error, term()}. event(Module, StatusCred, ToolName, Context, CommentsCred, Request) -> - #{headers := Headers, body := Body} = Request, - case maps:get(<<"x-github-event">>, Headers, undefined) of + case egithub_webhook_req:header(<<"x-github-event">>, Request) of undefined -> {error, missing_header}; <<"ping">> -> ok; <<"pull_request">> -> - EventData = egithub_json:decode(Body), + {_Request2, EventData} = egithub_webhook_req:payload(Request), set_status(pending, StatusCred, ToolName, Context, EventData), try Result = do_handle_pull_request(Module, CommentsCred, EventData), diff --git a/src/egithub_webhook_req.erl b/src/egithub_webhook_req.erl new file mode 100644 index 0000000..13cfa6d --- /dev/null +++ b/src/egithub_webhook_req.erl @@ -0,0 +1,40 @@ +%%%------------------------------------------------------------------- +%%% @author mwahl +%%% @copyright (C) 2016, +%%% @doc +%%% +%%% @end +%%% Created : 28. Oct 2016 11:11 AM +%%%------------------------------------------------------------------- +-module(egithub_webhook_req). +-author("mwahl"). + +-opaque request() :: #{headers => map(), body => map()|binary()}. +-export_type([request/0]). + +%% API +-export([new/2, headers/1, header/2, header/3, payload/1]). + +-spec new(map(), binary()|map()) -> request(). +new(Headers, Body) -> #{headers => Headers, body => Body}. + +-spec headers(request()) -> map(). +headers(#{headers := Headers}) -> Headers. + +-spec header(binary(), request()) -> binary()|undefined. +header(Header, Request) -> header(Header, Request, undefined). + +-spec header(binary(), request(), binary()|undefined) -> binary()|undefined. +header(Header, #{headers := Headers}, Default) -> + maps:get(Header, Headers, Default). + +-spec payload(request()) -> {request(), map()}. +payload(Request=#{body := Body}) when is_binary(Body)-> + with_decoded_body(Request); +payload(Request=#{body := DecodedBody}) when is_map(DecodedBody) -> + {Request, DecodedBody}. + +-spec with_decoded_body(request()) -> {request(), map()}. +with_decoded_body(Request=#{body := Body}) -> + DecodedBody = egithub_json:decode(Body), + {Request#{body => DecodedBody}, DecodedBody}. \ No newline at end of file diff --git a/test/egithub_webhook_req_tests.erl b/test/egithub_webhook_req_tests.erl new file mode 100644 index 0000000..9ecb174 --- /dev/null +++ b/test/egithub_webhook_req_tests.erl @@ -0,0 +1,68 @@ +%%%------------------------------------------------------------------- +%%% @author mwahl +%%% @copyright (C) 2016, +%%% @doc +%%% +%%% @end +%%% Created : 28. Oct 2016 11:40 AM +%%%------------------------------------------------------------------- +-module(egithub_webhook_req_tests). +-author("mwahl"). + +-include_lib("eunit/include/eunit.hrl"). + +setup_test_data() -> + EncodedBody = <<"{\"foo\":\"bar\"}">>, + DecodedBody = egithub_json:decode(EncodedBody), + TestHeaders = #{<<"Accept">> => <<"*">>, + <<"Content-Type">> => <<"application/json">>}, + EncodedReq = egithub_webhook_req:new(TestHeaders, EncodedBody), + DecodedReq = egithub_webhook_req:new(TestHeaders, DecodedBody), + #{ + encoded_body => EncodedBody, + decoded_body => DecodedBody, + headers => TestHeaders, + encoded_request => EncodedReq, + decoded_request => DecodedReq + }. + +egithub_webhook_req_headers_test_() -> + #{headers := TestHeaders, encoded_request := Req} = setup_test_data(), + [ + ?_assertEqual( + TestHeaders, + egithub_webhook_req:headers(Req) + ), + ?_assertEqual( + undefined, + egithub_webhook_req:header(<<"Undefined">>, Req) + ), + ?_assertEqual( + <<"*">>, + egithub_webhook_req:header(<<"Accept">>, Req) + ) + ]. + +egithub_webhook_req_encoded_body_test() -> + #{ + encoded_request := Req, + decoded_body := DecodedBody + } = setup_test_data(), + ?assertEqual( + {DecodedBody, DecodedBody}, + begin + {Req2, Payload1} = egithub_webhook_req:payload(Req), + {_Req3, Payload2} = egithub_webhook_req:payload(Req2), + {Payload1, Payload2} + end + ). + +egithub_webhook_req_decoded_body_test() -> + #{ + decoded_request := Req, + decoded_body := DecodedBody + } = setup_test_data(), + ?assertEqual( + {Req, DecodedBody}, + egithub_webhook_req:payload(Req) + ). \ No newline at end of file