Bug 17600: Standardize our EXPORT_OK
[srvgit] / t / db_dependent / Auth_with_ldap.t
index 878385f..39f6e8e 100755 (executable)
@@ -20,108 +20,243 @@ use Modern::Perl;
 use Test::More tests => 4;
 use Test::MockModule;
 use Test::MockObject;
+use t::lib::Mocks;
+use t::lib::TestBuilder;
 use Test::Warn;
 
 use C4::Context;
 
-my $dbh = C4::Context->dbh;
+use Koha::Patrons;
+
+my $dbh = '';
+
 # Start transaction
-$dbh->{ AutoCommit } = 0;
-$dbh->{ RaiseError } = 1;
+my $schema = Koha::Database->new->schema;
+$schema->storage->txn_begin();
+
+my $builder = t::lib::TestBuilder->new();
 
 # Variables controlling LDAP server config
 my $update         = 0;
 my $replicate      = 0;
 my $auth_by_bind   = 1;
 my $anonymous_bind = 1;
+my $user           = 'cn=Manager,dc=metavore,dc=com';
+my $pass           = 'metavore';
+
 # Variables controlling LDAP behaviour
 my $desired_authentication_result = 'success';
 my $desired_connection_result     = 'error';
-my $desired_bind_result           = 'error';
-my $desired_compare_result        = 'error';
+my $desired_admin_bind_result     = 'error';
 my $desired_search_result         = 'error';
 my $desired_count_result          = 1;
-my $non_anonymous_bind_result     = 'error';
+my $desired_bind_result           = 'error';
+my $remaining_entry = 1;
 my $ret;
 
 # Mock the context module
-my $context     = new Test::MockModule( 'C4::Context' );
+my $context = Test::MockModule->new('C4::Context');
 $context->mock( 'config', \&mockedC4Config );
 
 # Mock the Net::LDAP module
