Skip to content

Commit

Permalink
Implements tests for static and dynamic application configuration trh…
Browse files Browse the repository at this point in the history
…ough env
  • Loading branch information
drobakowski committed Jan 12, 2017
1 parent bbafbb1 commit 1079caa
Show file tree
Hide file tree
Showing 6 changed files with 405 additions and 172 deletions.
10 changes: 5 additions & 5 deletions priv/app_test.config
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@

,{access_token_expiry, 3600}

,{access_token_server_request_retry_timeout, 3600}
,{access_token_server_request_retry_timeout, 6300}

,{credentials, [
{client_id, "..."}
,{client_secret, "..."}
,{username, "..."}
,{password, "..."}
{client_id, "client_id"}
,{client_secret, "client_secret"}
,{username, "username"}
,{password, "password"}
]}

,{sobjects_mapping, #{}}
Expand Down
27 changes: 26 additions & 1 deletion src/config/sf_client_config.erl
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
%% API
-export([
init/0
,application/0
,get_sf_rest_api_version/0
,get_sf_rest_api_endpoint/0
,get_sf_rest_api_version_path/0
Expand Down Expand Up @@ -44,6 +45,7 @@ init() ->
maybe_to_binary(maybe_prefix_with_https(get_config(sf_rest_api_endpoint)))
end}]}
,{sf_rest_api_version_path, "_INTERNAL_SF_REST_API_VERSION_PATH", [{transform, fun(_) ->
%% sf_rest_api_version_path will be generated at runtime and can't be configured through the config
error_m:fail(dont_set_sf_rest_api_version_path)
end}, {default, fun() ->
RestApiEndpoint = get_sf_rest_api_endpoint(),
Expand Down Expand Up @@ -75,30 +77,53 @@ init() ->
end}]}
]).


-spec application() -> ?APP_ENV.
application() ->
?APP_ENV.


-spec get_sf_rest_api_version() -> binary().
get_sf_rest_api_version() ->
stillir:get_config(?APP_ENV, sf_rest_api_version).


-spec get_sf_rest_api_endpoint() -> binary().
get_sf_rest_api_endpoint() ->
stillir:get_config(?APP_ENV, sf_rest_api_endpoint).


-spec get_sf_rest_api_version_path() -> {ok, binary()} | {error, no_available_rest_api_version_path | dont_set_sf_rest_api_version_path}.
get_sf_rest_api_version_path() ->
stillir:get_config(?APP_ENV, sf_rest_api_version_path).


-spec get_credentials_client_id() -> string().
get_credentials_client_id() ->
stillir:get_config(?APP_ENV, sf_credentials_client_id).


-spec get_credentials_client_secret() -> string().
get_credentials_client_secret() ->
stillir:get_config(?APP_ENV, sf_credentials_client_secret).


-spec get_credentials_username() -> string().
get_credentials_username() ->
stillir:get_config(?APP_ENV, sf_credentials_username).


-spec get_credentials_password() -> string().
get_credentials_password() ->
stillir:get_config(?APP_ENV, sf_credentials_password).


-spec get_access_token_expiry() -> pos_integer().
get_access_token_expiry() ->
stillir:get_config(?APP_ENV, sf_access_token_expiry).


-spec get_access_token_server_request_retry_timeout() -> pos_integer().
get_access_token_server_request_retry_timeout() ->
get_config(access_token_server_request_retry_timeout).

Expand All @@ -120,7 +145,7 @@ get_config(Config) ->
get_required(AppEnv, Key) ->
case application:get_env(AppEnv, Key) of
undefined ->
throw({missing_config, Key});
erlang:error({missing_config, Key});
{ok, Value} ->
Value
end.
Expand Down
6 changes: 4 additions & 2 deletions src/sf_client.erl
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,10 @@


reinitialize_client() ->
sf_client_config:init(),
sf_client_sobjects_mapping_server:reinitialize_sf_mapping().
_ = sf_client_config:init(),
_ = sf_client_sobjects_mapping_server:reinitialize_sf_mapping(),
_ = sf_client_access_token_server:reasign_server_access_token(),
ok.


-spec create(MappingKey :: mapping_key(), Model :: model()) -> {ok, Id :: sf_sobject_id()} | {error, Reason :: any()}.
Expand Down
184 changes: 184 additions & 0 deletions test/sf_client_config_eunit_lib.erl
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
%%%-------------------------------------------------------------------
%%% @author David Robakowski
%%% @copyright (C) 2017, Synlay Technologies UG & Co. KG
%%% @doc
%%%
%%% @end
%%% Created : 13. Jan 2017 00:00
%%%-------------------------------------------------------------------
-module(sf_client_config_eunit_lib).
-author("David Robakowski").

-include_lib("proper/include/proper.hrl").
-include_lib("eunit/include/eunit.hrl").

-behaviour(sf_client_sobjects_mapping_behaviour).

-define(MAPPING_KEY, ?MODULE).

-define(RESTC_RESPONSE(ExpectedStatusCode, Header, Body), {ok, ExpectedStatusCode, Header, Body}).

%% API
-export([
new_sobject_from_model/1,
sobject_table_name/0,
sobject_external_id_attribute_name/0,
model_id/1,
to_string/1
]).

%% API
-export([
setup/0
,teardown/1
]).


setup() ->

_ = ets:new(?MODULE, [public, named_table, set]),

application:ensure_all_started(restc),

ok = meck:new(sf_client_config, [passthrough]),
ok = meck:new(restc, [passthrough]),

