Data-RecordStore

 view release on metacpan or  search on metacpan

t/recordstore.t  view on Meta::CPAN


    my $silos = $rs->silos;
    is( @$silos - $rs->[Data::RecordStore->MIN_SILO_ID], 1 + (31 - 12), '20 silos' );

    $rs = Data::RecordStore->reopen_store( $dir );
    ok( $rs, 'reopen store right stuff' );
    is( @$silos - $rs->[Data::RecordStore->MIN_SILO_ID], 1 + (31 - 12), 'still 20 silos' );

    $dir = tempdir( CLEANUP => 1 );
    $rs = Data::RecordStore->open_store( "$dir/NOODIR" );

    ok( $rs, 'inited store' );

    
    $dir = tempdir( CLEANUP => 1 );

    failnice( sub { Data::RecordStore->open_store( BASE_PATH => $dir, MAX_FILE_SIZE => 300, MIN_FILE_SIZE => 3_000 ) },
              'cannot be more than',
              'min size cant be larger than max' );

    $rs = Data::RecordStore->open_store( BASE_PATH => $dir, MAX_FILE_SIZE => 3_000_000_000, MIN_FILE_SIZE => 300 );
    ok( $rs, 'reinit store right stuff' );
    is( $rs->[Data::RecordStore->MIN_SILO_ID], 9, "min silo id for 300 min size" );
    is( @$silos - $rs->[Data::RecordStore->MIN_SILO_ID], 1 + (31 - 9), 'number of silos' );

    $rs = Data::RecordStore->reopen_store( $dir );
    ok( $rs, 'reinit store right stuff min' );
    is( $rs->[Data::RecordStore->MIN_SILO_ID], 9, "still min silo id for 300 min size" );
    is( @$silos - $rs->[Data::RecordStore->MIN_SILO_ID], 1 + ( 31 - 9), 'still number of silos for 300-3B' );

    my $size = 2 ** 12;
    $dir = tempdir( CLEANUP => 1 );
    $rs = Data::RecordStore->open_store(
        BASE_PATH => $dir,
        MAX_FILE_SIZE => $size,
        );
    $silos = $rs->silos;
    is( @$silos - $rs->[Data::RecordStore->MIN_SILO_ID], 13 - 12, '1 silo' );

    ok( $rs, 'inited store' );

    failnice( sub { Data::RecordStore->open_store( BASE_PATH => $dir, MAX_FILE_SIZE => 2**9 ) },
              'cannot be more than',
              'default min size cant be larger than max' );

    my $min_size = 2 ** 10;
    $dir = tempdir( CLEANUP => 1 );
    $rs = Data::RecordStore->open_store(
        BASE_PATH => $dir,
        MIN_FILE_SIZE => $min_size,
        );
    is( $rs->[Data::RecordStore->MIN_SILO_ID], 10, 'min silo id is 10' );
    is( $rs->[Data::RecordStore->MAX_SILO_ID], 31, 'max silo id is 31' );
    $silos = $rs->silos;
    is( $#$silos - $rs->[Data::RecordStore->MIN_SILO_ID], 31 - 10, '21 silos' );

    ok( $rs, 'inited store' );

    if( ! $is_root ) {
        $dir = tempdir( CLEANUP => 1 );
        chmod 0444, $dir;
        failnice( sub { Data::RecordStore->open_store(
                            BASE_PATH => "$dir/cant",
                            MAX_FILE_SIZE => 2 ** 12,
                            ) },
                  'permission denied',
                  'made a directory that it could not' );

        $dir = tempdir( CLEANUP => 1 );
        my $lockfile = "$dir/LOCK";
        open my $out, '>', $lockfile;
        print $out '';
        close $out;
        chmod 0444, $lockfile;
        failnice( sub { 
            Data::RecordStore->open_store( BASE_PATH => $dir ) },
                  "permission denied",
                  "was able to init store with unwritable lock file" );

        $dir = tempdir( CLEANUP => 1 );
        Data::RecordStore->open_store( $dir );
        chmod 0000, "$dir/LOCK";
        failnice( sub { Data::RecordStore->reopen_store( $dir ) },
                  'permission denied',
                  'was able to reopen store with unwritable lock file' );

        $dir = tempdir( CLEANUP => 1 );
        chmod 0444, "$dir";
        failnice( sub { Data::RecordStore->open_store( $dir ) },
                  'permission denied',
                  'was not able to open store in unwritable directory' );

        $dir = tempdir( CLEANUP => 1 );
        open $out, ">", "$dir/VERSION";
        print $out "666\n";
        close $out;
        failnice( sub { Data::RecordStore->open_store( $dir ) },
                  'Aborting open',
                  'opened with version file but no lockfile' );
    }

    $dir = tempdir( CLEANUP => 1 );
    $rs = Data::RecordStore->open_store( BASE_PATH => $dir,
                                         MAX_FILE_SIZE => 2 ** 12 );

    ok( $rs, 'opened a record store' );
    $silos = $rs->silos;
    is( @$silos - $rs->[Data::RecordStore->MIN_SILO_ID], 13 - 12, 'opened with correct number of silos' );

    unless( $is_root ) {
        remove_tree "$dir/data_silos/12";
        failnice( sub { Data::RecordStore->reopen_store( $dir ) },
                  'could not find silo',
                  'was able to open data store with missing silo' );

        $dir = tempdir( CLEANUP => 1 );
        $rs = Data::RecordStore->open_store( BASE_PATH => $dir,
                                             MAX_FILE_SIZE => 2 ** 12 );
        my $lockfile = "$dir/LOCK";
        unlink $lockfile;
        failnice( sub { Data::RecordStore->reopen_store( $dir ) },
                  'no lock file found',
                  'able to open store without lockfile' );


        $dir = tempdir( CLEANUP => 1 );
        $rs = Data::RecordStore->open_store( BASE_PATH => $dir,
                                             MAX_FILE_SIZE => 2 ** 12 );
        my $infofile = "$dir/config.yaml";
        unlink $infofile;
        failnice( sub { Data::RecordStore->reopen_store( $dir ) },
                  'could not find record store',
                  'able to open store without infofile' );

        $dir = tempdir( CLEANUP => 1 );
        $rs = Data::RecordStore->open_store( $dir );
        my $lock_dir = "$dir/user_locks";
        remove_tree( $lock_dir );
        failnice( sub { Data::RecordStore->reopen_store( $dir ) },
                  'locks directory not found',
                  'able to open store without locks dir' );

        $dir = tempdir( CLEANUP => 1 );
        $rs = Data::RecordStore->open_store( BASE_PATH => $dir,
                                             MAX_FILE_SIZE => 2 ** 12 );
        my $trans_dir = "$dir/transactions";
        remove_tree( $trans_dir );
        failnice( sub { Data::RecordStore->reopen_store( $dir ) },
                  'transaction directory not found',
                  'able to open store without transactions dir' );

        $dir = tempdir( CLEANUP => 1 );
        $rs = Data::RecordStore->open_store( BASE_PATH => $dir,
                                             MAX_FILE_SIZE => 2 ** 12 );
        my $trans_silo_dir = "$dir/transactions";
        chmod 0444, $trans_silo_dir;
        failnice( sub { $rs->use_transaction },
                  'permission denied',
                  'able to use transaction with unwritable stack silo dir' );
    }

} #test_init

