2016-09-07 19:43:14 +00:00
|
|
|
-module(dmt_api_tests_SUITE).
|
|
|
|
-include_lib("common_test/include/ct.hrl").
|
|
|
|
|
|
|
|
-export([all/0]).
|
|
|
|
-export([groups/0]).
|
|
|
|
-export([init_per_suite/1]).
|
|
|
|
-export([end_per_suite/1]).
|
2017-03-29 15:27:11 +00:00
|
|
|
-export([init_per_group/2]).
|
|
|
|
-export([end_per_group/2]).
|
2018-07-17 11:17:53 +00:00
|
|
|
-export([init_per_testcase/2]).
|
|
|
|
-export([end_per_testcase/2]).
|
2016-09-07 19:43:14 +00:00
|
|
|
|
2017-04-03 11:20:25 +00:00
|
|
|
-export([pull_commit/1]).
|
2018-07-06 13:33:49 +00:00
|
|
|
-export([retry_commit/1]).
|
2016-09-07 19:43:14 +00:00
|
|
|
-export([insert/1]).
|
|
|
|
-export([update/1]).
|
|
|
|
-export([delete/1]).
|
2018-07-06 13:33:49 +00:00
|
|
|
-export([migration_success/1]).
|
2016-09-07 19:43:14 +00:00
|
|
|
|
2016-10-14 17:48:54 +00:00
|
|
|
-include_lib("dmsl/include/dmsl_domain_config_thrift.hrl").
|
2016-09-07 19:43:14 +00:00
|
|
|
|
|
|
|
%% tests descriptions
|
|
|
|
|
|
|
|
-type config() :: [{atom(), term()}].
|
|
|
|
|
|
|
|
-define(config(Key, C), (element(2, lists:keyfind(Key, 1, C)))).
|
2018-08-30 15:39:03 +00:00
|
|
|
-define(DEFAULT_LIMIT, 9001). % to emulate unlimited polling
|
2016-09-07 19:43:14 +00:00
|
|
|
|
|
|
|
-type test_case_name() :: atom().
|
|
|
|
-type group_name() :: atom().
|
|
|
|
|
|
|
|
-spec all() -> [{group, group_name()}].
|
|
|
|
all() ->
|
|
|
|
[
|
2018-07-06 13:33:49 +00:00
|
|
|
{group, basic_lifecycle_v3},
|
|
|
|
{group, migration_to_v4},
|
|
|
|
{group, basic_lifecycle_v4}
|
2016-09-07 19:43:14 +00:00
|
|
|
].
|
|
|
|
|
|
|
|
-spec groups() -> [{group_name(), list(), [test_case_name()]}].
|
|
|
|
groups() ->
|
|
|
|
[
|
2018-07-06 13:33:49 +00:00
|
|
|
{basic_lifecycle_v3, [sequence], [
|
2017-04-03 11:20:25 +00:00
|
|
|
pull_commit,
|
|
|
|
{group, basic_lifecycle}
|
|
|
|
]},
|
2018-07-06 13:33:49 +00:00
|
|
|
{basic_lifecycle_v4, [sequence], [
|
2017-04-03 11:20:25 +00:00
|
|
|
pull_commit,
|
2018-07-06 13:33:49 +00:00
|
|
|
{group, basic_lifecycle},
|
|
|
|
retry_commit
|
2017-04-03 11:20:25 +00:00
|
|
|
]},
|
2016-09-07 19:43:14 +00:00
|
|
|
{basic_lifecycle, [sequence, {repeat, 10}, shuffle], [
|
|
|
|
insert,
|
|
|
|
update,
|
|
|
|
delete
|
2018-07-06 13:33:49 +00:00
|
|
|
]},
|
|
|
|
{migration_to_v4, [sequence], [
|
|
|
|
migration_success
|
2016-09-07 19:43:14 +00:00
|
|
|
]}
|
|
|
|
].
|
|
|
|
|
|
|
|
%%
|
|
|
|
%% starting/stopping
|
|
|
|
-spec init_per_suite(config()) -> config().
|
|
|
|
init_per_suite(C) ->
|
2017-11-17 15:52:52 +00:00
|
|
|
Apps =
|
2018-07-06 13:33:49 +00:00
|
|
|
genlib_app:start_application_with(scoper, [
|
2019-06-25 16:08:15 +00:00
|
|
|
{storage, scoper_storage_logger}
|
2018-07-06 13:33:49 +00:00
|
|
|
]) ++
|
|
|
|
genlib_app:start_application_with(dmt_client, [
|
2017-11-17 15:52:52 +00:00
|
|
|
{cache_update_interval, 5000}, % milliseconds
|
2018-08-30 15:39:03 +00:00
|
|
|
{cache_update_pull_limit, ?DEFAULT_LIMIT},
|
2017-11-17 15:52:52 +00:00
|
|
|
{max_cache_size, #{
|
|
|
|
elements => 20,
|
|
|
|
memory => 52428800 % 50Mb
|
|
|
|
}},
|
|
|
|
{service_urls, #{
|
2019-06-25 16:08:15 +00:00
|
|
|
'Repository' => <<"http://dominant:8022/v1/domain/repository">>,
|
|
|
|
'RepositoryClient' => <<"http://dominant:8022/v1/domain/repository_client">>
|
2017-11-17 15:52:52 +00:00
|
|
|
}}
|
|
|
|
]),
|
2017-03-29 15:27:11 +00:00
|
|
|
[{suite_apps, Apps} | C].
|
2016-09-07 19:43:14 +00:00
|
|
|
|
|
|
|
-spec end_per_suite(config()) -> term().
|
|
|
|
end_per_suite(C) ->
|
2017-03-29 15:27:11 +00:00
|
|
|
genlib_app:stop_unload_applications(?config(suite_apps, C)).
|
|
|
|
|
|
|
|
-spec init_per_group(group_name(), config()) -> config().
|
2017-11-16 16:41:03 +00:00
|
|
|
init_per_group(basic_lifecycle_v3, C) ->
|
|
|
|
[{group_apps, start_with_repository(dmt_api_repository_v3)} | C];
|
2018-07-06 13:33:49 +00:00
|
|
|
init_per_group(basic_lifecycle_v4, C) ->
|
|
|
|
[{group_apps, start_with_repository(dmt_api_repository_v4)} | C];
|
|
|
|
init_per_group(migration_to_v4, C) ->
|
|
|
|
[{group_apps, genlib_app:start_application_with(dmt_api, [
|
|
|
|
{repository, dmt_api_repository_migration},
|
|
|
|
{migration, #{
|
|
|
|
timeout => 360,
|
|
|
|
limit => 20
|
|
|
|
}},
|
|
|
|
{automaton_service_url, "http://machinegun:8022/v1/automaton"},
|
|
|
|
{max_cache_size, 2048} % 2Kb
|
|
|
|
])} | C];
|
2017-03-29 15:27:11 +00:00
|
|
|
init_per_group(_, C) ->
|
|
|
|
C.
|
|
|
|
|
|
|
|
start_with_repository(Repository) ->
|
|
|
|
genlib_app:start_application_with(dmt_api, [
|
|
|
|
{repository, Repository},
|
2017-05-17 21:24:55 +00:00
|
|
|
{automaton_service_url, "http://machinegun:8022/v1/automaton"},
|
2018-07-06 13:33:49 +00:00
|
|
|
{max_cache_size, 52428800} % 50Mb
|
2017-03-29 15:27:11 +00:00
|
|
|
]).
|
|
|
|
|
|
|
|
-spec end_per_group(group_name(), config()) -> term().
|
2018-07-06 13:33:49 +00:00
|
|
|
end_per_group(Group, C) when
|
|
|
|
Group =:= basic_lifecycle_v3 orelse
|
|
|
|
Group =:= basic_lifecycle_v4 orelse
|
|
|
|
Group =:= migration_to_v4
|
|
|
|
->
|
2017-11-16 16:41:03 +00:00
|
|
|
genlib_app:stop_unload_applications(?config(group_apps, C));
|
2017-03-29 15:27:11 +00:00
|
|
|
end_per_group(_, _C) ->
|
|
|
|
ok.
|
2016-09-07 19:43:14 +00:00
|
|
|
|
2018-07-17 11:17:53 +00:00
|
|
|
-spec init_per_testcase(test_case_name(), config()) -> config().
|
|
|
|
init_per_testcase(_, C) ->
|
|
|
|
%% added because dmt_client:checkout({head, #'Head'{}})
|
|
|
|
%% could return old version from cache overwise
|
|
|
|
{ok, _Version} = dmt_client_cache:update(),
|
|
|
|
C.
|
|
|
|
|
|
|
|
-spec end_per_testcase(test_case_name(), config()) -> term().
|
|
|
|
end_per_testcase(_, _) ->
|
|
|
|
ok.
|
2016-09-07 19:43:14 +00:00
|
|
|
%%
|
|
|
|
%% tests
|
|
|
|
|
|
|
|
-spec insert(term()) -> term().
|
|
|
|
insert(_C) ->
|
|
|
|
ID = next_id(),
|
|
|
|
Object = fixture_domain_object(ID, <<"InsertFixture">>),
|
|
|
|
Ref = fixture_object_ref(ID),
|
2018-07-17 11:17:53 +00:00
|
|
|
#'ObjectNotFound'{} = (catch dmt_client:checkout_object({head, #'Head'{}}, Ref)),
|
|
|
|
#'Snapshot'{version = Version1} = dmt_client:checkout({head, #'Head'{}}),
|
|
|
|
Version2 = dmt_client:commit(Version1, #'Commit'{ops = [{insert, #'InsertOp'{object = Object}}]}),
|
|
|
|
_ = dmt_client_cache:update(),
|
|
|
|
#'VersionedObject'{object = Object} = dmt_client:checkout_object({head, #'Head'{}}, Ref),
|
|
|
|
#'ObjectNotFound'{} = (catch dmt_client:checkout_object({version, Version1}, Ref)),
|
|
|
|
#'VersionedObject'{object = Object} = dmt_client:checkout_object({version, Version2}, Ref).
|
2016-09-07 19:43:14 +00:00
|
|
|
|
|
|
|
-spec update(term()) -> term().
|
|
|
|
update(_C) ->
|
|
|
|
ID = next_id(),
|
|
|
|
Object1 = fixture_domain_object(ID, <<"UpdateFixture1">>),
|
|
|
|
Object2 = fixture_domain_object(ID, <<"UpdateFixture2">>),
|
|
|
|
Ref = fixture_object_ref(ID),
|
2018-07-17 11:17:53 +00:00
|
|
|
#'Snapshot'{version = Version0} = dmt_client:checkout({head, #'Head'{}}),
|
|
|
|
Version1 = dmt_client:commit(Version0, #'Commit'{ops = [{insert, #'InsertOp'{object = Object1}}]}),
|
|
|
|
Version2 = dmt_client:commit(
|
2016-09-07 19:43:14 +00:00
|
|
|
Version1,
|
|
|
|
#'Commit'{ops = [{update, #'UpdateOp'{old_object = Object1, new_object = Object2}}]}
|
|
|
|
),
|
2018-07-17 11:17:53 +00:00
|
|
|
_ = dmt_client_cache:update(),
|
|
|
|
#'VersionedObject'{object = Object1} = dmt_client:checkout_object({version, Version1}, Ref),
|
|
|
|
#'VersionedObject'{object = Object2} = dmt_client:checkout_object({version, Version2}, Ref).
|
2016-09-07 19:43:14 +00:00
|
|
|
|
|
|
|
-spec delete(term()) -> term().
|
|
|
|
delete(_C) ->
|
|
|
|
ID = next_id(),
|
|
|
|
Object = fixture_domain_object(ID, <<"DeleteFixture">>),
|
|
|
|
Ref = fixture_object_ref(ID),
|
2018-07-17 11:17:53 +00:00
|
|
|
#'Snapshot'{version = Version0} = dmt_client:checkout({head, #'Head'{}}),
|
|
|
|
Version1 = dmt_client:commit(Version0, #'Commit'{ops = [{insert, #'InsertOp'{object = Object}}]}),
|
|
|
|
Version2 = dmt_client:commit(Version1, #'Commit'{ops = [{remove, #'RemoveOp'{object = Object}}]}),
|
|
|
|
_ = dmt_client_cache:update(),
|
|
|
|
#'VersionedObject'{object = Object} = dmt_client:checkout_object({version, Version1}, Ref),
|
|
|
|
#'ObjectNotFound'{} = (catch dmt_client:checkout_object({version, Version2}, Ref)).
|
2016-09-07 19:43:14 +00:00
|
|
|
|
2017-04-03 11:20:25 +00:00
|
|
|
-spec pull_commit(term()) -> term().
|
|
|
|
pull_commit(_C) ->
|
|
|
|
ID = next_id(),
|
2018-08-30 15:39:03 +00:00
|
|
|
History1 = #{} = dmt_client:pull_range(0, ?DEFAULT_LIMIT),
|
2017-04-03 11:20:25 +00:00
|
|
|
Version1 = lists:max([0 | maps:keys(History1)]),
|
|
|
|
Object = fixture_domain_object(ID, <<"PullFixture">>),
|
|
|
|
Commit = #'Commit'{ops = [{insert, #'InsertOp'{object = Object}}]},
|
2018-07-17 11:17:53 +00:00
|
|
|
Version2 = dmt_client:commit(Version1, Commit),
|
2018-08-30 15:39:03 +00:00
|
|
|
#{Version2 := Commit} = dmt_client:pull_range(Version1, ?DEFAULT_LIMIT).
|
2017-04-03 11:20:25 +00:00
|
|
|
|
2018-07-06 13:33:49 +00:00
|
|
|
-spec retry_commit(term()) -> term().
|
|
|
|
retry_commit(_C) ->
|
|
|
|
Commit1 = #'Commit'{ops = [{insert, #'InsertOp'{
|
|
|
|
object = fixture_domain_object(next_id(), <<"RetryCommitFixture">>)
|
|
|
|
}}]},
|
2018-07-17 11:17:53 +00:00
|
|
|
#'Snapshot'{version = Version1} = dmt_client:checkout({head, #'Head'{}}),
|
|
|
|
Version2 = dmt_client:commit(Version1, Commit1),
|
2018-07-06 13:33:49 +00:00
|
|
|
Version2 = Version1 + 1,
|
2018-07-17 11:17:53 +00:00
|
|
|
Version2 = dmt_client:commit(Version1, Commit1),
|
|
|
|
_ = dmt_client_cache:update(),
|
|
|
|
#'Snapshot'{version = Version2} = dmt_client:checkout({head, #'Head'{}}),
|
2018-07-06 13:33:49 +00:00
|
|
|
Commit2 = #'Commit'{ops = [{insert, #'InsertOp'{
|
|
|
|
object = fixture_domain_object(next_id(), <<"RetryCommitFixture">>)
|
|
|
|
}}]},
|
2018-07-17 11:17:53 +00:00
|
|
|
Version3 = dmt_client:commit(Version2, Commit2),
|
2018-07-06 13:33:49 +00:00
|
|
|
Version3 = Version2 + 1,
|
2018-07-17 11:17:53 +00:00
|
|
|
Version2 = dmt_client:commit(Version1, Commit1),
|
|
|
|
_ = dmt_client_cache:update(),
|
|
|
|
#'Snapshot'{version = Version3} = dmt_client:checkout({head, #'Head'{}}).
|
2018-07-06 13:33:49 +00:00
|
|
|
|
|
|
|
-spec migration_success(term()) -> term().
|
|
|
|
migration_success(_C) ->
|
2018-07-17 11:17:53 +00:00
|
|
|
#'Snapshot'{version = VersionV3} = dmt_client:checkout({head, #'Head'{}}),
|
2018-07-06 13:33:49 +00:00
|
|
|
true = VersionV3 > 0,
|
|
|
|
VersionV4 = wait_for_migration(VersionV3, 20, 1000),
|
|
|
|
VersionV4 = VersionV3 + 1.
|
|
|
|
|
|
|
|
wait_for_migration(V, TriesLeft, SleepInterval) when TriesLeft > 0 ->
|
|
|
|
ID = next_id(),
|
|
|
|
Object = fixture_domain_object(ID, <<"MigrationCommitFixture">>),
|
|
|
|
Commit = #'Commit'{ops = [{insert, #'InsertOp'{object = Object}}]},
|
|
|
|
try
|
2018-07-17 11:17:53 +00:00
|
|
|
dmt_client:commit(V, Commit)
|
2018-07-06 13:33:49 +00:00
|
|
|
catch
|
|
|
|
_Class:_Reason ->
|
|
|
|
timer:sleep(SleepInterval),
|
|
|
|
wait_for_migration(V, TriesLeft - 1, SleepInterval)
|
|
|
|
end;
|
|
|
|
wait_for_migration(_, _, _) ->
|
|
|
|
error(wait_for_migration_failed).
|
|
|
|
|
2016-09-07 19:43:14 +00:00
|
|
|
next_id() ->
|
|
|
|
erlang:system_time(micro_seconds) band 16#7FFFFFFF.
|
|
|
|
|
|
|
|
fixture_domain_object(Ref, Data) ->
|
2016-10-14 17:48:54 +00:00
|
|
|
{category, #domain_CategoryObject{
|
|
|
|
ref = #domain_CategoryRef{id = Ref},
|
|
|
|
data = #domain_Category{name = Data, description = Data}
|
2016-09-07 19:43:14 +00:00
|
|
|
}}.
|
|
|
|
|
|
|
|
fixture_object_ref(Ref) ->
|
2016-10-14 17:48:54 +00:00
|
|
|
{category, #domain_CategoryRef{id = Ref}}.
|