-my $ldap = new Test::MockModule( 'Net::LDAP' );
-
-$ldap->mock( 'new',  sub {
-    if ( $desired_connection_result eq 'error' ) {
-        # We were asked to fail the LDAP conexion
-        return;
-    } else {
-        # Return a mocked Net::LDAP object (Test::MockObject)
-        return mock_net_ldap();
+my $net_ldap = Test::MockModule->new('Net::LDAP');
+
+$net_ldap->mock(
+    'new',
+    sub {
+        if ( $desired_connection_result eq 'error' ) {
+
+            # We were asked to fail the LDAP conexion
+            return;
+        }
+        else {
+            # Return a mocked Net::LDAP object (Test::MockObject)
+            return mock_net_ldap();
+        }
     }
-});
+);
+
+my $categorycode = $builder->build( { source => 'Category' } )->{categorycode};
+my $branchcode   = $builder->build( { source => 'Branch' } )->{branchcode};
+my $attr_type    = $builder->build(
+    {
+        source => 'BorrowerAttributeType',
+        value  => {
+            category_code => $categorycode
+        }
+    }
+);
+my $attr_type2    = $builder->build(
+    {
+        source => 'BorrowerAttributeType',
+        value  => {
+            category_code => $categorycode
+        }
+    }
+);
+
+my $borrower = $builder->build(
+    {
+        source => 'Borrower',
+        value  => {
+            userid       => 'hola',
+            branchcode   => $branchcode,
+            categorycode => $categorycode
+        }
+    }
+);
+
+$builder->build(
+    {
+        source => 'BorrowerAttribute',
+        value  => {
+            borrowernumber => $borrower->{borrowernumber},
+            code           => $attr_type->{code},
+            attribute      => 'FOO'
+        }
+    }
+);
 
+my $patron = Koha::Patrons->find($borrower->{borrowernumber});
 
 # C4::Auth_with_ldap needs several stuff set first ^^^
-use_ok( 'C4::Auth_with_ldap' );
-can_ok( 'C4::Auth_with_ldap', qw/
-        checkpw_ldap
-        search_method /);
+use_ok('C4::Auth_with_ldap', qw( checkpw_ldap ));
+can_ok(
+    'C4::Auth_with_ldap', qw/
+      checkpw_ldap
+      search_method /
+);
 
-subtest "checkpw_ldap tests" => sub {
+subtest 'checkpw_ldap tests' => sub {
 
     plan tests => 4;
 
+    my $dbh = C4::Context->dbh;
     ## Connection fail tests
     $desired_connection_result = 'error';
-    warning_is { $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' ) }
-        "LDAP connexion failed",
-        "checkpw_ldap prints correct warning if LDAP conexion fails";
-    is( $ret, 0, "checkpw_ldap returns 0 if LDAP conexion fails");
+    warning_is {
+        $ret =
+          C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' );
+    }
+    'LDAP connexion failed',
+      'checkpw_ldap prints correct warning if LDAP conexion fails';
+    is( $ret, 0, 'checkpw_ldap returns 0 if LDAP conexion fails' );
 
     ## Connection success tests
     $desired_connection_result = 'success';
 
-    subtest "auth_by_bind = 1 tests" => sub {
+    subtest 'auth_by_bind = 1 tests' => sub {
 
-        plan tests => 5;
+        plan tests => 11;
 
-        $auth_by_bind          = 1;
+        $auth_by_bind = 1;
 
         $desired_authentication_result = 'success';
-        $anonymous_bind        = 1;
-        $desired_bind_result   = 'error';
-        $desired_search_result = 'error';
+        $anonymous_bind                = 1;
+        $desired_admin_bind_result   = 'error';
+        $desired_search_result         = 'error';
         reload_ldap_module();
 
+        warning_like {
+            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
+                password => 'hey' );
+        }
+        qr/Anonymous LDAP bind failed: LDAP error #1: error_name/,
+          'checkpw_ldap prints correct warning if LDAP anonymous bind fails';
+        is( $ret, 0, 'checkpw_ldap returns 0 if LDAP anonymous bind fails' );
 
-        warning_like { $ret = C4::Auth_with_ldap::checkpw_ldap(
-                               $dbh, 'hola', password => 'hey' ) }
-                    qr/Anonymous LDAP bind failed: LDAP error #1: error_name/,
-                    "checkpw_ldap prints correct warning if LDAP anonymous bind fails";
-        is( $ret, 0, "checkpw_ldap returns 0 if LDAP anonymous bind fails");
+        $anonymous_bind = 0;
+        $user = undef;
+        $pass = undef;
+        reload_ldap_module();
+
+        warning_like {
+            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
+                password => 'hey' );
+        }
+        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
+          'checkpw_ldap prints correct warning if LDAP bind_by_auth fails';
+        is( $ret, 0, 'checkpw_ldap returns 0 if LDAP bind_by_auth fails' );
 
         $desired_authentication_result = 'success';
-        $anonymous_bind        = 1;
-        $desired_bind_result   = 'success';
-        $desired_search_result = 'success';
-        $desired_count_result  = 0; # user auth problem
-        $non_anonymous_bind_result = 'success';
+        $anonymous_bind                = 1;
+        $desired_admin_bind_result   = 'success';
+        $desired_search_result         = 'success';
+        $desired_count_result          = 1;
+        $desired_bind_result = 'success';
+        $update                        = 1;
+        reload_ldap_module();
+
+        t::lib::Mocks::mock_preference( 'ExtendedPatronAttributes', 1 );
+        my $auth = Test::MockModule->new('C4::Auth_with_ldap');
+        $auth->mock(
+            'update_local',
+            sub {
+                return $borrower->{cardnumber};
+            }
+        );
+        $auth->mock(
+            'ldap_entry_2_hash',
+            sub {
+                return (
+                    $attr_type2->{code}, 'BAR'
+                );
+            }
+        );
+
+        C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' );
+        ok(
+            Koha::Patrons->find($borrower->{borrowernumber})->extended_attributes->count,
+            'Extended attributes are not deleted'
+        );
+
+        is( $patron->get_extended_attribute( $attr_type2->{code} )->attribute, 'BAR', 'Mapped attribute is BAR' );
+        $auth->unmock('update_local');
+        $auth->unmock('ldap_entry_2_hash');
+
+        $update               = 0;
+        $desired_count_result = 0;    # user auth problem
+        $patron->delete;
+        reload_ldap_module();
+        is(
+            C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' ),
+            0,
+            'checkpw_ldap returns 0 if user lookup returns 0'
+        );
+
+        $desired_bind_result = 'error';
         reload_ldap_module();
-        is ( C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola', password => 'hey' ),
-            0, "checkpw_ldap returns 0 if user lookup returns 0");
 
-        $non_anonymous_bind_result = 'error';
+        warning_like {
+            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
+                password => 'hey' );
+        }
+        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
+          'checkpw_ldap prints correct warning if LDAP bind fails';
+        is( $ret, -1,
+            'checkpw_ldap returns -1 LDAP bind fails for user (Bug 8148)' );
+
+        # regression tests for bug 12831
+        $desired_authentication_result = 'error';
+        $anonymous_bind                = 0;
+        $desired_admin_bind_result   = 'error';
+        $desired_search_result         = 'success';
+        $desired_count_result          = 0;           # user auth problem
+        $desired_bind_result = 'error';
         reload_ldap_module();
 
-        warning_like { $ret = C4::Auth_with_ldap::checkpw_ldap(
-                               $dbh, 'hola', password => 'hey' ) }
-                    qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
-                    "checkpw_ldap prints correct warning if LDAP bind fails";
-        is ( $ret, -1, "checkpw_ldap returns -1 LDAP bind fails for user (Bug 8148)");
+        warning_like {
+            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
+                password => 'hey' );
+        }
+        qr/LDAP bind failed as kohauser hola: LDAP error #1: error_name/,
+          'checkpw_ldap prints correct warning if LDAP bind fails';
+        is( $ret, 0,
+            'checkpw_ldap returns 0 LDAP bind fails for user (Bug 12831)' );
+
     };
 
-    subtest "auth_by_bind = 0 tests" => sub {
+    subtest 'auth_by_bind = 0 tests' => sub {
 
         plan tests => 8;
 
@@ -129,119 +264,135 @@ subtest "checkpw_ldap tests" => sub {
 
         # Anonymous bind
         $anonymous_bind            = 1;
+        $user                      = 'cn=Manager,dc=metavore,dc=com';
+        $pass                      = 'metavore';
+        $desired_admin_bind_result = 'error';
         $desired_bind_result       = 'error';
-        $non_anonymous_bind_result = 'error';
         reload_ldap_module();
 
-        warning_like { $ret = C4::Auth_with_ldap::checkpw_ldap(
-                               $dbh, 'hola', password => 'hey' ) }
-                    qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
-                    "checkpw_ldap prints correct warning if LDAP bind fails";
-        is ( $ret, 0, "checkpw_ldap returns 0 if bind fails");
+        warning_like {
+            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
+                password => 'hey' );
+        }
+qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
+          'checkpw_ldap prints correct warning if LDAP bind fails';
+        is( $ret, 0, 'checkpw_ldap returns 0 if bind fails' );
 
         $anonymous_bind            = 1;
-        $desired_bind_result       = 'success';
-        $non_anonymous_bind_result = 'success';
-        $desired_compare_result    = 'error';
+        $desired_admin_bind_result = 'success';
+        $desired_bind_result = 'error';
+        $desired_search_result = 'success';
+        $desired_count_result = 1;
         reload_ldap_module();
 
-        warning_like { $ret = C4::Auth_with_ldap::checkpw_ldap(
-                               $dbh, 'hola', password => 'hey' ) }
-                    qr/LDAP Auth rejected : invalid password for user 'hola'. LDAP error #1: error_name/,
-                    "checkpw_ldap prints correct warning if LDAP bind fails";
-        is ( $ret, -1, "checkpw_ldap returns -1 if bind fails (Bug 8148)");
+        warning_like {
+            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
+                password => 'hey' );
+        }
+qr/LDAP Auth rejected : invalid password for user 'hola'./,
+          'checkpw_ldap prints correct warning if LDAP bind fails';
+        is( $ret, -1, 'checkpw_ldap returns -1 if bind fails (Bug 8148)' );
 
         # Non-anonymous bind
         $anonymous_bind            = 0;
-        $desired_bind_result       = 'success';
-        $non_anonymous_bind_result = 'error';
-        $desired_compare_result    = 'dont care';
+        $desired_admin_bind_result = 'error';
+        $desired_bind_result = 'error';
         reload_ldap_module();
 
-        warning_like { $ret = C4::Auth_with_ldap::checkpw_ldap(
-                               $dbh, 'hola', password => 'hey' ) }
-                    qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
-                    "checkpw_ldap prints correct warning if LDAP bind fails";
-        is ( $ret, 0, "checkpw_ldap returns 0 if bind fails");
+        warning_like {
+            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
+                password => 'hey' );
+        }
+qr/LDAP bind failed as ldapuser cn=Manager,dc=metavore,dc=com: LDAP error #1: error_name/,
+          'checkpw_ldap prints correct warning if LDAP bind fails';
+        is( $ret, 0, 'checkpw_ldap returns 0 if bind fails' );
 
         $anonymous_bind            = 0;
-        $desired_bind_result       = 'success';
-        $non_anonymous_bind_result = 'success';
-        $desired_compare_result    = 'error';
+        $desired_admin_bind_result = 'success';
+        $desired_bind_result = 'error';
         reload_ldap_module();
 
-        warning_like { $ret = C4::Auth_with_ldap::checkpw_ldap(
-                               $dbh, 'hola', password => 'hey' ) }
-                    qr/LDAP Auth rejected : invalid password for user 'hola'. LDAP error #1: error_name/,
-                    "checkpw_ldap prints correct warning if LDAP bind fails";
-        is ( $ret, -1, "checkpw_ldap returns -1 if bind fails (Bug 8148)");
+        warning_like {
+            $ret = C4::Auth_with_ldap::checkpw_ldap( $dbh, 'hola',
+                password => 'hey' );
+        }
+qr/LDAP Auth rejected : invalid password for user 'hola'./,
+          'checkpw_ldap prints correct warning if LDAP bind fails';
+        is( $ret, -1, 'checkpw_ldap returns -1 if bind fails (Bug 8148)' );
 
     };
 };
 