meck:expect(sf_client_config, get_sobjects_mapping, fun() ->
#{?MODULE => ?MODULE}
end),

meck:expect(restc, request, fun
%% sf_client_sobjects_mapping_server:init_sf_mappings/0@L163 - Get a List of Resources
(get, json, "https://localhost/services/data", [200], [], []) ->
?RESTC_RESPONSE(200, [], [#{
<<"version">> => <<"39.0">>
,<<"url">> => <<"/services/data/v39.0">>
}]);

%% sf_client_access_token_server:init_system/0@L326 - Get an access token
(post, json, "https://localhost/services/oauth2/token?grant_type=" ++ _, [200], [], []) ->
?RESTC_RESPONSE(200, [], #{
<<"access_token">> => <<"ACCESS_TOKEN">>
,<<"instance_url">> => <<"https://cs83.salesforce.com">>
,<<"id">> => <<"https://test.salesforce.com/id/.../...">>
,<<"token_type">> => <<"Bearer">>
,<<"issued_at">> => <<"1484007526619">>
,<<"signature">> => <<"....">>
});

%% sf_client_sobjects_mapping_server:init_sf_mappings/0@L167 - Get the sobjects path
(get, json, "https://localhost/services/data/v39.0", [200],[{<<"Authorization">>,<<"Bearer ACCESS_TOKEN">>}],
[]) ->
?RESTC_RESPONSE(200, [], #{
<<"sobjects">> => <<"/services/data/v39.0/sobjects">>
});

%% sf_client_sobjects_mapping_server:init_sf_mappings - Get the corresponding sobject urls
(get, json, "https://localhost/services/data/v39.0/sobjects", [200],
[{<<"Authorization">>,<<"Bearer ACCESS_TOKEN">>}], []) ->
?RESTC_RESPONSE(200, [], #{
<<"sobjects">> => [#{
<<"name">> => sobject_table_name()
,<<"urls">> => #{
<<"sobject">> => <<"/services/data/v39.0/sobjects/MOCK_sobject_table_name">>
}
}]
});

%% Create a new resource => sf_client:create...
(post, json, <<"https://localhost/services/data/v39.0/sobjects/MOCK_sobject_table_name">>, [201],
[{<<"Authorization">>,<<"Bearer ACCESS_TOKEN">>}], DbModel) ->

SfInternalId = get_sf_id(DbModel),
ExternalId = proplists:get_value(sobject_external_id_attribute_name(), DbModel),
true = ets:insert(?MODULE, {SfInternalId, DbModel, ExternalId}),

?RESTC_RESPONSE(201, [], #{
<<"id">> => SfInternalId
,<<"success">> => true
,<<"errors">> => []
});

%% Find the SF resource by the internal model id
(get, json,
"https://localhost/services/data/v39.0/sobjects/MOCK_sobject_table_name/External_ID__c/" ++ IdWithSufix,
[200], [{<<"Authorization">>,<<"Bearer ACCESS_TOKEN">>}], []) ->

[ExternalId, _Suffix] = binary:split(list_to_binary(IdWithSufix), <<"?fields=Id">>),

case ets:match(?MODULE, {'$1', '_', ExternalId}) of
[] ->
{error, not_found};
[[SfInternalId]] ->
?RESTC_RESPONSE(200, [], #{<<"Id">> => SfInternalId})
end;

%% Update a specific SF resource
(patch, json, "https://localhost/services/data/v39.0/sobjects/MOCK_sobject_table_name/" ++ SObjectIdStr, [204],
[{<<"Authorization">>,<<"Bearer ACCESS_TOKEN">>}], NewDbModel) ->

SObjectId = list_to_binary(SObjectIdStr),
ExternalId = proplists:get_value(sobject_external_id_attribute_name(), NewDbModel),

true = ets:insert(?MODULE, {SObjectId, NewDbModel, ExternalId}),

?RESTC_RESPONSE(204, [], <<>>);

%% Delete a specific SF resource
(delete, json, "https://localhost/services/data/v39.0/sobjects/MOCK_sobject_table_name/" ++ SObjectIdStr, [204],
[{<<"Authorization">>,<<"Bearer ACCESS_TOKEN">>}], []) ->

SObjectId = list_to_binary(SObjectIdStr),

true = ets:delete(?MODULE, SObjectId),

?RESTC_RESPONSE(204, [], <<>>);

(Action, json, Url, [Status], _Auth, DbModel) ->
?debugVal({Action, Url, Status, _Auth, DbModel}),
throw(not_implemented)

end),

application:ensure_all_started(sf_client),

ok.


teardown(_) ->
true = ets:delete(?MODULE),
catch meck:unload(sf_client_config),
catch meck:unload(restc),
ok.


%%--------------------------------------------------------------------
%% @doc sf_client_sobjects_mapping_behaviour implementation
%%--------------------------------------------------------------------


get_sf_id(Model) ->
st_digest_lib:hexbinarystring(crypto:hash(md4,(term_to_binary(Model)))).


new_sobject_from_model(Model) ->
[
{sobject_external_id_attribute_name(), model_id(Model)}
,{<<"Data">>, term_to_binary(Model)}
].


sobject_external_id_attribute_name() ->
<<"External_ID__c">>.


model_id({Id, _Model}) ->
st_digest_lib:hexbinarystring(crypto:hash(md4,(term_to_binary(Id)))).


sobject_table_name() ->
<<"MOCK_sobject_table_name">>.


to_string(Model) ->
binary_to_list(model_id(Model)).
Loading

0 comments on commit 1079caa

Please sign in to comment.