Port LockFileLock tests to C

Project: http://git-wip-us.apache.org/repos/asf/lucy/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucy/commit/35388cd2
Tree: http://git-wip-us.apache.org/repos/asf/lucy/tree/35388cd2
Diff: http://git-wip-us.apache.org/repos/asf/lucy/diff/35388cd2

Branch: refs/heads/master
Commit: 35388cd22600cb3c202cf11c8c9afd661c8f4fe4
Parents: e06cdbf
Author: Nick Wellnhofer <[email protected]>
Authored: Fri Feb 17 21:38:56 2017 +0100
Committer: Nick Wellnhofer <[email protected]>
Committed: Mon Feb 20 16:48:17 2017 +0100

----------------------------------------------------------------------
 core/Lucy/Store/Lock.c            |  18 --
 core/Lucy/Store/Lock.cfh          |   9 -
 go/lucy/store_test.go             |  15 --
 perl/t/105-folder.t               |  36 +---
 perl/t/106-locking.t              |  89 ----------
 perl/t/110-shared_lock.t          |  93 -----------
 perl/t/111-index_manager.t        |  17 +-
 perl/t/core/106-lf_lock.t         |  23 +++
 test/Lucy/Test.c                  |   2 +
 test/Lucy/Test/Store/TestLock.c   | 297 +++++++++++++++++++++++++++++++++
 test/Lucy/Test/Store/TestLock.cfh |  29 ++++
 11 files changed, 356 insertions(+), 272 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/core/Lucy/Store/Lock.c
----------------------------------------------------------------------
diff --git a/core/Lucy/Store/Lock.c b/core/Lucy/Store/Lock.c
index 90a6aa0..5cddcd9 100644
--- a/core/Lucy/Store/Lock.c
+++ b/core/Lucy/Store/Lock.c
@@ -77,16 +77,6 @@ Lock_Destroy_IMP(Lock *self) {
     SUPER_DESTROY(self, LOCK);
 }
 
