|
@@ -0,0 +1,161 @@
|
|
|
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
|
|
+//
|
|
|
+// Permission to use, copy, modify, and/or distribute this software for any
|
|
|
+// purpose with or without fee is hereby granted, provided that the above
|
|
|
+// copyright notice and this permission notice appear in all copies.
|
|
|
+//
|
|
|
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
|
|
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
|
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
|
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
|
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
|
|
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
|
+// PERFORMANCE OF THIS SOFTWARE.
|
|
|
+
|
|
|
+#include "util/interprocess_sync_file.h"
|
|
|
+#include <gtest/gtest.h>
|
|
|
+
|
|
|
+using namespace std;
|
|
|
+
|
|
|
+namespace isc {
|
|
|
+namespace util {
|
|
|
+
|
|
|
+class InterprocessSyncFileTest : public ::testing::Test {
|
|
|
+protected:
|
|
|
+ InterprocessSyncFileTest() {}
|
|
|
+};
|
|
|
+
|
|
|
+TEST_F(InterprocessSyncFileTest, TestLock) {
|
|
|
+ InterprocessSync *sync = new InterprocessSyncFile("test");
|
|
|
+ InterprocessSyncLocker *locker = sync->getLocker();
|
|
|
+
|
|
|
+ EXPECT_TRUE(locker->lock());
|
|
|
+
|
|
|
+ int fds[2];
|
|
|
+
|
|
|
+ // Here, we check that a lock has been taken by forking and
|
|
|
+ // checking from the child that a lock exists. This has to be
|
|
|
+ // done from a separate process as we test by trying to lock the
|
|
|
+ // range again on the lock file. The lock attempt would pass if
|
|
|
+ // done from the same process for the granted range. The lock
|
|
|
+ // attempt must fail to pass our check.
|
|
|
+
|
|
|
+ bool was_locked(false);
|
|
|
+
|
|
|
+ pipe(fds);
|
|
|
+
|
|
|
+ if (fork() == 0) {
|
|
|
+ unsigned char locked = 0;
|
|
|
+ // Child writes to pipe
|
|
|
+ close(fds[0]);
|
|
|
+
|
|
|
+ InterprocessSync *sync2 = new InterprocessSyncFile("test");
|
|
|
+ InterprocessSyncLocker *locker2 = sync2->getLocker();
|
|
|
+
|
|
|
+ if (!locker2->tryLock()) {
|
|
|
+ locked = 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ delete locker2;
|
|
|
+ delete sync2;
|
|
|
+
|
|
|
+ write(fds[1], &locked, sizeof locked);
|
|
|
+ close(fds[1]);
|
|
|
+ exit(0);
|
|
|
+ } else {
|
|
|
+ unsigned char locked = 0;
|
|
|
+ // Parent reads from pipe
|
|
|
+ close(fds[1]);
|
|
|
+
|
|
|
+ // Read status and set flag
|
|
|
+ read(fds[0], &locked, sizeof locked);
|
|
|
+ if (locked == 1) {
|
|
|
+ was_locked = true;
|
|
|
+ } else {
|
|
|
+ was_locked = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ close(fds[0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ EXPECT_TRUE(was_locked);
|
|
|
+ EXPECT_TRUE(locker->unlock());
|
|
|
+
|
|
|
+ delete locker;
|
|
|
+ delete sync;
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(InterprocessSyncFileTest, TestMultipleFilesDirect) {
|
|
|
+ InterprocessSync *sync = new InterprocessSyncFile("test1");
|
|
|
+ InterprocessSyncLocker *locker = sync->getLocker();
|
|
|
+
|
|
|
+ EXPECT_TRUE(locker->lock());
|
|
|
+
|
|
|
+ InterprocessSync *sync2 = new InterprocessSyncFile("test2");
|
|
|
+ InterprocessSyncLocker *locker2 = sync2->getLocker();
|
|
|
+ EXPECT_TRUE(locker2->lock());
|
|
|
+ EXPECT_TRUE(locker2->unlock());
|
|
|
+ delete sync2;
|
|
|
+ delete locker2;
|
|
|
+
|
|
|
+ EXPECT_TRUE(locker->unlock());
|
|
|
+
|
|
|
+ delete locker;
|
|
|
+ delete sync;
|
|
|
+}
|
|
|
+
|
|
|
+TEST_F(InterprocessSyncFileTest, TestMultipleFilesForked) {
|
|
|
+ InterprocessSync *sync = new InterprocessSyncFile("test");
|
|
|
+ InterprocessSyncLocker *locker = sync->getLocker();
|
|
|
+
|
|
|
+ EXPECT_TRUE(locker->lock());
|
|
|
+
|
|
|
+ int fds[2];
|
|
|
+
|
|
|
+ bool was_not_locked(true);
|
|
|
+
|
|
|
+ pipe(fds);
|
|
|
+
|
|
|
+ if (fork() == 0) {
|
|
|
+ unsigned char locked = 0xff;
|
|
|
+ // Child writes to pipe
|
|
|
+ close(fds[0]);
|
|
|
+
|
|
|
+ InterprocessSync *sync2 = new InterprocessSyncFile("test2");
|
|
|
+ InterprocessSyncLocker *locker2 = sync2->getLocker();
|
|
|
+
|
|
|
+ if (locker2->tryLock()) {
|
|
|
+ locked = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ delete locker2;
|
|
|
+ delete sync2;
|
|
|
+
|
|
|
+ write(fds[1], &locked, sizeof locked);
|
|
|
+ close(fds[1]);
|
|
|
+ exit(0);
|
|
|
+ } else {
|
|
|
+ unsigned char locked = 0xff;
|
|
|
+ // Parent reads from pipe
|
|
|
+ close(fds[1]);
|
|
|
+
|
|
|
+ // Read status and set flag
|
|
|
+ read(fds[0], &locked, sizeof locked);
|
|
|
+ if (locked == 0) {
|
|
|
+ was_not_locked = true;
|
|
|
+ } else {
|
|
|
+ was_not_locked = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ close(fds[0]);
|
|
|
+ }
|
|
|
+
|
|
|
+ EXPECT_TRUE(was_not_locked);
|
|
|
+ EXPECT_TRUE(locker->unlock());
|
|
|
+
|
|
|
+ delete locker;
|
|
|
+ delete sync;
|
|
|
+}
|
|
|
+
|
|
|
+} // namespace util
|
|
|
+} // namespace isc
|