App-karr

 view release on metacpan or  search on metacpan

t/202-foundation-chain-executor.t  view on Meta::CPAN

  like $out, qr/the planner is wanted/,
    'and the tick says so out loud, because no planner runs from here yet';

  # The control: the same chain against a board where the precheck holds.
  my $ok_repo = make_repo();
  seed_board( $ok_repo, { status => 'todo' } );
  write_karr( $ok_repo, command => write_agent($ok_repo), max_runtime => 60 );
  my $ok_hub = make_repo();
  chain_store($ok_hub)->write_chain( [
    { id => 1, kind => 'ticket', repo => "$ok_repo", ticket => 1,
      precheck => 'ticket_status == todo' },
  ] );
  tick($ok_hub);
  is_deeply [ runs_of($ok_repo) ], ['1'],
    'and with the same precheck holding, the very same step does run';
};

subtest 'a ticket step whose card is not on the board is stale, not run' => sub {
  my $repo = make_repo();
  seed_board( $repo, { status => 'todo' } );
  write_karr( $repo, command => write_agent($repo), max_runtime => 60 );

  my $hub = make_repo();
  chain_store($hub)->write_chain( [
    { id => 1, kind => 'ticket', repo => "$repo", ticket => 99 },
  ] );

  tick($hub);
  ok !path($repo)->child('runs.log')->exists, 'no agent was started';
  my $step = step_of( $hub, 1 );
  is $step->{state}, 'stale', 'a plan about a card that is gone is out of date';
  like $step->{stale_reason}, qr/ticket 99 is not on the board/,
    'and says which card it could not find';
};

# ---------------------------------------------------------------------------
# What a failure does to the DAG
# ---------------------------------------------------------------------------

subtest 'a failed step stops its own branch and nothing else' => sub {
  my $repo  = make_repo();
  my $hub   = make_repo();
  my $after = path($repo)->child('after');
  my $other = path($repo)->child('other');

  chain_store($hub)->write_chain( [
    { id => 1, kind => 'shell', repo => "$repo", command => 'exit 3' },
    { id => 2, kind => 'shell', repo => "$repo", needs => [1],
      command => "echo after >> '$after'" },
    { id => 3, kind => 'shell', repo => "$repo", command => "echo other >> '$other'" },
  ] );

  my ( $out ) = tick($hub);

  is step_of( $hub, 1 )->{state}, 'failed', 'the step that exited non-zero failed';
  is step_of( $hub, 1 )->{result}{exit}, 3, 'with the exit code recorded';

  is step_of( $hub, 2 )->{state}, 'pending',
    'its dependent never became ready -- ready_steps releases a step only when '
    . 'everything it needs is DONE, so the branch prunes itself and nobody has '
    . 'to compute a cascade';
  ok !$after->exists, 'and it certainly did not run';

  is step_of( $hub, 3 )->{state}, 'done',
    'a step on another branch is unaffected: that is what the missing edge means';
  is_deeply [ lines_of($other) ], ['other'], 'and it ran';

  my ( $planner ) = grep { $_->{event} eq 'planner' } log_of($hub);
  is $planner->{step}, '1', 'the planner is wanted for the step that failed';
  is $planner->{policy}, 'plan', 'under the on_stall policy the spec writes';
  like $out, qr/the planner is wanted for step\(s\) 1/,
    'and the operator is told, since the operator is the planner until there '
    . 'is one';
};

# ---------------------------------------------------------------------------
# Not every non-run is a failure
# ---------------------------------------------------------------------------

subtest 'a broken agent command requeues its step instead of failing it' => sub {
  my $repo = make_repo();
  seed_board( $repo, { status => 'todo' } );
  write_karr( $repo, command => 'exit 7', max_runtime => 60 );

  my $hub = make_repo();
  chain_store($hub)->write_chain( [
    { id => 1, kind => 'ticket', repo => "$repo", ticket => 1 },
  ] );

  my ( $out ) = tick($hub);
  my $step = step_of( $hub, 1 );
  is $step->{state}, 'pending',
    'a rate-limited or broken agent command says nothing about the plan, so '
    . 'the step goes back rather than down';
  is $step->{attempts}, 1, 'the attempt is still counted';
  ok !defined $step->{started}, 'and the claim is cleared';
  like $out, qr/requeued/, 'the tick says it requeued it';
};

subtest 'a disabled board requeues a shell step, it does not fail it' => sub {
  my $repo   = make_repo();
  my $hub    = make_repo();
  my $marker = path($repo)->child('marker');
  seed_board( $repo, { status => 'todo' } );
  board_store($repo)->set_foundation_enabled( 0, 'parked on purpose' );

  chain_store($hub)->write_chain( [
    { id => 1, kind => 'shell', repo => "$repo", command => "echo x >> '$marker'" },
  ] );

  tick($hub);
  ok !$marker->exists,
    'the board-level disable wins over a planned step: it is synchronised '
    . 'board state, and "no automated runs here" does not get smaller because '
    . 'the run was planned in the hub';
  is step_of( $hub, 1 )->{state}, 'pending',
    'pending, not failed -- whoever disabled the board is who can enable it';
};

subtest 'a repository this machine does not have is left alone entirely' => sub {
  my $hub = make_repo();



( run in 1.036 second using v1.01-cache-2.11-cpan-e7c6538aa59 )