mirror of
https://github.com/valitydev/dominant.git
synced 2024-11-06 02:25:17 +00:00
OPS-161: Use modernizer facility to migrate domain-config (#20)
So that valitydev/damsel@09e7a75 might be dropped after migration. * Bump to valitydev/machinery-erlang@19cdc6c
This commit is contained in:
parent
4e01fe45ba
commit
6f4ec7d9b8
@ -63,10 +63,11 @@
|
||||
{profiles, [
|
||||
{test, [
|
||||
{deps, [
|
||||
{meck, "0.9.2"},
|
||||
{dmt_client, {git, "https://github.com/valitydev/dmt-client.git", {ref, "ce6678a"}}}
|
||||
]},
|
||||
{dialyzer, [
|
||||
{plt_extra_apps, [dmt_client]}
|
||||
{plt_extra_apps, [meck, dmt_client]}
|
||||
]}
|
||||
]},
|
||||
{prod, [
|
||||
|
@ -38,12 +38,12 @@
|
||||
{<<"jsx">>,{pkg,<<"jsx">>,<<"3.1.0">>},1},
|
||||
{<<"machinery">>,
|
||||
{git,"https://github.com/valitydev/machinery-erlang.git",
|
||||
{ref,"4c0382f6cb14ebea361909c2a0e06efe0fc0d505"}},
|
||||
{ref,"19cdc6c846f0ebf65ae193ca0988e353e53fe1d5"}},
|
||||
0},
|
||||
{<<"metrics">>,{pkg,<<"metrics">>,<<"1.0.1">>},2},
|
||||
{<<"mg_proto">>,
|
||||
{git,"https://github.com/valitydev/machinegun-proto.git",
|
||||
{ref,"a411c7d5d779389c70d2594eb4a28a916dce1721"}},
|
||||
{git,"https://github.com/valitydev/machinegun-proto",
|
||||
{ref,"96f7f11b184c29d8b7e83cd7646f3f2c13662bda"}},
|
||||
1},
|
||||
{<<"mimerl">>,{pkg,<<"mimerl">>,<<"1.2.0">>},2},
|
||||
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.3.1">>},2},
|
||||
|
@ -54,8 +54,8 @@ get_repository_handlers() ->
|
||||
get_handler(repository_client, #{
|
||||
repository => Repository,
|
||||
default_handling_timeout => DefaultTimeout
|
||||
}),
|
||||
get_machinery_handler(Repository)
|
||||
})
|
||||
| get_machinery_handlers(Repository)
|
||||
].
|
||||
|
||||
-spec get_handler(repository | repository_client | state_processor, woody:options()) ->
|
||||
@ -71,15 +71,23 @@ get_handler(repository_client, Options) ->
|
||||
{dmt_api_repository_client_handler, Options}
|
||||
}}.
|
||||
|
||||
-spec get_machinery_handler(module()) ->
|
||||
woody:http_handler(woody:th_handler()).
|
||||
get_machinery_handler(Repository) ->
|
||||
machinery_mg_backend:get_handler(
|
||||
{Repository, #{
|
||||
path => "/v1/stateproc",
|
||||
backend_config => #{schema => Repository}
|
||||
}}
|
||||
).
|
||||
-spec get_machinery_handlers(module()) ->
|
||||
[woody:http_handler(woody:th_handler())].
|
||||
get_machinery_handlers(Repository) ->
|
||||
[
|
||||
machinery_mg_backend:get_handler(
|
||||
{Repository, #{
|
||||
path => "/v1/stateproc",
|
||||
backend_config => #{schema => Repository}
|
||||
}}
|
||||
),
|
||||
machinery_modernizer_mg_backend:get_handler(
|
||||
#{
|
||||
path => <<"/v1/modernizer">>,
|
||||
backend_config => #{schema => Repository}
|
||||
}
|
||||
)
|
||||
].
|
||||
|
||||
-spec enable_health_logging(erl_health:check()) -> erl_health:check().
|
||||
enable_health_logging(Check) ->
|
||||
|
48
src/dmt_api_repository_migration.erl
Normal file
48
src/dmt_api_repository_migration.erl
Normal file
@ -0,0 +1,48 @@
|
||||
-module(dmt_api_repository_migration).
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
|
||||
-export([migrate/2]).
|
||||
|
||||
-type snapshot() :: dmt_api_repository:snapshot().
|
||||
-type commit() :: dmt_api_repository:commit().
|
||||
-type version() :: dmt_api_repository:version().
|
||||
|
||||
-spec migrate
|
||||
(version(), commit()) -> commit();
|
||||
(version(), snapshot()) -> snapshot().
|
||||
migrate(1, Data) ->
|
||||
migrate_legacy_payment_system_conditions(Data).
|
||||
|
||||
migrate_legacy_payment_system_conditions(Data) ->
|
||||
% TODO OPS-161
|
||||
% Relevant for https://github.com/valitydev/damsel/commit/09e7a75, revert this commit after
|
||||
% complete migration.
|
||||
% Replaces any `BankCardCondition` in a commit or snapshot which represents legacy payment
|
||||
% system condition (i.e. one that compares against an atom in % `LegacyBankCardPaymentSystem`
|
||||
% enum) with an empty `BankCardCondition`. Obviously, this incurs information loss yet
|
||||
% significantly easier than proper mapping. Two reasons why this looks valid:
|
||||
% - Production domain config do not contain legacy conditions anywhere in the last 3 months
|
||||
% of snapshots.
|
||||
% - https://github.com/valitydev/party-management since at least bb4549c won't handle them
|
||||
% anyway.
|
||||
genlib_ted:run(
|
||||
fun
|
||||
(Condition = #domain_BankCardCondition{}, _Annos) ->
|
||||
{replace, migrate_legacy_payment_system_condition(Condition)};
|
||||
(_, _Annos) ->
|
||||
proceed
|
||||
end,
|
||||
Data
|
||||
).
|
||||
|
||||
migrate_legacy_payment_system_condition(Condition) ->
|
||||
case Condition#domain_BankCardCondition.definition of
|
||||
{payment_system_is, Legacy} ->
|
||||
true = is_atom(Legacy),
|
||||
Condition#domain_BankCardCondition{definition = undefined};
|
||||
{_, _} ->
|
||||
Condition;
|
||||
undefined ->
|
||||
Condition
|
||||
end.
|
@ -41,6 +41,10 @@
|
||||
-export([unmarshal/3]).
|
||||
-export([get_version/1]).
|
||||
|
||||
%% NOTE
|
||||
%% Used in migration tests.
|
||||
-export([modernize/1]).
|
||||
|
||||
%%
|
||||
-record(st, {
|
||||
snapshot = #domain_conf_Snapshot{version = 0, domain = dmt_domain:new()} :: snapshot(),
|
||||
@ -117,10 +121,17 @@ get_history_by_range(HistoryRange, WoodyCtx) ->
|
||||
|
||||
-spec get_backend(woody_context:ctx()) -> machinery_mg_backend:backend().
|
||||
get_backend(WoodyCtx) ->
|
||||
machinery_mg_backend:new(WoodyCtx, #{
|
||||
machinery_mg_backend:new(WoodyCtx, get_backend_config()).
|
||||
|
||||
-spec get_modernizer_backend(woody_context:ctx()) -> machinery_modernizer_mg_backend:backend().
|
||||
get_modernizer_backend(WoodyCtx) ->
|
||||
machinery_modernizer_mg_backend:new(WoodyCtx, get_backend_config()).
|
||||
|
||||
get_backend_config() ->
|
||||
#{
|
||||
client => dmt_api_woody_utils:get_woody_client(automaton),
|
||||
schema => ?MODULE
|
||||
}).
|
||||
}.
|
||||
|
||||
%%
|
||||
|
||||
@ -230,6 +241,10 @@ make_event(Snapshot, Commit) ->
|
||||
|
||||
%%
|
||||
|
||||
-spec modernize(woody_context:ctx()) -> ok.
|
||||
modernize(WoodyCtx) ->
|
||||
machinery_modernizer:modernize(?NS, ?ID, get_modernizer_backend(WoodyCtx)).
|
||||
|
||||
-spec marshal(machinery_mg_schema:t(), machinery_mg_schema:v(_), machinery_mg_schema:context()) ->
|
||||
{machinery_msgpack:t(), machinery_mg_schema:context()}.
|
||||
marshal({event, FmtVsn}, V, C) ->
|
||||
@ -252,26 +267,53 @@ unmarshal({response, call}, V, C) ->
|
||||
unmarshal(T, V, C) ->
|
||||
machinery_mg_schema_generic:unmarshal(T, V, C).
|
||||
|
||||
%%
|
||||
|
||||
-spec get_version(machinery_mg_schema:vt()) -> machinery_mg_schema:version().
|
||||
get_version(_) ->
|
||||
1.
|
||||
% NOTE
|
||||
% Current format version.
|
||||
% Be aware, this function is being mocked in the testsuite.
|
||||
2.
|
||||
|
||||
encode_event_data(1 = FmtVsn, {commit, Commit, Meta}) ->
|
||||
encode_event_data(FmtVsn, {commit, CommitIn, Meta}) ->
|
||||
% NOTE
|
||||
% Ensure that outdated commit won't sneak in.
|
||||
Commit = migrate(1, get_version(event), commit, CommitIn),
|
||||
{arr, [{str, <<"commit">>}, encode(commit, Commit), encode_commit_meta(FmtVsn, Meta)]}.
|
||||
|
||||
encode_commit_meta(1, #{snapshot := Snapshot}) ->
|
||||
encode_commit_meta(_FmtVsn, #{snapshot := SnapshotIn}) ->
|
||||
% NOTE
|
||||
% Ensure that outdated snapshot won't sneak in.
|
||||
Snapshot = migrate(1, get_version(event), snapshot, SnapshotIn),
|
||||
{obj, #{{str, <<"snapshot">>} => encode(snapshot, Snapshot)}};
|
||||
encode_commit_meta(1, #{}) ->
|
||||
encode_commit_meta(_FmtVsn, #{}) ->
|
||||
{obj, #{}}.
|
||||
|
||||
decode_event_data(1 = FmtVsn, {arr, [{str, <<"commit">>}, Commit, Meta]}) ->
|
||||
{commit, decode(commit, Commit), decode_commit_meta(FmtVsn, Meta)}.
|
||||
decode_event_data(FmtVsn, {arr, [{str, <<"commit">>}, CommitEnc, Meta]}) when
|
||||
is_integer(FmtVsn), FmtVsn > 0
|
||||
->
|
||||
Commit = migrate(FmtVsn, get_version(event), commit, decode(commit, CommitEnc)),
|
||||
{commit, Commit, decode_commit_meta(FmtVsn, Meta)}.
|
||||
|
||||
decode_commit_meta(1, {obj, #{{str, <<"snapshot">>} := Snapshot}}) ->
|
||||
#{snapshot => decode(snapshot, Snapshot)};
|
||||
decode_commit_meta(1, {obj, #{}}) ->
|
||||
decode_commit_meta(FmtVsn, {obj, #{{str, <<"snapshot">>} := SnapshotEnc}}) ->
|
||||
Snapshot = migrate(FmtVsn, get_version(event), snapshot, decode(snapshot, SnapshotEnc)),
|
||||
#{snapshot => Snapshot};
|
||||
decode_commit_meta(_FmtVsn, {obj, #{}}) ->
|
||||
#{}.
|
||||
|
||||
migrate(TargetVsn, TargetVsn, _Type, Data) ->
|
||||
% Nothing to migrate.
|
||||
Data;
|
||||
migrate(Vsn, TargetVsn, Type, Data) when Vsn < TargetVsn ->
|
||||
Migrated = dmt_api_repository_migration:migrate(Vsn, Data),
|
||||
ok = validate(Type, Migrated),
|
||||
migrate(Vsn + 1, TargetVsn, Type, Migrated).
|
||||
|
||||
validate(T, V) ->
|
||||
_ = encode(T, V),
|
||||
ok.
|
||||
|
||||
%%
|
||||
|
||||
encode_call({commit, Version, Commit}) ->
|
||||
|
193
test/dmt_api_migration_tests_SUITE.erl
Normal file
193
test/dmt_api_migration_tests_SUITE.erl
Normal file
@ -0,0 +1,193 @@
|
||||
-module(dmt_api_migration_tests_SUITE).
|
||||
|
||||
-include_lib("stdlib/include/assert.hrl").
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_thrift.hrl").
|
||||
-include_lib("damsel/include/dmsl_domain_conf_thrift.hrl").
|
||||
|
||||
-export([all/0]).
|
||||
-export([init_per_suite/1]).
|
||||
-export([end_per_suite/1]).
|
||||
-export([init_per_testcase/2]).
|
||||
-export([end_per_testcase/2]).
|
||||
|
||||
-export([fv2_migration_succeeds/1]).
|
||||
-export([fv2_modernization_succeeds/1]).
|
||||
|
||||
-type config() :: [{atom(), term()}].
|
||||
-type test_case_name() :: atom().
|
||||
|
||||
-define(CONF(Key, C), (element(2, lists:keyfind(Key, 1, C)))).
|
||||
|
||||
-define(REPOSITORY, dmt_api_repository_v5).
|
||||
|
||||
%%
|
||||
|
||||
-spec all() -> [test_case_name()].
|
||||
all() ->
|
||||
[
|
||||
fv2_migration_succeeds,
|
||||
fv2_modernization_succeeds
|
||||
].
|
||||
|
||||
-spec init_per_suite(config()) -> config().
|
||||
init_per_suite(C) ->
|
||||
Apps1 = genlib_app:start_application_with(scoper, [
|
||||
{storage, scoper_storage_logger}
|
||||
]),
|
||||
Apps2 = genlib_app:start_application_with(dmt_api, [
|
||||
{repository, ?REPOSITORY},
|
||||
% NOTE
|
||||
% Effectively disable cache altogether so it won't spoil testcase expectations.
|
||||
% Keep in mind that in production setting this cache will certainly affect migrations'
|
||||
% visibility.
|
||||
{max_cache_size, 0},
|
||||
{services, #{
|
||||
automaton => #{
|
||||
url => "http://machinegun:8022/v1/automaton"
|
||||
}
|
||||
}}
|
||||
]),
|
||||
|
||||
Apps3 = genlib_app:start_application_with(dmt_client, [
|
||||
{max_cache_size, #{
|
||||
elements => 1,
|
||||
memory => 102400
|
||||
}},
|
||||
{service_urls, #{
|
||||
'Repository' => <<"http://dominant:8022/v1/domain/repository">>,
|
||||
'RepositoryClient' => <<"http://dominant:8022/v1/domain/repository_client">>
|
||||
}}
|
||||
]),
|
||||
ok = logger:set_primary_config(level, info),
|
||||
[{suite_apps, Apps1 ++ Apps2 ++ Apps3} | C].
|
||||
|
||||
-spec end_per_suite(config()) -> term().
|
||||
end_per_suite(C) ->
|
||||
genlib_app:stop_unload_applications(?CONF(suite_apps, C)).
|
||||
|
||||
-spec init_per_testcase(test_case_name(), config()) -> config().
|
||||
init_per_testcase(Name, C) ->
|
||||
_ = meck:unload(),
|
||||
WoodyCtx = woody_context:new(mk_rpc_id(Name)),
|
||||
[{woody_ctx, WoodyCtx}, {dmt_client_opts, #{woody_context => WoodyCtx}} | C].
|
||||
|
||||
mk_rpc_id(Name) ->
|
||||
TraceID = genlib:format("~s:~p", [Name, erlang:system_time(millisecond)]),
|
||||
woody_context:new_rpc_id(<<"undefined">>, TraceID, woody_context:new_req_id()).
|
||||
|
||||
-spec end_per_testcase(test_case_name(), config()) -> _.
|
||||
end_per_testcase(_, _) ->
|
||||
ok.
|
||||
|
||||
%%
|
||||
|
||||
-define(FMT_VSN_INITIAL, 1).
|
||||
-define(FMT_VSN_TARGET, 2).
|
||||
|
||||
-define(LEGACY_CONDITION,
|
||||
{payment_tool,
|
||||
{bank_card, #domain_BankCardCondition{
|
||||
definition = {payment_system_is, uzcard}
|
||||
}}}
|
||||
).
|
||||
|
||||
-define(TARGET_CONDITION,
|
||||
{payment_tool,
|
||||
{bank_card, #domain_BankCardCondition{
|
||||
definition = undefined
|
||||
}}}
|
||||
).
|
||||
|
||||
-spec fv2_migration_succeeds(config()) -> _.
|
||||
fv2_migration_succeeds(C) ->
|
||||
ClientOpts = ?CONF(dmt_client_opts, C),
|
||||
ok = meck:new(dmt_api_repository_v5, [passthrough]),
|
||||
ok = meck:expect(dmt_api_repository_v5, get_version, fun(_) -> ?FMT_VSN_INITIAL end),
|
||||
Version1 = get_latest_version(ClientOpts),
|
||||
ObjectRef1 = #domain_CriterionRef{id = dmt_ct_helper:next_id()},
|
||||
Commit1 = dmt_ct_helper:mk_insert_commit(
|
||||
{criterion, #domain_CriterionObject{
|
||||
ref = ObjectRef1,
|
||||
data = #domain_Criterion{
|
||||
name = <<"Legacy Criterion 1">>,
|
||||
predicate = {condition, ?LEGACY_CONDITION}
|
||||
}
|
||||
}}
|
||||
),
|
||||
Version2 = dmt_client_api:commit(Version1, Commit1, ClientOpts),
|
||||
ok = meck:expect(dmt_api_repository_v5, get_version, fun(_) -> ?FMT_VSN_TARGET end),
|
||||
Snapshot2 = checkout(Version2, ClientOpts),
|
||||
?assertMatch(
|
||||
{criterion, #domain_CriterionObject{
|
||||
data = #domain_Criterion{
|
||||
predicate = {condition, ?TARGET_CONDITION}
|
||||
}
|
||||
}},
|
||||
get_domain_object({criterion, ObjectRef1}, Snapshot2)
|
||||
),
|
||||
ObjectRef2 = #domain_CriterionRef{id = dmt_ct_helper:next_id()},
|
||||
Commit2 = dmt_ct_helper:mk_insert_commit(
|
||||
{criterion, #domain_CriterionObject{
|
||||
ref = ObjectRef2,
|
||||
data = #domain_Criterion{
|
||||
name = <<"Legacy Criterion 2">>,
|
||||
predicate = {condition, ?LEGACY_CONDITION}
|
||||
}
|
||||
}}
|
||||
),
|
||||
Version3 = dmt_client_api:commit(Version2, Commit2, ClientOpts),
|
||||
Snapshot3 = checkout(Version3, ClientOpts),
|
||||
?assertMatch(
|
||||
{criterion, #domain_CriterionObject{
|
||||
data = #domain_Criterion{
|
||||
predicate = {condition, ?TARGET_CONDITION}
|
||||
}
|
||||
}},
|
||||
get_domain_object({criterion, ObjectRef2}, Snapshot3)
|
||||
),
|
||||
ok = meck:unload(dmt_api_repository_v5).
|
||||
|
||||
-spec fv2_modernization_succeeds(config()) -> _.
|
||||
fv2_modernization_succeeds(C) ->
|
||||
ClientOpts = ?CONF(dmt_client_opts, C),
|
||||
ok = meck:new(dmt_api_repository_v5, [passthrough]),
|
||||
ok = meck:expect(dmt_api_repository_v5, get_version, fun(_) -> ?FMT_VSN_INITIAL end),
|
||||
Version1 = get_latest_version(ClientOpts),
|
||||
ObjectRef = #domain_CriterionRef{id = dmt_ct_helper:next_id()},
|
||||
Commit = dmt_ct_helper:mk_insert_commit(
|
||||
{criterion, #domain_CriterionObject{
|
||||
ref = ObjectRef,
|
||||
data = #domain_Criterion{
|
||||
name = <<"Legacy Criterion">>,
|
||||
predicate = {condition, ?LEGACY_CONDITION}
|
||||
}
|
||||
}}
|
||||
),
|
||||
Version2 = dmt_client_api:commit(Version1, Commit, #{}),
|
||||
ok = meck:expect(dmt_api_repository_v5, get_version, fun(_) -> ?FMT_VSN_TARGET end),
|
||||
ok = dmt_api_repository_v5:modernize(?CONF(woody_ctx, C)),
|
||||
Snapshot2 = checkout(Version2, ClientOpts),
|
||||
?assertMatch(
|
||||
{criterion, #domain_CriterionObject{
|
||||
data = #domain_Criterion{
|
||||
predicate = {condition, ?TARGET_CONDITION}
|
||||
}
|
||||
}},
|
||||
get_domain_object({criterion, ObjectRef}, Snapshot2)
|
||||
),
|
||||
ok = meck:unload(dmt_api_repository_v5).
|
||||
|
||||
%%
|
||||
|
||||
checkout(head, ClientOpts) ->
|
||||
dmt_client_api:checkout({head, #domain_conf_Head{}}, ClientOpts);
|
||||
checkout(Version, ClientOpts) when is_integer(Version) ->
|
||||
dmt_client_api:checkout({version, Version}, ClientOpts).
|
||||
|
||||
get_latest_version(ClientOpts) ->
|
||||
Snapshot = checkout(head, ClientOpts),
|
||||
Snapshot#domain_conf_Snapshot.version.
|
||||
|
||||
get_domain_object(ObjectRef, #domain_conf_Snapshot{domain = Domain}) ->
|
||||
maps:get(ObjectRef, Domain).
|
@ -154,10 +154,7 @@ insert(_C) ->
|
||||
Ref = fixture_object_ref(ID),
|
||||
#domain_conf_ObjectNotFound{} = (catch dmt_client:checkout_object(Ref)),
|
||||
#domain_conf_Snapshot{version = Version1} = dmt_client:checkout(latest),
|
||||
Version2 = dmt_client:commit(
|
||||
Version1,
|
||||
#domain_conf_Commit{ops = [{insert, #domain_conf_InsertOp{object = Object}}]}
|
||||
),
|
||||
Version2 = dmt_client:insert(Version1, Object),
|
||||
_ = dmt_client_cache:update(),
|
||||
Object = dmt_client:checkout_object(Ref),
|
||||
#domain_conf_ObjectNotFound{} = (catch dmt_client:checkout_object(Version1, Ref)),
|
||||
@ -170,14 +167,8 @@ update(_C) ->
|
||||
Object2 = fixture_domain_object(ID, <<"UpdateFixture2">>),
|
||||
Ref = fixture_object_ref(ID),
|
||||
#domain_conf_Snapshot{version = Version0} = dmt_client:checkout(latest),
|
||||
Version1 = dmt_client:commit(
|
||||
Version0,
|
||||
#domain_conf_Commit{ops = [{insert, #domain_conf_InsertOp{object = Object1}}]}
|
||||
),
|
||||
Version2 = dmt_client:commit(
|
||||
Version1,
|
||||
#domain_conf_Commit{ops = [{update, #domain_conf_UpdateOp{old_object = Object1, new_object = Object2}}]}
|
||||
),
|
||||
Version1 = dmt_client:commit(Version0, dmt_ct_helper:mk_insert_commit(Object1)),
|
||||
Version2 = dmt_client:commit(Version1, dmt_ct_helper:mk_update_commit(Object1, Object2)),
|
||||
_ = dmt_client_cache:update(),
|
||||
Object1 = dmt_client:checkout_object(Version1, Ref),
|
||||
Object2 = dmt_client:checkout_object(Version2, Ref).
|
||||
@ -188,14 +179,8 @@ delete(_C) ->
|
||||
Object = fixture_domain_object(ID, <<"DeleteFixture">>),
|
||||
Ref = fixture_object_ref(ID),
|
||||
#domain_conf_Snapshot{version = Version0} = dmt_client:checkout(latest),
|
||||
Version1 = dmt_client:commit(
|
||||
Version0,
|
||||
#domain_conf_Commit{ops = [{insert, #domain_conf_InsertOp{object = Object}}]}
|
||||
),
|
||||
Version2 = dmt_client:commit(
|
||||
Version1,
|
||||
#domain_conf_Commit{ops = [{remove, #domain_conf_RemoveOp{object = Object}}]}
|
||||
),
|
||||
Version1 = dmt_client:commit(Version0, dmt_ct_helper:mk_insert_commit(Object)),
|
||||
Version2 = dmt_client:commit(Version1, dmt_ct_helper:mk_remove_commit(Object)),
|
||||
Object = dmt_client:checkout_object(Version1, Ref),
|
||||
#domain_conf_ObjectNotFound{} = (catch dmt_client:checkout_object(Version2, Ref)).
|
||||
|
||||
@ -205,31 +190,23 @@ pull_commit(_C) ->
|
||||
History1 = #{} = dmt_client:pull_range(0, ?DEFAULT_LIMIT),
|
||||
Version1 = lists:max([0 | maps:keys(History1)]),
|
||||
Object = fixture_domain_object(ID, <<"PullFixture">>),
|
||||
Commit = #domain_conf_Commit{ops = [{insert, #domain_conf_InsertOp{object = Object}}]},
|
||||
Commit = dmt_ct_helper:mk_insert_commit(Object),
|
||||
Version2 = dmt_client:commit(Version1, Commit),
|
||||
#{Version2 := Commit} = dmt_client:pull_range(Version1, ?DEFAULT_LIMIT).
|
||||
|
||||
-spec retry_commit(term()) -> term().
|
||||
retry_commit(_C) ->
|
||||
Commit1 = #domain_conf_Commit{
|
||||
ops = [
|
||||
{insert, #domain_conf_InsertOp{
|
||||
object = fixture_domain_object(next_id(), <<"RetryCommitFixture">>)
|
||||
}}
|
||||
]
|
||||
},
|
||||
Commit1 = dmt_ct_helper:mk_insert_commit(
|
||||
fixture_domain_object(next_id(), <<"RetryCommitFixture">>)
|
||||
),
|
||||
#domain_conf_Snapshot{version = Version1} = dmt_client:checkout(latest),
|
||||
Version2 = dmt_client:commit(Version1, Commit1),
|
||||
Version2 = Version1 + 1,
|
||||
Version2 = dmt_client:commit(Version1, Commit1),
|
||||
#domain_conf_Snapshot{version = Version2} = dmt_client:checkout(latest),
|
||||
Commit2 = #domain_conf_Commit{
|
||||
ops = [
|
||||
{insert, #domain_conf_InsertOp{
|
||||
object = fixture_domain_object(next_id(), <<"RetryCommitFixture">>)
|
||||
}}
|
||||
]
|
||||
},
|
||||
Commit2 = dmt_ct_helper:mk_insert_commit(
|
||||
fixture_domain_object(next_id(), <<"RetryCommitFixture">>)
|
||||
),
|
||||
Version3 = dmt_client:commit(Version2, Commit2),
|
||||
Version3 = Version2 + 1,
|
||||
Version2 = dmt_client:commit(Version1, Commit1),
|
||||
@ -240,34 +217,20 @@ missing_version(_C) ->
|
||||
#domain_conf_Snapshot{version = Version1} = dmt_client:checkout(latest),
|
||||
_ = ?assertThrow(
|
||||
#domain_conf_VersionNotFound{},
|
||||
dmt_client:commit(
|
||||
dmt_client:insert(
|
||||
Version1 + 42,
|
||||
#domain_conf_Commit{
|
||||
ops = [
|
||||
{insert, #domain_conf_InsertOp{
|
||||
object = fixture_domain_object(next_id(), <<"MissingVersionFixture">>)
|
||||
}}
|
||||
]
|
||||
}
|
||||
fixture_domain_object(next_id(), <<"MissingVersionFixture">>)
|
||||
)
|
||||
).
|
||||
|
||||
-spec obsolete(term()) -> term().
|
||||
obsolete(_C) ->
|
||||
Commit1 = #domain_conf_Commit{
|
||||
ops = [
|
||||
{insert, #domain_conf_InsertOp{
|
||||
object = fixture_domain_object(next_id(), <<"InitialFixture">>)
|
||||
}}
|
||||
]
|
||||
},
|
||||
Commit2 = #domain_conf_Commit{
|
||||
ops = [
|
||||
{insert, #domain_conf_InsertOp{
|
||||
object = fixture_domain_object(next_id(), <<"ObsoleteFixture">>)
|
||||
}}
|
||||
]
|
||||
},
|
||||
Commit1 = dmt_ct_helper:mk_insert_commit(
|
||||
fixture_domain_object(next_id(), <<"InitialFixture">>)
|
||||
),
|
||||
Commit2 = dmt_ct_helper:mk_insert_commit(
|
||||
fixture_domain_object(next_id(), <<"ObsoleteFixture">>)
|
||||
),
|
||||
#domain_conf_Snapshot{version = Version1} = dmt_client:checkout(latest),
|
||||
_Version2 = dmt_client:commit(Version1, Commit1),
|
||||
_ = ?assertThrow(
|
||||
@ -285,27 +248,22 @@ conflict_notfound(_C) ->
|
||||
object_ref = {criterion, #domain_CriterionRef{id = 42}}
|
||||
}}
|
||||
},
|
||||
dmt_client:commit(Version1, #domain_conf_Commit{
|
||||
ops = [
|
||||
{update, #domain_conf_UpdateOp{
|
||||
old_object = criterion_w_refs(42, []),
|
||||
new_object = criterion_w_refs(42, [43, 44, 45])
|
||||
}}
|
||||
]
|
||||
})
|
||||
dmt_client:commit(
|
||||
Version1,
|
||||
dmt_ct_helper:mk_update_commit(
|
||||
criterion_w_refs(42, []),
|
||||
criterion_w_refs(42, [43, 44, 45])
|
||||
)
|
||||
)
|
||||
).
|
||||
|
||||
-spec conflict_exists(term()) -> term().
|
||||
conflict_exists(_C) ->
|
||||
ID = next_id(),
|
||||
Ref = fixture_object_ref(ID),
|
||||
Commit = #domain_conf_Commit{
|
||||
ops = [
|
||||
{insert, #domain_conf_InsertOp{
|
||||
object = fixture_domain_object(ID, <<"ExistingObjectFixture">>)
|
||||
}}
|
||||
]
|
||||
},
|
||||
Commit = dmt_ct_helper:mk_insert_commit(
|
||||
fixture_domain_object(ID, <<"ExistingObjectFixture">>)
|
||||
),
|
||||
#domain_conf_Snapshot{version = Version1} = dmt_client:checkout(latest),
|
||||
Version2 = dmt_client:commit(Version1, Commit),
|
||||
_ = ?assertThrow(
|
||||
@ -322,24 +280,17 @@ conflict_mismatch(_C) ->
|
||||
Object1 = fixture_domain_object(ID1, <<"Original">>),
|
||||
Ref2 = fixture_object_ref(ID2),
|
||||
#domain_conf_Snapshot{version = Version1} = dmt_client:checkout(latest),
|
||||
Version2 = dmt_client:commit(
|
||||
Version1,
|
||||
#domain_conf_Commit{ops = [{insert, #domain_conf_InsertOp{object = Object1}}]}
|
||||
),
|
||||
Version2 = dmt_client:commit(Version1, dmt_ct_helper:mk_insert_commit(Object1)),
|
||||
_ = ?assertThrow(
|
||||
#domain_conf_OperationConflict{
|
||||
conflict = {object_reference_mismatch, #domain_conf_ObjectReferenceMismatchConflict{object_ref = Ref2}}
|
||||
},
|
||||
dmt_client:commit(
|
||||
Version2,
|
||||
#domain_conf_Commit{
|
||||
ops = [
|
||||
{update, #domain_conf_UpdateOp{
|
||||
old_object = Object1,
|
||||
new_object = fixture_domain_object(ID2, <<"Mismatch">>)
|
||||
}}
|
||||
]
|
||||
}
|
||||
dmt_ct_helper:mk_update_commit(
|
||||
Object1,
|
||||
fixture_domain_object(ID2, <<"Mismatch">>)
|
||||
)
|
||||
)
|
||||
).
|
||||
|
||||
@ -394,10 +345,7 @@ checkout_object(_C) ->
|
||||
Object = fixture_domain_object(ID, <<"InsertFixture">>),
|
||||
Ref = fixture_object_ref(ID),
|
||||
#domain_conf_Snapshot{version = Version1} = dmt_client:checkout(latest),
|
||||
Version2 = dmt_client:commit(
|
||||
Version1,
|
||||
#domain_conf_Commit{ops = [{insert, #domain_conf_InsertOp{object = Object}}]}
|
||||
),
|
||||
Version2 = dmt_client:insert(Version1, Object),
|
||||
?assertEqual(
|
||||
{ok, #domain_conf_VersionedObject{version = Version2, object = Object}},
|
||||
call_checkout_object({head, #domain_conf_Head{}}, Ref)
|
||||
@ -416,9 +364,7 @@ checkout_object(_C) ->
|
||||
).
|
||||
|
||||
next_id() ->
|
||||
16#7FFFFFFF band
|
||||
(erlang:system_time(millisecond) * 1000 +
|
||||
erlang:unique_integer([positive, monotonic])).
|
||||
dmt_ct_helper:next_id().
|
||||
|
||||
fixture_domain_object(Ref, Data) ->
|
||||
{category, #domain_CategoryObject{
|
||||
|
42
test/dmt_ct_helper.erl
Normal file
42
test/dmt_ct_helper.erl
Normal file
@ -0,0 +1,42 @@
|
||||
-module(dmt_ct_helper).
|
||||
|
||||
-include_lib("damsel/include/dmsl_domain_conf_thrift.hrl").
|
||||
|
||||
-export([mk_insert_commit/1]).
|
||||
-export([mk_update_commit/2]).
|
||||
-export([mk_remove_commit/1]).
|
||||
|
||||
-export([next_id/0]).
|
||||
|
||||
-type object() :: dmsl_domain_thrift:'DomainObject'().
|
||||
-type commit() :: dmt_api_repository:commit().
|
||||
|
||||
-spec mk_insert_commit(object() | [object()]) -> commit().
|
||||
mk_insert_commit(Objects) when is_list(Objects) ->
|
||||
#domain_conf_Commit{
|
||||
ops = [{insert, #domain_conf_InsertOp{object = Object}} || Object <- Objects]
|
||||
};
|
||||
mk_insert_commit(Object) when is_tuple(Object) ->
|
||||
mk_insert_commit([Object]).
|
||||
|
||||
-spec mk_update_commit(_Old :: object(), _New :: object()) -> commit().
|
||||
mk_update_commit(Old, New) when is_tuple(Old), is_tuple(New) ->
|
||||
#domain_conf_Commit{
|
||||
ops = [{update, #domain_conf_UpdateOp{old_object = Old, new_object = New}}]
|
||||
}.
|
||||
|
||||
-spec mk_remove_commit(object() | [object()]) -> commit().
|
||||
mk_remove_commit(Objects) when is_list(Objects) ->
|
||||
#domain_conf_Commit{
|
||||
ops = [{remove, #domain_conf_RemoveOp{object = Object}} || Object <- Objects]
|
||||
};
|
||||
mk_remove_commit(Object) when is_tuple(Object) ->
|
||||
mk_remove_commit([Object]).
|
||||
|
||||
%%
|
||||
|
||||
-spec next_id() -> 0..16#7FFFFFFF.
|
||||
next_id() ->
|
||||
16#7FFFFFFF band
|
||||
(erlang:system_time(millisecond) * 1000 +
|
||||
erlang:unique_integer([positive, monotonic])).
|
@ -5,5 +5,12 @@ namespaces:
|
||||
domain-config:
|
||||
processor:
|
||||
url: http://dominant:8022/v1/stateproc
|
||||
modernizer:
|
||||
# NOTE
|
||||
# Knowingly greater than any reasonable format version so that modernizing
|
||||
# always considers every event as outdated.
|
||||
current_format_version: 9999
|
||||
handler:
|
||||
url: http://dominant:8022/v1/modernizer
|
||||
storage:
|
||||
type: memory
|
||||
|
Loading…
Reference in New Issue
Block a user