Merge pull request #11152 from keynslug/test/ft-prop-aggressive

test(ft): make proptests even less aggressive
This commit is contained in:
Andrew Mayorov 2023-06-27 17:44:54 +02:00 committed by GitHub
commit 30d78aaac2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 106 additions and 57 deletions

View File

@ -52,12 +52,19 @@
%% Generic Types
-export([
scaled/2
scaled/2,
fixedmap/1
]).
%% Iterators
-export([nof/1]).
%% Utilities
-export([
generate/2,
typegen/0
]).
-type proptype() :: proper_types:raw_type().
%%--------------------------------------------------------------------
@ -679,6 +686,36 @@ limited_list(N, T) ->
scaled(F, T) when F > 0 ->
?SIZED(S, resize(round(S * F), T)).
-spec fixedmap(#{_Key => proptype()}) -> proptype().
fixedmap(M) ->
?LET(PList, maps:to_list(M), maps:from_list(PList)).
%%--------------------------------------------------------------------
%% Utilities
%%--------------------------------------------------------------------
-type typegen() :: {typegen, proper_gen:size(), proper_gen:seed()}.
-spec typegen() -> proptype().
typegen() ->
Seed = {non_neg_integer(), non_neg_integer(), non_neg_integer()},
{typegen, ?SIZED(S, S), Seed}.
-spec generate(proptype(), typegen()) -> _Instance.
generate(T, {typegen, Size, Seed}) ->
% NOTE
% We need to run it in a separate process so that it won't erase
% any proper state in the current process allocated by the property
% being evaluated.
{Pid, MRef} = erlang:spawn_monitor(
fun() -> exit(proper_gen:pick(T, Size, Seed)) end
),
receive
{'DOWN', MRef, process, Pid, Result} ->
{ok, Instance} = Result,
Instance
end.
%%--------------------------------------------------------------------
%% Internal funcs
%%--------------------------------------------------------------------

View File

@ -18,24 +18,28 @@
-include_lib("proper/include/proper.hrl").
-import(emqx_proper_types, [scaled/2]).
-import(emqx_proper_types, [scaled/2, fixedmap/1, typegen/0, generate/2]).
-define(COVERAGE_TIMEOUT, 5000).
-define(COVERAGE_TIMEOUT, 10000).
prop_coverage() ->
?FORALL(
{Filesize, Segsizes},
{filesize_t(), segsizes_t()},
?FORALL(
Fragments,
noshrink(segments_t(Filesize, Segsizes)),
#{filesize := Filesize, segsizes := Segsizes, typegen := TypeGen},
noshrink(
fixedmap(#{
filesize => filesize_t(),
segsizes => segsizes_t(),
typegen => typegen()
})
),
?TIMEOUT(
?COVERAGE_TIMEOUT,
begin
ASM1 = append_segments(mk_assembly(Filesize), Fragments),
Segments = generate(segments_t(Filesize, Segsizes), TypeGen),
ASM1 = append_segments(mk_assembly(Filesize), Segments),
{Time, ASM2} = timer:tc(emqx_ft_assembly, update, [ASM1]),
measure(
#{"Fragments" => length(Fragments), "Time" => Time},
#{"Segments" => length(Segments), "Time" => Time},
case emqx_ft_assembly:status(ASM2) of
complete ->
Coverage = emqx_ft_assembly:coverage(ASM2),
@ -49,23 +53,26 @@ prop_coverage() ->
)
end
)
)
).
prop_coverage_likely_incomplete() ->
?FORALL(
{Filesize, Segsizes, Hole},
{filesize_t(), segsizes_t(), filesize_t()},
?FORALL(
Fragments,
noshrink(segments_t(Filesize, Segsizes, (Hole rem max(Filesize, 1)))),
?TIMEOUT(
?COVERAGE_TIMEOUT,
begin
ASM1 = append_segments(mk_assembly(Filesize), Fragments),
#{filesize := Filesize, segsizes := Segsizes, hole := HoleIn, typegen := TypeGen},
noshrink(
fixedmap(#{
filesize => filesize_t(),
segsizes => segsizes_t(),
hole => filesize_t(),
typegen => typegen()
})
),
?TIMEOUT(?COVERAGE_TIMEOUT, begin
Hole = HoleIn rem max(Filesize, 1),
Segments = generate(segments_t(Filesize, Segsizes, Hole), TypeGen),
ASM1 = append_segments(mk_assembly(Filesize), Segments),
{Time, ASM2} = timer:tc(emqx_ft_assembly, update, [ASM1]),
measure(
#{"Fragments" => length(Fragments), "Time" => Time},
#{"Segments" => length(Segments), "Time" => Time},
case emqx_ft_assembly:status(ASM2) of
complete ->
% NOTE: this is still possible due to the nature of `SUCHTHATMAYBE`
@ -75,23 +82,28 @@ prop_coverage_likely_incomplete() ->
collect(incomplete, true)
end
)
end
)
)
end)
).
prop_coverage_complete() ->
?FORALL(
{Filesize, Segsizes},
{filesize_t(), ?SUCHTHAT([BaseSegsize | _], segsizes_t(), BaseSegsize > 0)},
?FORALL(
{Fragments, RemoteNode},
noshrink({segments_t(Filesize, Segsizes), remote_node_t()}),
#{filesize := Filesize, segsizes := Segsizes, node := RemoteNode, typegen := TypeGen},
noshrink(
fixedmap(#{
filesize => filesize_t(),
segsizes => ?SUCHTHAT([BaseSegsize | _], segsizes_t(), BaseSegsize > 0),
node => remote_node_t(),
typegen => typegen()
})
),
?TIMEOUT(
?COVERAGE_TIMEOUT,
begin
% Ensure that we have complete coverage
Segments = generate(segments_t(Filesize, Segsizes), TypeGen),
ASM1 = mk_assembly(Filesize),
ASM2 = append_coverage(ASM1, RemoteNode, Filesize, Segsizes),
ASM3 = append_segments(ASM2, Fragments),
ASM3 = append_segments(ASM2, Segments),
{Time, ASM4} = timer:tc(emqx_ft_assembly, update, [ASM3]),
measure(
#{"CoverageMax" => nsegs(Filesize, Segsizes), "Time" => Time},
@ -189,7 +201,7 @@ segment_t(Filesize, Segsizes) ->
).
filesize_t() ->
scaled(2500, non_neg_integer()).
scaled(2000, non_neg_integer()).
segsizes_t() ->
?LET(