-subtest "search_method tests" => sub {
+subtest 'search_method tests' => sub {
 
-    plan tests => 5;
+    plan tests => 3;
 
     my $ldap = mock_net_ldap();
 
     # Null params tests
-    is( C4::Auth_with_ldap::search_method( $ldap, undef), undef,
-        "search_method returns undef on undefined userid");
-    is( C4::Auth_with_ldap::search_method( undef, "undef"), undef,
-        "search_method returns undef on undefined ldap object");
+    is( C4::Auth_with_ldap::search_method( $ldap, undef ),
+        undef, 'search_method returns undef on undefined userid' );
+    is( C4::Auth_with_ldap::search_method( undef, 'undef' ),
+        undef, 'search_method returns undef on undefined ldap object' );
 
     # search ->code and !->code
     $desired_search_result = 'error';
     reload_ldap_module();
-    eval { $ret = C4::Auth_with_ldap::search_method( $ldap, "undef"); };
-    like( $@, qr/LDAP search failed to return object : 1/,
-        "search_method prints correct warning when db->search returns error code");
-
-    $desired_search_result = 'success';
-    $desired_count_result  = 2;
-    reload_ldap_module();
-    warning_like { $ret = C4::Auth_with_ldap::search_method( $ldap, '123') }
-                   qr/^LDAP Auth rejected \: \(uid\=123\) gets 2 hits/,
-                   "search_method prints correct warning when hits count is not 1";
-    is( $ret, 0, "search_method returns 0 when hits count is not 1" );
-
+    my $eval_retval =
+      eval { $ret = C4::Auth_with_ldap::search_method( $ldap, 'undef' ); };
+    like(
+        $@,
+        qr/LDAP search failed to return object : 1/,
+'search_method prints correct warning when db->search returns error code'
+    );
 };
 
 # Function that mocks the call to C4::Context->config(param)
 sub mockedC4Config {
+    my $class = shift;
+    my $param = shift;
 
-    my $param =  shift;
-
-    my %ldap_mapping = (
-        firstname    => { is => 'givenname' },
-        surname      => { is => 'sn' },
-        address      => { is => 'postaladdress' },
-        city         => { is => 'l' },
-        zipcode      => { is => 'postalcode' },
-        branchcode   => { is => 'branch' },
-        userid       => { is => 'uid' },
-        password     => { is => 'userpassword' },
-        email        => { is => 'mail' },
-        categorycode => { is => 'employeetype' },
-        phone        => { is => 'telephonenumber' }
-    );
+    if ( $param eq 'useshibboleth' ) {
+        return 0;
+    }
+    if ( $param eq 'ldapserver' ) {
+        my %ldap_mapping = (
+            firstname    => { is => 'givenname' },
+            surname      => { is => 'sn' },
+            address      => { is => 'postaladdress' },
+            city         => { is => 'l' },
+            zipcode      => { is => 'postalcode' },
+            branchcode   => { is => 'branch' },
+            userid       => { is => 'uid' },
+            password     => { is => 'userpassword' },
+            email        => { is => 'mail' },
+            categorycode => { is => 'employeetype' },
+            phone        => { is => 'telephonenumber' },
+        );
 
-    my %ldap_config  = (
-        anonymous_bind => $anonymous_bind,
-        auth_by_bind   => $auth_by_bind,
-        base           => 'dc=metavore,dc=com',
-        hostname       => 'localhost',
-        mapping        => \%ldap_mapping,
-        pass           => 'metavore',
-        principal_name => '%s@my_domain.com',
-        replicate      => $replicate,
-        update         => $update,
-        user           => 'cn=Manager,dc=metavore,dc=com'
-    );
+        my %ldap_config = (
+            anonymous_bind => $anonymous_bind,
+            auth_by_bind   => $auth_by_bind,
+            base           => 'dc=metavore,dc=com',
+            hostname       => 'localhost',
+            mapping        => \%ldap_mapping,
+            pass           => $pass,
+            principal_name => '%s@my_domain.com',
+            replicate      => $replicate,
+            update         => $update,
+            user           => $user,
+        );
+        return \%ldap_config;
+    }
+    if ( $param =~ /(intranetdir|opachtdocs|intrahtdocs)/x ) {
+        return q{};
+    }
+    if ( ref $class eq 'HASH' ) {
+        return $class->{$param};
+    }
 
-    return \%ldap_config;
-};
+    return C4::Context::_common_config($param, 'config');
+}
 
 # Function that mocks the call to Net::LDAP
 sub mock_net_ldap {
@@ -249,72 +400,63 @@ sub mock_net_ldap {
     my $mocked_ldap = Test::MockObject->new();
 
     $mocked_ldap->mock( 'bind', sub {
-
-        my @args = @_;
-        my $mocked_message;
-
-        if ( $#args > 1 ) {
-            # Args passed => non-anonymous bind
-            if ( $non_anonymous_bind_result eq 'error' ) {
+        if (is_admin_bind(@_)) {
+            return mock_net_ldap_message(
+                ($desired_admin_bind_result eq 'error' ) ? 1 : 0, # code
+                ($desired_admin_bind_result eq 'error' ) ? 1 : 0, # error
+                ($desired_admin_bind_result eq 'error' ) ? 'error_name' : 0, # error_name
+                ($desired_admin_bind_result eq 'error' ) ? 'error_text' : 0  # error_text
+            );
+        }
+        else {
+            if ( $desired_bind_result eq 'error' ) {
                 return mock_net_ldap_message(1,1,'error_name','error_text');
-            } else {
-                return mock_net_ldap_message(0,0,'','');
             }
-        } else {
-            $mocked_message = mock_net_ldap_message(
-                ($desired_bind_result eq 'error' ) ? 1 : 0, # code
-                ($desired_bind_result eq 'error' ) ? 1 : 0, # error
-                ($desired_bind_result eq 'error' ) ? 'error_name' : 0, # error_name
-                ($desired_bind_result eq 'error' ) ? 'error_text' : 0  # error_text
-            );
+            return mock_net_ldap_message(0,0,'','');
         }
-
-        return $mocked_message;
     });
 
-    $mocked_ldap->mock( 'compare', sub {
-
-        my $mocked_message;
+    $mocked_ldap->mock(
+        'search',
+        sub {
+
+            $remaining_entry = 1;
+
+            return mock_net_ldap_search(
+                {
+                    count => ($desired_count_result)
+                    ? $desired_count_result
+                    : 1,    # default to 1
+                    code => ( $desired_search_result eq 'error' )
+                    ? 1
+                    : 0,    # 0 == success
+                    error => ( $desired_search_result eq 'error' ) ? 1
+                    : 0,
+                    error_text => ( $desired_search_result eq 'error' )
+                    ? 'error_text'
+                    : undef,
+                    error_name => ( $desired_search_result eq 'error' )
+                    ? 'error_name'
+                    : undef,
+                    shift_entry => mock_net_ldap_entry( 'sampledn', 1 )
+                }
+            );
 
-        if ( $desired_compare_result eq 'error' ) {
-            $mocked_message = mock_net_ldap_message(1,1,'error_name','error_text');
-        } else {
-            # we expect return code 6 for success
-            $mocked_message = mock_net_ldap_message(6,0,'','');
         }
-
-        return $mocked_message;
-    });
-
-    $mocked_ldap->mock( 'search', sub {
-
-        return mock_net_ldap_search(
-            ( $desired_count_result )             # count
-                ? $desired_count_result
-                : 1, # default to 1
-            ( $desired_search_result eq 'error' ) # code
-                ? 1
-                : 0, # 0 == success
-            ( $desired_search_result eq 'error' ) # error
-                ? 1
-                : 0,
-            ( $desired_search_result eq 'error' ) # error_text
-                ? 'error_text'
-                : undef,
-            ( $desired_search_result eq 'error' ) # error_name
-                ? 'error_name'
-                : undef,
-            mock_net_ldap_entry( 'sampledn', 1 )  # shift_entry
-        );
-
-    });
+    );
 
     return $mocked_ldap;
 }
 
 sub mock_net_ldap_search {
-    my ( $count, $code, $error, $error_text,
-         $error_name, $shift_entry ) = @_;
+    my ($parameters) = @_;
+
+    my $count       = $parameters->{count};
+    my $code        = $parameters->{code};
+    my $error       = $parameters->{error};
+    my $error_text  = $parameters->{error_text};
+    my $error_name  = $parameters->{error_name};
+    my $shift_entry = $parameters->{shift_entry};
 
     my $mocked_search = Test::MockObject->new();
     $mocked_search->mock( 'count',       sub { return $count; } );
@@ -322,7 +464,13 @@ sub mock_net_ldap_search {
     $mocked_search->mock( 'error',       sub { return $error; } );
     $mocked_search->mock( 'error_name',  sub { return $error_name; } );
     $mocked_search->mock( 'error_text',  sub { return $error_text; } );
-    $mocked_search->mock( 'shift_entry', sub { return $shift_entry; } );
+    $mocked_search->mock( 'shift_entry', sub {
+        if ($remaining_entry) {
+            $remaining_entry--;
+            return $shift_entry;
+        }
+        return '';
+    });
 
     return $mocked_search;
 }
@@ -356,8 +504,18 @@ sub reload_ldap_module {
     delete $INC{'C4/Auth_with_ldap.pm'};
     require C4::Auth_with_ldap;
     C4::Auth_with_ldap->import;
+    return;
+}
+
+sub is_admin_bind {
+    my @args = @_;
+
+    if ($#args <= 1 || $args[1] eq 'cn=Manager,dc=metavore,dc=com') {
+        return 1;
+    }
+
+    return 0;
 }
 
-$dbh->rollback;
+$schema->storage->txn_rollback();
 
-1;