sub test_locks {
    my $use_single = shift;
    my $dir = tempdir( CLEANUP => 1 );

    my $store = Data::RecordStore->open_store( BASE_PATH => $dir );
    $store->lock( "FOO", "BAR", "BAZ", "BAZ" );

    eval {
        $store->lock( "SOMETHING" );
        fail( "Data::RecordStore->lock called twice in a row" );
    };
    like( $@, qr/cannot be called twice in a row/, 'Data::RecordStore->lock called twice in a row error message' );
    $store->unlock;
    $store->lock( "SOMETHING" );
    pass( "Store was able to lock after unlocking" );
    $store->unlock;

    $store->lock( "SOMETHING", "ZOMETHING" );
    pass( "Store was able to lock same label after unlocking" );
    $store->unlock;

    unless( $is_root ) {
        chmod 0444, "$dir/user_locks/SOMETHING";
        eval {
            $store->lock( "SOMETHING" );
            fail( "Store was able to lock unwritable lock file" );
        };
        like( $@, qr/lock failed/, 'lock failed when unwritable' );
        undef $@;
        chmod 0744, "$dir/user_locks/SOMETHING";

        chmod 0444, "$dir/user_locks/ZOMETHING";
        eval {
            $store->lock( "BUMTHING", "ZOMETHING" );
            fail( "Store was able to lock unwritable lock file" );
        };
        like( $@, qr/lock failed/, 'lock failed when unwritable' );
        undef $@;

        chmod 0744, "$dir/user_locks/ZOMETHING";
        $store->lock( "BUMTHING", "ZOMETHING" );
        pass( 'store able to lock with permissions restored' );
        $store->unlock;

        $dir = tempdir( CLEANUP => 1 );
        eval {
            $store = Data::RecordStore->open_store( BASE_PATH => $dir );
            pass( "Was able to open store" );
            chmod 0444, "$dir/user_locks";

            $store->lock( "FOO" );
            fail( "Data::RecordStore->lock didnt die trying to lock to unwriteable directory" );
        };
        like( $@, qr/lock failed/, "unable to lock because of unwriteable lock directory" );


        $dir = tempdir( CLEANUP => 1 );
        eval {
            $store = Data::RecordStore->open_store( BASE_PATH => $dir );
            open my $out, '>', "$dir/user_locks/BAR";
            print $out '';
            close $out;
            chmod 0444, "$dir/user_locks/BAR";
            pass( "Was able to open store" );
            $store->lock( "FOO", "BAR", "BAZ" );
            fail( "Data::RecordStore->lock didnt die trying to lock unwriteable lock file" );
        };
        like( $@, qr/lock failed/, "unable to lock because of unwriteable lock file" );

    }
} #test_locks

