Skip to main content

src/aion@testing@replay.erl

-module(aion@testing@replay).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/aion/testing/replay.gleam").
-export([assert_replay/2]).
-export_type([replay_error/1]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

?MODULEDOC(
    " Replay assertions for `aion/testing`.\n"
    "\n"
    " The helper runs a workflow twice in the same process-scoped harness, compares\n"
    " the captured observation sequences, and reports mismatches as typed data. This\n"
    " is a test-time simulation of AD's non-determinism detection: production replay\n"
    " remains the responsibility of AD, but workflow authors can catch accidental\n"
    " unrecorded branching in ordinary `gleam test` suites.\n"
).

-type replay_error(ENF) :: {workflow_failed, ENF} |
    {observation_mismatch, binary(), binary()} |
    {replay_harness_failure, aion@error:engine_error()}.

-file("src/aion/testing/replay.gleam", 78).
-spec capture() -> {ok, binary()} | {error, replay_error(any())}.
capture() ->
    case aion_flow_ffi:testing_observations() of
        {ok, Observations} ->
            {ok, Observations};

        {error, Raw_error} ->
            {error, {replay_harness_failure, {engine_failure, Raw_error}}}
    end.

-file("src/aion/testing/replay.gleam", 70).
-spec clear() -> {ok, nil} | {error, replay_error(any())}.
clear() ->
    case aion_flow_ffi:testing_clear_observations() of
        {ok, _} ->
            {ok, nil};

        {error, Raw_error} ->
            {error, {replay_harness_failure, {engine_failure, Raw_error}}}
    end.

-file("src/aion/testing/replay.gleam", 43).
-spec compare_replay(ENO, binary(), fun(() -> {ok, ENO} | {error, ENP})) -> {ok,
        ENO} |
    {error, replay_error(ENP)}.
compare_replay(Value, Recorded, Workflow) ->
    case clear() of
        {error, Harness_error} ->
            {error, Harness_error};

        {ok, _} ->
            case Workflow() of
                {error, Workflow_error} ->
                    {error, {workflow_failed, Workflow_error}};

                {ok, _} ->
                    case capture() of
                        {error, Harness_error@1} ->
                            {error, Harness_error@1};

                        {ok, Replayed} ->
                            case Recorded =:= Replayed of
                                true ->
                                    {ok, Value};

                                false ->
                                    {error,
                                        {observation_mismatch,
                                            Recorded,
                                            Replayed}}
                            end
                    end
            end
    end.

-file("src/aion/testing/replay.gleam", 25).
?DOC(" Run a workflow twice and require identical observations.\n").
-spec assert_replay(any(), fun(() -> {ok, ENH} | {error, ENI})) -> {ok, ENH} |
    {error, replay_error(ENI)}.
assert_replay(_, Workflow) ->
    case clear() of
        {error, Harness_error} ->
            {error, Harness_error};

        {ok, _} ->
            case Workflow() of
                {error, Workflow_error} ->
                    {error, {workflow_failed, Workflow_error}};

                {ok, Value} ->
                    case capture() of
                        {error, Harness_error@1} ->
                            {error, Harness_error@1};

                        {ok, Recorded} ->
                            compare_replay(Value, Recorded, Workflow)
                    end
            end
    end.