-String*
-Lock_Get_Name_IMP(Lock *self) {
-    return Lock_IVARS(self)->name;
-}
-
-String*
-Lock_Get_Host_IMP(Lock *self) {
-    return Lock_IVARS(self)->host;
-}
-
 bool
 Lock_Obtain_Shared_IMP(Lock *self) {
     LockIVARS *const ivars = Lock_IVARS(self);
@@ -163,14 +153,6 @@ LFLock_init(LockFileLock *self, Folder *folder, String 
*name, String *host,
     return self;
 }
 
-String*
-LFLock_Get_Lock_Path_IMP(LockFileLock *self) {
-    LockFileLockIVARS *const ivars = LFLock_IVARS(self);
-    return ivars->shared_lock_path
-           ? ivars->shared_lock_path
-           : ivars->lock_path;
-}
-
 struct lockfile_context {
     OutStream *outstream;
     String *json;

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/core/Lucy/Store/Lock.cfh
----------------------------------------------------------------------
diff --git a/core/Lucy/Store/Lock.cfh b/core/Lucy/Store/Lock.cfh
index 6688e95..30940b4 100644
--- a/core/Lucy/Store/Lock.cfh
+++ b/core/Lucy/Store/Lock.cfh
@@ -96,12 +96,6 @@ abstract class Lucy::Store::Lock inherits Clownfish::Obj {
     public abstract void
     Release(Lock *self);
 
-    String*
-    Get_Name(Lock *self);
-
-    String*
-    Get_Host(Lock *self);
-
     public void
     Destroy(Lock *self);
 }
@@ -131,9 +125,6 @@ class Lucy::Store::LockFileLock nickname LFLock
     public void
     Release(LockFileLock *self);
 
-    String*
-    Get_Lock_Path(LockFileLock *self);
-
     public void
     Destroy(LockFileLock *self);
 }

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/go/lucy/store_test.go
----------------------------------------------------------------------
diff --git a/go/lucy/store_test.go b/go/lucy/store_test.go
index ae70069..2b24ff4 100644
--- a/go/lucy/store_test.go
+++ b/go/lucy/store_test.go
@@ -652,21 +652,10 @@ func TestLockFileLockAll(t *testing.T) {
        lock := NewLockFileLock(folder, "foo", "dev.example.com", 0, 1, false)
        other := NewLockFileLock(folder, "foo", "dev.example.com", 0, 1, false)
 
-       if got := lock.getName(); got != "foo" {
-               t.Errorf("getName: %v", got)
-       }
-       if got := lock.getHost(); got != "dev.example.com" {
-               t.Errorf("getHost: %v", got)
-       }
-
        err = lock.RequestShared()
        if err != nil {
                t.Errorf("Request: %v", err)
        }
-       if got := lock.getLockPath(); len(got) == 0 {
-               // Lock path only valid when locked for shared locks.
-               t.Errorf("getLockPath should work")
-       }
        err = other.RequestShared()
        if err != nil {
                t.Errorf("Shared lock Request should succeed: %v", err)
@@ -686,10 +675,6 @@ func TestLockFileLockAll(t *testing.T) {
        if err != nil {
                t.Errorf("Request: %v", err)
        }
-       if got := lock.getLockPath(); len(got) == 0 {
-               // Lock path only valid when locked for shared locks.
-               t.Errorf("getLockPath should work")
-       }
        err = other.RequestExclusive()
        if err == nil {
                t.Errorf("Request should fail for locked resource")

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/perl/t/105-folder.t
----------------------------------------------------------------------
diff --git a/perl/t/105-folder.t b/perl/t/105-folder.t
index ba1255e..002642f 100644
--- a/perl/t/105-folder.t
+++ b/perl/t/105-folder.t
@@ -17,7 +17,7 @@ use strict;
 use warnings;
 use lib 'buildlib';
 
-use Test::More tests => 25;
+use Test::More tests => 17;
 use File::Spec::Functions qw( catfile );
 use Fcntl;
 use Lucy::Test::TestUtils qw( init_test_index_loc );
@@ -46,43 +46,13 @@ for my $folder ( $fs_folder, $ram_folder ) {
     my $slurped = $folder->slurp_file('king_of_rock');
     is( $slurped, $king, "slurp_file works" );
 
-    my $lock = Lucy::Store::LockFileLock->new(
-        host           => '',
-        folder         => $folder,
-        name           => 'lock_robster',
-        timeout        => 0,
-        exclusive_only => 1,
-    );
-    my $competing_lock = Lucy::Store::LockFileLock->new(
-        host           => '',
-        folder         => $folder,
-        name           => 'lock_robster',
-        timeout        => 0,
-        exclusive_only => 1,
-    );
-
-    $lock->obtain_exclusive();
-    my $lock_path = $lock->get_lock_path;
-    ok( $folder->exists($lock_path), "lock is locked" );
-    ok( !$competing_lock->obtain_exclusive(),
-        "shouldn't get lock on existing resource"
-    );
-    ok( $folder->exists($lock_path),
-        "lock still locked after competing attempt"
-    );
-
-    $lock->release;
-    ok( !$folder->exists($lock_path), "release works" );
-
-    $lock->obtain_exclusive();
     $folder->rename( from => 'king_of_rock', to => 'king_of_lock' );
-    $lock->release;
 
     ok( !$folder->exists('king_of_rock'),
-        "file successfully removed while locked"
+        "file successfully removed"
     );
     is( $folder->exists('king_of_lock'),
-        1, "file successfully moved while locked" );
+        1, "file successfully moved" );
 
     is( $folder->open_out("king_of_lock"),
         undef, "open_out returns undef when file exists" );

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/perl/t/106-locking.t
----------------------------------------------------------------------
diff --git a/perl/t/106-locking.t b/perl/t/106-locking.t
deleted file mode 100644
index 15c6a3a..0000000
--- a/perl/t/106-locking.t
+++ /dev/null
@@ -1,89 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-use strict;
-use warnings;
-use lib 'buildlib';
-
-use Time::HiRes qw( sleep );
-use Test::More;
-use File::Spec::Functions qw( catfile );
-use Lucy::Test::TestUtils qw( init_test_index_loc );
-
-BEGIN {
-    if ( $^O =~ /(mswin|cygwin)/i ) {
-        plan( 'skip_all', "fork on Windows not supported by Lucy" );
-    }
-    else {
-        plan( tests => 3 );
-    }
-}
-
-my $path = init_test_index_loc();
-
-Dead_locks_are_removed: {
-    my $lock_path = catfile( $path, 'locks', 'foo.lock' );
-
-    # Remove any existing lockfile
-    unlink $lock_path;
-    die "Can't unlink '$lock_path'" if -e $lock_path;
-
-    my $folder = Lucy::Store::FSFolder->new( path => $path );
-
-    sub make_lock {
-        my $lock = Lucy::Store::LockFileLock->new(
-            timeout        => 0,
-            name           => 'foo',
-            host           => '',
-            exclusive_only => 1,
-            @_
-        );
-        $lock->obtain_exclusive() or die "no dice";
-        return $lock;
-    }
-
-    # Fork a process that will create a lock and then exit
-    my $pid = fork();
-    if ( $pid == 0 ) {    # child
-        make_lock( folder => $folder );
-        exit;
-    }
-    else {
-        waitpid( $pid, 0 );
-    }
-
-    sleep .1;
-    ok( -e $lock_path, "child secured lock" );
-
-    # The locking attempt will fail if the pid from the process that made the
-    # lock is active, so do the best we can to see whether another process
-    # started up with the child's pid (which would be weird).
-    my $pid_active = kill( 0, $pid );
-
-    eval { make_lock( folder => $folder, host => 'somebody_else' ) };
-    like( $@, qr/no dice/, "different host fails to get lock" );
-
-    eval { make_lock( folder => $folder ) };
-    warn $@ if $@;
-    my $saved_err = $@;
-    $pid_active ||= kill( 0, $pid );
-SKIP: {
-        skip( "Child's pid is active", 1 ) if $pid_active;
-        ok( !$saved_err,
-            'second lock attempt clobbered dead lock file and did not die' );
-    }
-
-    undef $folder;
-}

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/perl/t/110-shared_lock.t
----------------------------------------------------------------------
diff --git a/perl/t/110-shared_lock.t b/perl/t/110-shared_lock.t
deleted file mode 100644
index 86e7d6c..0000000
--- a/perl/t/110-shared_lock.t
+++ /dev/null
@@ -1,93 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements.  See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership.
-# The ASF licenses this file to You under the Apache License, Version 2.0
-# (the "License"); you may not use this file except in compliance with
-# the License.  You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-use strict;
-use warnings;
-
-use Test::More tests => 14;
-use Lucy::Test;
-
-my $folder = Lucy::Store::RAMFolder->new;
-my @args = (
-    folder         => $folder,
-    name           => 'ness',
-    timeout        => 0,
-    host           => 'nessie',
-    exclusive_only => 0,
-);
-
-my $ex_lock = Lucy::Store::LockFileLock->new(@args);
-
-sub is_locked {
-    if ($ex_lock->request_exclusive) {
-        $ex_lock->release;
-        return 0;
-    }
-    else {
-        return 1;
-    }
-}
-
-my $lock = Lucy::Store::LockFileLock->new(@args);
-
-ok( !is_locked(), "not locked yet" );
-
-ok( $lock->obtain_shared(),               "obtain" );
-ok( is_locked(),                          "is_locked" );
-ok( $folder->exists('locks/ness-1.lock'), "lockfile exists" );
-
-my $another_lock = Lucy::Store::LockFileLock->new(@args);
-ok( $another_lock->obtain_shared(), "got a second lock on the same resource" );
-
-$lock->release;
-ok( is_locked(),
-    "first lock released but still is_locked because of other lock" );
-
-my $ya_lock = Lucy::Store::LockFileLock->new(@args);
-ok( $ya_lock->obtain_shared(), "got yet another lock" );
-
-ok( $lock->obtain_shared(), "got first lock again" );
-is( $lock->get_lock_path, "locks/ness-3.lock",
-    "first lock uses a different lock_path now" );
-
-# Rewrite lock file to spec a different pid.
-my $content = $folder->slurp_file("locks/ness-3.lock");
-$content =~ s/$$/123456789/;
-$folder->delete('locks/ness-3.lock') or die "Can't delete 'ness-3.lock'";
-my $outstream = $folder->open_out('locks/ness-3.lock')
-    or die Clownfish->error;
-$outstream->print($content);
-$outstream->close;
-
-$lock->release;
-$another_lock->release;
-$ya_lock->release;
-
-ok( $lock->get_lock_path, "failed to release a lock with a different pid" );
-ok( !is_locked(), "is_locked clears stale locks" );
-
-ok( $lock->obtain_shared(), "got lock again" );
-ok( is_locked(), "it's locked" );
-
-# Rewrite lock file to spec a different host.
-$content = $folder->slurp_file("locks/ness-1.lock");
-$content =~ s/nessie/sting/;
-$folder->delete('locks/ness-1.lock') or die "Can't delete 'ness-1.lock'";
-$outstream = $folder->open_out('locks/ness-1.lock') or die Clownfish->error;
-$outstream->print($content);
-$outstream->close;
-
-$lock->release;
-ok( is_locked(), "don't delete lock belonging to another host" );

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/perl/t/111-index_manager.t
----------------------------------------------------------------------
diff --git a/perl/t/111-index_manager.t b/perl/t/111-index_manager.t
index d42ae98..dd7d8d0 100644
--- a/perl/t/111-index_manager.t
+++ b/perl/t/111-index_manager.t
@@ -32,24 +32,11 @@ sub recycle {
 
 package main;
 
-use Test::More tests => 11;
+use Test::More tests => 8;
 use Lucy::Test;
 
-my $folder = Lucy::Store::RAMFolder->new;
-
-my $lock = Lucy::Store::LockFileLock->new(
-    folder         => $folder,
-    host           => 'me',
-    name           => 'angie',
-    timeout        => 1000,
-    exclusive_only => 0,
-);
-isa_ok( $lock, 'Lucy::Store::Lock', "make_lock" );
-is( $lock->get_name, "angie", "correct lock name" );
-is( $lock->get_host, "me",    "correct host" );
-
 my $schema = Lucy::Test::TestSchema->new;
-$folder = Lucy::Store::RAMFolder->new;
+my $folder = Lucy::Store::RAMFolder->new;
 
 for ( 1 .. 20 ) {
     my $indexer = Lucy::Index::Indexer->new(

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/perl/t/core/106-lf_lock.t
----------------------------------------------------------------------
diff --git a/perl/t/core/106-lf_lock.t b/perl/t/core/106-lf_lock.t
new file mode 100644
index 0000000..db99bc4
--- /dev/null
+++ b/perl/t/core/106-lf_lock.t
@@ -0,0 +1,23 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You under the Apache License, Version 2.0
+# (the "License"); you may not use this file except in compliance with
+# the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+use strict;
+use warnings;
+
+use Lucy::Test;
+my $success = Lucy::Test::run_tests("Lucy::Test::Store::TestLockFileLock");
+
+exit($success ? 0 : 1);
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/test/Lucy/Test.c
----------------------------------------------------------------------
diff --git a/test/Lucy/Test.c b/test/Lucy/Test.c
index 22223e1..2a30a68 100644
--- a/test/Lucy/Test.c
+++ b/test/Lucy/Test.c
@@ -75,6 +75,7 @@
 #include "Lucy/Test/Store/TestIOChunks.h"
 #include "Lucy/Test/Store/TestIOPrimitives.h"
 #include "Lucy/Test/Store/TestInStream.h"
+#include "Lucy/Test/Store/TestLock.h"
 #include "Lucy/Test/Store/TestRAMDirHandle.h"
 #include "Lucy/Test/Store/TestRAMFileHandle.h"
 #include "Lucy/Test/Store/TestRAMFolder.h"
@@ -114,6 +115,7 @@ Test_create_test_suite() {
     TestSuite_Add_Batch(suite, (TestBatch*)TestFSFolder_new());
     TestSuite_Add_Batch(suite, (TestBatch*)TestRAMFolder_new());
     TestSuite_Add_Batch(suite, (TestBatch*)TestFolder_new());
+    TestSuite_Add_Batch(suite, (TestBatch*)TestLFLock_new());
     TestSuite_Add_Batch(suite, (TestBatch*)TestIxManager_new());
     TestSuite_Add_Batch(suite, (TestBatch*)TestCFWriter_new());
     TestSuite_Add_Batch(suite, (TestBatch*)TestCFReader_new());

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/test/Lucy/Test/Store/TestLock.c
----------------------------------------------------------------------
diff --git a/test/Lucy/Test/Store/TestLock.c b/test/Lucy/Test/Store/TestLock.c
new file mode 100644
index 0000000..f606e7b
--- /dev/null
+++ b/test/Lucy/Test/Store/TestLock.c
@@ -0,0 +1,297 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define TESTLUCY_USE_SHORT_NAMES
+#include "Lucy/Util/ToolSet.h"
+
+#include "charmony.h"
+
+// rmdir
+#ifdef CHY_HAS_DIRECT_H
+  #include <direct.h>
+#endif
+#ifdef CHY_HAS_UNISTD_H
+  #include <unistd.h>
+#endif
+
+#include "Lucy/Test/Store/TestLock.h"
+#include "Clownfish/TestHarness/TestBatchRunner.h"
+#include "Lucy/Store/FSFolder.h"
+#include "Lucy/Store/Lock.h"
+#include "Lucy/Store/RAMFolder.h"
+#include "Lucy/Util/Json.h"
+
+TestLockFileLock*
+TestLFLock_new() {
+    return (TestLockFileLock*)Class_Make_Obj(TESTLOCKFILELOCK);
+}
+
+static Folder*
+S_create_fs_folder() {
+    Folder *folder = (Folder*)FSFolder_new(SSTR_WRAP_C("_locktest"));
+    Folder_Initialize(folder);
+    return folder;
+}
+
+static void
+S_destroy_fs_folder(Folder *folder) {
+    Folder_Delete_Tree(folder, SSTR_WRAP_C("locks"));
+    rmdir("_locktest");
+    DECREF(folder);
+}
+
+static void
+test_exclusive_only(TestBatchRunner *runner, Lock *lock1, Lock *lock2,
+                    const char *tag) {
+    TEST_TRUE(runner, Lock_Request_Exclusive(lock1),
+              "Request_Exclusive (only) succeeds %s", tag);
+    Err_set_error(NULL);
+    TEST_FALSE(runner, Lock_Request_Exclusive(lock2),
+               "Request_Exclusive (only) after Request_Exclusive fails %s",
+               tag);
+    TEST_TRUE(runner, CERTIFY(Err_get_error(), LOCKERR),
+              "Request_Exclusive (only) after Request_Exclusive sets"
+              " LockErr %s", tag);
+    Lock_Release(lock1);
+
+    TEST_TRUE(runner, Lock_Request_Exclusive(lock2),
+              "Request_Exclusive (only) succeeds after Release %s", tag);
+    TEST_FALSE(runner, Lock_Request_Exclusive(lock1),
+               "Request_Exclusive (only) fails if lock2 is locked %s", tag);
+    Lock_Release(lock2);
+
+    DECREF(lock2);
+    DECREF(lock1);
+}
+
+static void
+test_lock(TestBatchRunner *runner, Lock *lock1, Lock *lock2, Lock *lock3,
+          const char *tag) {
+    TEST_TRUE(runner, Lock_Request_Shared(lock1), "Request_Shared succeeds %s",
+              tag);
+    TEST_TRUE(runner, Lock_Request_Shared(lock2),
+              "Request_Shared on another lock succeeds %s", tag);
+    Err_set_error(NULL);
+    TEST_FALSE(runner, Lock_Request_Exclusive(lock3),
+               "Request_Exclusive after Request_Shared fails %s", tag);
+    TEST_TRUE(runner, CERTIFY(Err_get_error(), LOCKERR),
+              "Request_Exclusive after Request_Shared sets LockErr %s", tag);
+    Lock_Release(lock1);
+    Lock_Release(lock2);
+
+    TEST_TRUE(runner, Lock_Request_Exclusive(lock1),
+              "Request_Exclusive succeeds %s", tag);
+    Err_set_error(NULL);
+    TEST_FALSE(runner, Lock_Request_Shared(lock2),
+               "Request_Shared after Request_Exclusive fails %s", tag);
+    TEST_TRUE(runner, CERTIFY(Err_get_error(), LOCKERR),
+              "Request_Shared after Request_Exclusive sets LockErr %s", tag);
+    Err_set_error(NULL);
+    TEST_FALSE(runner, Lock_Request_Exclusive(lock3),
+               "Request_Exclusive after Request_Exclusive fails %s", tag);
+    TEST_TRUE(runner, CERTIFY(Err_get_error(), LOCKERR),
+              "Request_Exclusive after Request_Exclusive sets LockErr %s",
+              tag);
+    Lock_Release(lock1);
+
+    TEST_TRUE(runner, Lock_Request_Exclusive(lock3),
+              "Request_Exclusive succeeds after Release %s", tag);
+    Lock_Release(lock3);
+
+    DECREF(lock3);
+    DECREF(lock2);
+    DECREF(lock1);
+}
+
+static void
+test_change_pid(TestBatchRunner *runner, Folder *folder, String *path,
+                const char *tag) {
+    Hash *hash = (Hash*)Json_slurp_json(folder, path);
+    TEST_TRUE(runner, CERTIFY(hash, HASH), "Lock file %s exists %s",
+              Str_Get_Ptr8(path), tag);
+    Hash_Store(hash, SSTR_WRAP_C("pid"), (Obj*)Str_newf("10000000"));
+    Folder_Delete(folder, path);
+    Json_spew_json((Obj*)hash, folder, path);
+    DECREF(hash);
+}
+
+static void
+test_stale(TestBatchRunner *runner, Folder *folder, const char *tag) {
+    String *name  = SSTR_WRAP_C("test");
+    String *host1 = SSTR_WRAP_C("fuchur");
+    String *host2 = SSTR_WRAP_C("drogon");
+    LockFileLock *lock1 = LFLock_new(folder, name, host1, 0, 100, false);
+    LockFileLock *lock2 = LFLock_new(folder, name, host2, 0, 100, false);
+    LockFileLock *tmp;
+
+    tmp = LFLock_new(folder, name, host1, 0, 100, false);
+    LFLock_Request_Exclusive(tmp);
+    DECREF(tmp);
+    test_change_pid(runner, folder, SSTR_WRAP_C("locks/test.lock"), tag);
+    TEST_FALSE(runner, LFLock_Request_Exclusive(lock2),
+               "Lock_Exclusive fails with other host's exclusive lock %s",
+               tag);
+    TEST_TRUE(runner, LFLock_Request_Exclusive(lock1),
+              "Lock_Exclusive succeeds with stale exclusive lock %s", tag);
+    LFLock_Release(lock1);
+
+    tmp = LFLock_new(folder, name, host1, 0, 100, false);
+    LFLock_Request_Shared(tmp);
+    DECREF(tmp);
+    test_change_pid(runner, folder, SSTR_WRAP_C("locks/test-1.lock"), tag);
+    TEST_FALSE(runner, LFLock_Request_Exclusive(lock2),
+               "Lock_Exclusive fails with other host's shared lock %s", tag);
+    TEST_TRUE(runner, LFLock_Request_Exclusive(lock1),
+              "Lock_Exclusive succeeds with stale shared files %s", tag);
+    LFLock_Release(lock1);
+
+    DECREF(lock2);
+    DECREF(lock1);
+}
+
+static void
+test_Obtain(TestBatchRunner *runner, Lock *lock1, Lock *lock2,
+            const char *tag) {
+    TEST_TRUE(runner, Lock_Obtain_Shared(lock1), "Obtain_Shared succeeds %s",
+              tag);
+    TEST_FALSE(runner, Lock_Obtain_Exclusive(lock2),
+               "Obtain_Exclusive after Obtain_Shared fails %s", tag);
+    Lock_Release(lock1);
+
+    TEST_TRUE(runner, Lock_Obtain_Exclusive(lock1),
+              "Obtain_Exclusive succeeds %s", tag);
+    TEST_FALSE(runner, Lock_Obtain_Shared(lock2),
+               "Obtain_Shared after Obtain_Exclusive fails %s", tag);
+    Lock_Release(lock1);
+
+    DECREF(lock2);
+    DECREF(lock1);
+}
+
+static void
+S_try_request_shared(void *context) {
+    Lock_Request_Shared((Lock*)context);
+}
+
+static void
+S_try_request_exclusive(void *context) {
+    Lock_Request_Exclusive((Lock*)context);
+}
+
+static void
+S_try_release(void *context) {
+    Lock_Release((Lock*)context);
+}
+
+static void
+test_double_request_release(TestBatchRunner *runner, Lock *lock,
+                            const char *tag) {
+    Err *err;
+
+    Lock_Request_Shared(lock);
+    err = Err_trap(S_try_request_shared, lock);
+    TEST_TRUE(runner, err, "Request_Shared/Request_Shared fails %s",
+              tag);
+    DECREF(err);
+    Lock_Release(lock);
+
+    Lock_Request_Exclusive(lock);
+    err = Err_trap(S_try_request_shared, lock);
+    TEST_TRUE(runner, err, "Request_Shared/Request_Exclusive fails %s",
+              tag);
+    DECREF(err);
+    Lock_Release(lock);
+
+    Lock_Request_Shared(lock);
+    err = Err_trap(S_try_request_exclusive, lock);
+    TEST_TRUE(runner, err, "Request_Exclusive/Request_Shared fails %s",
+              tag);
+    DECREF(err);
+    Lock_Release(lock);
+
+    Lock_Request_Exclusive(lock);
+    err = Err_trap(S_try_request_exclusive, lock);
+    TEST_TRUE(runner, err,
+              "Request_Exclusive/Request_Exclusive fails %s", tag);
+    DECREF(err);
+    Lock_Release(lock);
+
+    err = Err_trap(S_try_release, lock);
+    TEST_TRUE(runner, err, "Double Release fails");
+    DECREF(err);
+
+    DECREF(lock);
+}
+
+static void
+test_empty_lock_folder(TestBatchRunner *runner, Folder *folder,
+                       const char *name, const char *tag) {
+    Vector *files = Folder_List_R(folder, SSTR_WRAP_C("locks"));
+    TEST_TRUE(runner, files, "Lock folder exists after %s tests %s", name,
+              tag);
+    TEST_UINT_EQ(runner, Vec_Get_Size(files), 0,
+                 "Lock folder is empty after %s tests %s", name, tag);
+    DECREF(files);
+}
+
+static void
+test_lf_lock_with_folder(TestBatchRunner *runner, Folder *folder,
+                         const char *tag) {
+    String *name = SSTR_WRAP_C("test");
+    String *host = SSTR_WRAP_C("fuchur");
+    LockFileLock *lock1, *lock2, *lock3;
+
+    lock1 = LFLock_new(folder, name, host, 0, 100, true);
+    lock2 = LFLock_new(folder, name, host, 0, 100, true);
+    test_exclusive_only(runner, (Lock*)lock1, (Lock*)lock2, tag);
+    test_empty_lock_folder(runner, folder, "exclusive only", tag);
+
+    lock1 = LFLock_new(folder, name, host, 0, 100, false);
+    lock2 = LFLock_new(folder, name, host, 0, 100, false);
+    lock3 = LFLock_new(folder, name, host, 0, 100, false);
+    test_lock(runner, (Lock*)lock1, (Lock*)lock2, (Lock*)lock3, tag);
+    test_empty_lock_folder(runner, folder, "lock", tag);
+
+    lock1 = LFLock_new(folder, name, host, 10, 1, false);
+    lock2 = LFLock_new(folder, name, host, 10, 1, false);
+    test_Obtain(runner, (Lock*)lock1, (Lock*)lock2, tag);
+    test_empty_lock_folder(runner, folder, "Obtain", tag);
+
+    lock1 = LFLock_new(folder, name, host, 0, 100, false);
+    test_double_request_release(runner, (Lock*)lock1, tag);
+    test_empty_lock_folder(runner, folder, "double", tag);
+
+    test_stale(runner, folder, tag);
+    test_empty_lock_folder(runner, folder, "stale", tag);
+}
+
+static void
+test_lf_lock(TestBatchRunner *runner) {
+    Folder *fs_folder = S_create_fs_folder();
+    test_lf_lock_with_folder(runner, fs_folder, "(FSFolder)");
+    S_destroy_fs_folder(fs_folder);
+
+    Folder *ram_folder = (Folder*)RAMFolder_new(NULL);
+    test_lf_lock_with_folder(runner, ram_folder, "(RAMFolder)");
+    DECREF(ram_folder);
+}
+
+void
+TestLFLock_Run_IMP(TestLockFileLock *self, TestBatchRunner *runner) {
+    TestBatchRunner_Plan(runner, (TestBatch*)self, 80);
+    test_lf_lock(runner);
+}
+

http://git-wip-us.apache.org/repos/asf/lucy/blob/35388cd2/test/Lucy/Test/Store/TestLock.cfh
----------------------------------------------------------------------
diff --git a/test/Lucy/Test/Store/TestLock.cfh 
b/test/Lucy/Test/Store/TestLock.cfh
new file mode 100644
index 0000000..b87cb7d
--- /dev/null
+++ b/test/Lucy/Test/Store/TestLock.cfh
@@ -0,0 +1,29 @@
+/* Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+parcel TestLucy;
+
+class Lucy::Test::Store::TestLockFileLock nickname TestLFLock
+    inherits Clownfish::TestHarness::TestBatch {
+
+    inert incremented TestLockFileLock*
+    new();
+
+    void
+    Run(TestLockFileLock *self, TestBatchRunner *runner);
+}
+
+

Reply via email to