sub test_use {
    my $dir = tempdir( CLEANUP => 1 );
    my $rs = Data::RecordStore->open_store(
        BASE_PATH => $dir,
        );
    is( $rs->entry_count, 0, 'starts with no entry count' );
    my $id = $rs->stow( "FOOOOF" );
    is( $rs->entry_count, 1, 'added one thing' );
    is( $rs->entry_count, $id, 'id of one thing is that of entry count' );
    my $nid = $rs->next_id;
    is( $rs->entry_count, 2, 'added nuther thing' );
    $id = $rs->stow( "LOOOOL", $nid );
    is( $rs->entry_count, 2, 'stowed that nuther thing' );
    is( $rs->index_silo->entry_count, 2, 'index silo also entry count 2' );
    is( $nid, 2, 'second id by next' );
    is( $id, $nid, 'entry count after forced set of things' );

    is( $rs->fetch( 1 ), "FOOOOF", 'got first entry' );
    is( $rs->fetch( 2 ), "LOOOOL", 'got second entry' );

    $rs->stow( "X"x10_000, 2 );
    is( $rs->fetch( 2 ), "X"x10_000, 'got ten zousand xsx' );

    $rs->delete_record( 2 );

    is( $rs->fetch( 2 ), undef, ' ten zousand xsx deletd' );
    $nid = $rs->next_id;
    is( $rs->fetch( $nid ), undef, 'nothing when next id' );
    $rs->delete_record( $nid );

    is( $rs->fetch( $nid ), undef, 'nothing when nothing next id dleted' );
    is( $rs->next_id, 1 + $nid, 'still produces an other id after nothign delete' );

    $dir = tempdir( CLEANUP => 1 );
    $rs = Data::RecordStore->open_store(
        BASE_PATH => $dir,
        );
    my $d1 = $rs->stow( "ZIPPO" );  #A 1
    $rs->stow( "BLINK" );           #B 2
    $rs->stow( "ZAP" );             #C 3
    my $d2 = $rs->stow( "XZOOR" );  #D 4
    my $d3 = $rs->stow( "ZSMOON" ); #E 5
    $rs->stow( "SOOZ" );            #F 6
    is( $rs->record_count, 6, "6 records stowed before delete test" );
    is( $rs->entry_count, 6, "6 entries before delete test" );

    is( $rs->silos_entry_count, 6, "6 items in silos" );
    is( $rs->active_entry_count, 6, "6 active items in silos" );
    # A B C D E F
    $rs->delete_record( $d1 );
    # F B C D E

t/recordstore.t  view on Meta::CPAN


    eval {
        local( *STDERR );
        my $errout;
        open( STDERR, ">>", \$errout );

        $rs->use_transaction();
        like( $errout, qr/already in transaction/i, "error message for trying to transaction twice" );
        pass( "able to open transaction twice" );
    };

    is( $rs->transaction_silo->entry_count, 1, 'trans silo still with one count' );
    is( $copy->transaction_silo->entry_count, 1, 'copy trans silo still with one count' );
    is( $rs->fetch( $oid ), "OMETHING ELSE", 'trans has right val for something not in trans' );
    $rs->stow( "THIS MEANS SOMETHING", $id );
    is( $rs->fetch( $id ), "THIS MEANS SOMETHING", "correct value in transaction" );
    is( $copy->fetch( $id ), "SOMETHING ZOMETHING", "correct value in non-transaction" );

    my $newid = $rs->stow( "ONE MORE THING TO STOWWWWWWWW" );
    is( $newid, 3, '3rd id' );
    is( $rs->fetch( $newid ), "ONE MORE THING TO STOWWWWWWWW", "correct value assigned id" );
    is( $copy->fetch( $newid ), undef, "copy cant see commit value" );

    $rs->stow( "OH LETS CHANGE THIS UP", $newid );
    is( $rs->fetch( $newid ), "OH LETS CHANGE THIS UP", "correct new value assigned id" );
    is( $copy->fetch( $newid ), undef, "copy still cant see commit value" );

    my $nid = $rs->stow( "FORGRABS" );
    my $nextid = $copy->next_id;
    is( $nextid, 1 + $nid, 'copy gets one id further than trans store' );
    is( $rs->fetch( $nid ), "FORGRABS", "correct new value assigned id" );
    is( $copy->fetch( $nid ), undef, "copy still cant see commit value" );

    $rs->delete_record( $nid );
    is( $rs->fetch( $nid ), undef, "correct deleted assigned id" );
    is( $copy->fetch( $nid ), undef, "copy still cant see commit value" );

    $copy->stow( "neet", $nextid );
    is( $rs->fetch( $nextid ), 'neet', "trans sees copy stow" );
    is( $copy->fetch( $nextid ), 'neet', "copy sees own stow" );

    $rs->delete_record( $nextid );
    is( $rs->fetch( $nextid ), undef, "trans cant see deleted item" );
    is( $copy->fetch( $nextid ), 'neet', "copy still sees own stow" );

    $rs->stow( "X" x 10_000 );

    $rs->commit_transaction();
    is( $copy->fetch( $id ), "THIS MEANS SOMETHING", "correct value in copy after commit" );
    is( $rs->fetch( $id ), "THIS MEANS SOMETHING", "correct value in after commit" );

    is( $rs->fetch( $nextid ), undef, "trans cant see deleted item after commit" );
    is( $copy->fetch( $nextid ), undef, "copy sees deleted own stow after commit" );

    is( $copy->fetch( $nextid + 1 ), "X" x 10_000, 'big thing saved' );

    if( ! $is_root ) {
        $dir = tempdir( CLEANUP => 1 );
        my $stacks = "$dir/transactions/1";
        make_path( $stacks );
        chmod 0444, $stacks;
        $rs = Data::RecordStore->open_store(
            BASE_PATH => $dir,
        );
        eval {
            $rs->use_transaction;
            fail( 'was able to use transaction with unwritable dir' );
        };
        like( $@, qr/permission denied/i, 'err msg for trans with unwrite dir' );
    }

    $dir = tempdir( CLEANUP => 1 );
    $rs = Data::RecordStore->open_store(
        BASE_PATH => $dir,
    );
    $copy = Data::RecordStore->open_store( $dir );
    
    $rs->use_transaction;
    
    $newid = $rs->stow( "WIBBLES AND FOOKZA" );
    $id = $copy->stow( "SOMETHING TO NEARLY DELETE" );
    $rs->delete_record( $id );

    is( $rs->fetch( $id ), undef, "trans cant see deleted item before commit" );
    is( $copy->fetch( $id ), "SOMETHING TO NEARLY DELETE", "copy sees thing after transaction delete no commit" );

    $rs->stow( "BLAME ME", $id );

    is( $rs->fetch( $id ), "BLAME ME", "trans sees updated before commit" );
    is( $copy->fetch( $id ), "SOMETHING TO NEARLY DELETE", "copy sees thing after transaction delete no commit" );

    $rs->delete_record( $id );

    $rs->delete_record( $id );

    is( $rs->fetch( $id ), undef, "trans cant see deleted item before commit" );
    is( $copy->fetch( $id ), "SOMETHING TO NEARLY DELETE", "copy sees thing after transaction delete no commit" );
    
    is( $rs->fetch( $newid ), "WIBBLES AND FOOKZA", "trans can see stowed item before rollback" );
    is( $copy->fetch( $newid ), undef, "copy cant see stowed item before rollback" );

    $rs->rollback_transaction;

    is( $rs->fetch( $id ), "SOMETHING TO NEARLY DELETE", "rs sees thing after transaction delete rollback" );
    is( $copy->fetch( $id ), "SOMETHING TO NEARLY DELETE", "copy sees thing after transaction delete no commit" );
    is( $rs->fetch( $newid ), undef, "trans cant see stowed item after rollback" );
    is( $copy->fetch( $newid ), undef, "copy cant see stowed item after rollback" );

    
    # need to monkey patch to test rollback of partially commited thing
    
    $dir = tempdir( CLEANUP => 1 );
    $rs = Data::RecordStore->open_store(
        BASE_PATH => $dir,
    );
    $copy = Data::RecordStore->open_store( $dir );

    my $times = 100_000;
    
    my $id1 = $copy->stow( "THIS IS THE FIRST ONE IN THE FIRST PLACE" );
    my $id2 = $copy->stow( "DELETE ME OR TRY TO" );



( run in 0.690 second using v1.01-cache-2.11-cpan-140bd7fdf52 )