App-karr

 view release on metacpan or  search on metacpan

t/30-foundation.t  view on Meta::CPAN

  my $cfg_dir = tempdir( CLEANUP => 1 );
  my $cfg     = $cfg_dir->child('config.yml');
  $cfg->spew_utf8( "scan:\n  - $parent\n" );

  my $f = new_foundation( config => "$cfg" );
  my @repos = $f->_discover_repos;
  is scalar @repos, 1, 'only the repo with .karr found';
  like "$repos[0]", qr/proj1/, 'correct repo discovered';
};

# ---------------------------------------------------------------------------
# Lock file
# ---------------------------------------------------------------------------

subtest 'no lock file → not held' => sub {
  my $dir = tempdir( CLEANUP => 1 );
  my $f   = new_foundation();
  ok ! $f->_lock_held( $dir ), 'no lock when file absent';
};

subtest 'stale lock (dead PID) → not held' => sub {
  my $dir = tempdir( CLEANUP => 1 );
  $dir->child('.karr.lock')->spew_utf8("999999999\n");  # unlikely PID
  my $f   = new_foundation();
  ok ! $f->_lock_held( $dir ), 'stale lock treated as not held';
};

subtest 'live lock (our own PID) → held' => sub {
  my $dir = tempdir( CLEANUP => 1 );
  $dir->child('.karr.lock')->spew_utf8("$$\n");  # our PID
  my $f   = new_foundation();
  ok $f->_lock_held( $dir ), 'own PID treated as held';
};

subtest 'acquire and release' => sub {
  my $dir = tempdir( CLEANUP => 1 );
  my $f   = new_foundation();
  $f->_acquire_lock( $dir );
  my $pid = $dir->child('.karr.lock')->slurp_utf8;
  chomp $pid;
  is $pid, $$, 'lock file contains our PID';
  $f->_release_lock( $dir );
  ok ! $dir->child('.karr.lock')->exists, 'lock file removed';
};

# ---------------------------------------------------------------------------
# State file
# ---------------------------------------------------------------------------

subtest 'state get/set round-trip' => sub {
  my $dir = tempdir( CLEANUP => 1 );
  my $f   = new_foundation();

  is $f->_state_get( $dir, 'hash' ), undef, 'undef before any state written';

  $f->_state_set( $dir, hash => 'abc123', last_exit => 0 );
  is $f->_state_get( $dir, 'hash' ),      'abc123', 'hash persisted';
  is $f->_state_get( $dir, 'last_exit' ), 0,        'last_exit persisted';

  $f->_state_set( $dir, hash => 'def456' );
  is $f->_state_get( $dir, 'hash' ),      'def456', 'hash updated';
  is $f->_state_get( $dir, 'last_exit' ), 0,        'last_exit preserved on partial update';
};

# ---------------------------------------------------------------------------
# .karr file parsing
# ---------------------------------------------------------------------------

subtest '_load_karr: missing file → empty hash' => sub {
  my $dir = tempdir( CLEANUP => 1 );
  my $f   = new_foundation();
  my $k   = $f->_load_karr( $dir );
  is ref $k, 'HASH', 'returns hashref';
  is scalar keys %$k, 0, 'empty when no .karr';
};

subtest '_load_karr: parses correctly' => sub {
  my $dir = tempdir( CLEANUP => 1 );
  write_karr_file( $dir, command => 'echo hello', max_runtime => 900 );
  my $f = new_foundation();
  my $k = $f->_load_karr( $dir );
  is $k->{command},     'echo hello', 'command parsed';
  is $k->{max_runtime}, 900,          'max_runtime parsed';
};

# ---------------------------------------------------------------------------
# Dry-run end-to-end
# ---------------------------------------------------------------------------

subtest 'run with --dry-run: does not execute' => sub {
  my $repo = make_git_repo();
  write_karr_file( $repo, command => 'touch __sentinel__', on_idle => 'always-run' );

  my ( $cfg_dir, $cfg ) = write_config( ["$repo"] );
  my $f   = new_foundation( config => "$cfg", dry_run => 1, force => 1 );
  # dry_run => 1 short-circuits sync, lock, command execution, state write
  $f->run;
  ok ! $repo->child('__sentinel__')->exists,
    'sentinel not created — dry-run did not execute';
};

done_testing;



( run in 0.396 second using v1.01-cache-2.11-cpan-bbe5e583499 )