You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by as...@apache.org on 2013/10/08 17:09:01 UTC

svn commit: r1530301 [3/8] - in /qpid/trunk/qpid: cpp/src/tests/legacystore/ cpp/src/tests/legacystore/federation/ cpp/src/tests/legacystore/jrnl/ cpp/src/tests/legacystore/jrnl/jtt/ cpp/src/tests/legacystore/python_tests/ tools/src/py/ tools/src/py/qp...

Added: qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jdir.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jdir.cpp?rev=1530301&view=auto
==============================================================================
--- qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jdir.cpp (added)
+++ qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jdir.cpp Tue Oct  8 15:09:00 2013
@@ -0,0 +1,416 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <cerrno>
+#include <cstring>
+#include <dirent.h>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include "qpid/legacystore/jrnl/file_hdr.h"
+#include "qpid/legacystore/jrnl/jcfg.h"
+#include "qpid/legacystore/jrnl/jdir.h"
+#include "qpid/legacystore/jrnl/jerrno.h"
+#include "qpid/legacystore/jrnl/jexception.h"
+#include <sys/stat.h>
+
+#define NUM_JFILES 4
+#define JFSIZE_SBLKS 128
+
+#define ERRORSTR(e) std::strerror(e) << " (" << e << ")"
+#define NUM_CLEAR_OPS 20
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jdir_suite)
+
+const string test_filename("_ut_jdir");
+const char* tdp = getenv("TMP_DATA_DIR");
+const string test_dir(tdp && strlen(tdp) > 0 ? string(tdp) + "/_ut_jdir" : "/var/tmp/_ut_jdir");
+
+// === Helper functions ===
+
+void create_file(const char* filename, mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
+{
+    ofstream of(filename, ofstream::out | ofstream::trunc);
+    if (!of.good())
+        BOOST_FAIL("Unable to open file " << filename << " for writing.");
+    of.write(filename, std::strlen(filename));
+    of.close();
+    ::chmod(filename, fmode);
+}
+
+void create_file(const string filename, mode_t fmode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
+{
+    create_file(filename.c_str(), fmode);
+}
+
+void create_jdat_file(const char* dirname, const char* base_filename, u_int32_t fid,
+        u_int64_t first_rid)
+{
+    stringstream fn;
+    fn << dirname << "/" << base_filename << ".";
+    fn << setfill('0') << hex << setw(4) << fid << ".jdat";
+    file_hdr fh(RHM_JDAT_FILE_MAGIC, RHM_JDAT_VERSION, 0, first_rid, fid, 0x200, true);
+    ofstream of(fn.str().c_str(), ofstream::out | ofstream::trunc);
+    if (!of.good())
+        BOOST_FAIL("Unable to open journal data file " << fn << " for writing.");
+    of.write((const char*)&fh, sizeof(file_hdr));
+    of.close();
+}
+
+void create_jinf_file(const char* dirname, const char* base_filename)
+{
+    timespec ts;
+    ::clock_gettime(CLOCK_REALTIME, &ts);
+    jinf ji("test journal id", dirname, base_filename, NUM_JFILES, false, 0, JFSIZE_SBLKS,
+            JRNL_WMGR_DEF_PAGE_SIZE, JRNL_WMGR_DEF_PAGES, ts);
+    ji.write();
+}
+
+void create_jrnl_fileset(const char* dirname, const char* base_filename)
+{
+    create_jinf_file(dirname, base_filename);
+    for (u_int32_t fid = 0; fid < NUM_JFILES; fid++)
+    {
+        u_int64_t rid = 0x12340000 + (fid * 0x25);
+        create_jdat_file(dirname, base_filename, fid, rid);
+    }
+}
+
+unsigned count_dir_contents(const char* dirname, bool incl_files, bool incl_dirs = true)
+{
+    struct dirent* entry;
+    struct stat s;
+    unsigned file_cnt = 0;
+    unsigned dir_cnt = 0;
+    unsigned other_cnt = 0;
+    DIR* dir = ::opendir(dirname);
+    if (!dir)
+        BOOST_FAIL("Unable to open directory " << dirname);
+    while ((entry = ::readdir(dir)) != NULL)
+    {
+        // Ignore . and ..
+        if (std::strcmp(entry->d_name, ".") != 0 && std::strcmp(entry->d_name, "..") != 0)
+        {
+            stringstream fn;
+            fn << dirname << "/" << entry->d_name;
+            if (::stat(fn.str().c_str(), &s))
+                BOOST_FAIL("Unable to stat dir entry " << entry->d_name << "; err=" <<
+                        ERRORSTR(errno));
+            if (S_ISREG(s.st_mode))
+                file_cnt++;
+            else if (S_ISDIR(s.st_mode))
+                dir_cnt++;
+            else
+                other_cnt++;
+        }
+    }
+    ::closedir(dir);
+    if (incl_files)
+    {
+        if (incl_dirs)
+            return file_cnt + dir_cnt;
+        return file_cnt;
+    }
+    else if (incl_dirs)
+        return dir_cnt;
+    return other_cnt;
+}
+
+void check_dir_contents(const char* dirname, const char* base_filename, unsigned num_subdirs,
+        bool jrnl_present)
+{
+    if (jdir::is_dir(dirname))
+    {
+        // Subdir count
+        BOOST_CHECK_EQUAL(count_dir_contents(dirname, false, true), num_subdirs);
+
+        // Journal file count
+        unsigned num_jrnl_files = jrnl_present ? NUM_JFILES + 1 : 0;
+        BOOST_CHECK_EQUAL(count_dir_contents(dirname, true, false), num_jrnl_files);
+
+        // Check journal files are present
+        if (jrnl_present)
+            try { jdir::verify_dir(dirname, base_filename); }
+            catch(const jexception& e) { BOOST_ERROR(e); }
+        for (unsigned subdir_num = 1; subdir_num <= num_subdirs; subdir_num++)
+        {
+            stringstream subdir_name;
+            subdir_name << dirname << "/_" << base_filename << ".bak.";
+            subdir_name << hex << setfill('0') << setw(4) << subdir_num;
+            try { jdir::verify_dir(subdir_name.str().c_str(), base_filename); }
+            catch(const jexception& e) { BOOST_ERROR(e); }
+        }
+    }
+    else
+        BOOST_ERROR(dirname << " is not a directory");
+}
+
+void check_dir_not_existing(const char* dirname)
+{
+    if (jdir::exists(dirname) && jdir::is_dir(dirname))
+        jdir::delete_dir(dirname);
+    if (jdir::exists(dirname))
+        BOOST_FAIL("Unable to remove directory " << dirname);
+}
+
+void check_dir_not_existing(const string dirname)
+{
+    check_dir_not_existing(dirname.c_str());
+}
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(constructor)
+{
+    cout << test_filename << ".constructor: " << flush;
+    string dir(test_dir + "/A/B/C/D/E/F");
+    string bfn("test_base");
+    jdir dir1(dir, bfn);
+    BOOST_CHECK(dir1.dirname().compare(dir) == 0);
+    BOOST_CHECK(dir1.base_filename().compare(bfn) == 0);
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(create_delete_dir)
+{
+    cout << test_filename << ".create_delete_dir: " << flush;
+    // Use instance
+    string dir_A(test_dir + "/A");
+    string dir_Ats(test_dir + "/A/"); // trailing '/'
+    check_dir_not_existing(test_dir + "/A");
+    jdir dir1(dir_A, "test_base");
+    dir1.create_dir();
+    // check all combos of jdir::exists and jdir::is_dir()
+    BOOST_CHECK(jdir::exists(dir_A));
+    BOOST_CHECK(jdir::exists(dir_Ats));
+    BOOST_CHECK(jdir::exists(dir_A.c_str()));
+    BOOST_CHECK(jdir::exists(dir_Ats.c_str()));
+    BOOST_CHECK(jdir::is_dir(dir_A));
+    BOOST_CHECK(jdir::is_dir(dir_Ats));
+    BOOST_CHECK(jdir::is_dir(dir_Ats.c_str()));
+    BOOST_CHECK(jdir::is_dir(dir_Ats.c_str()));
+    // do it a second time when dir exists
+    dir1.create_dir();
+    BOOST_CHECK(jdir::is_dir(dir_A));
+    dir1.delete_dir();
+    BOOST_CHECK(!jdir::exists(dir_A));
+
+    // Use static fn
+    check_dir_not_existing(test_dir + "/B");
+    jdir::create_dir(test_dir + "/B");
+    BOOST_CHECK(jdir::is_dir(test_dir + "/B"));
+    jdir::create_dir(test_dir + "/B");
+    BOOST_CHECK(jdir::is_dir(test_dir + "/B"));
+    jdir::delete_dir(test_dir + "/B");
+    BOOST_CHECK(!jdir::exists(test_dir + "/B"));
+
+    // Non-empty dirs
+    check_dir_not_existing(test_dir + "/C");
+    jdir::create_dir(test_dir + "/C");
+    BOOST_CHECK(jdir::is_dir(test_dir + "/C"));
+    create_file(test_dir + "/C/test_file_1.txt"); // mode 644 (default)
+    create_file(test_dir + "/C/test_file_2.txt", S_IRWXU | S_IRWXG | S_IRWXO); // mode 777
+    create_file(test_dir + "/C/test_file_3.txt", S_IRUSR | S_IRGRP | S_IROTH); // mode 444 (read-only)
+    create_file(test_dir + "/C/test_file_4.txt", 0); // mode 000 (no permissions)
+    BOOST_CHECK(jdir::is_dir(test_dir + "/C"));
+    jdir::create_dir(test_dir + "/C");
+    BOOST_CHECK(jdir::is_dir(test_dir + "/C"));
+    jdir::delete_dir(test_dir + "/C");
+    BOOST_CHECK(!jdir::exists(test_dir + "/C"));
+
+    // Check non-existent dirs fail
+    check_dir_not_existing(test_dir + "/D");
+    try
+    {
+        jdir::is_dir(test_dir + "/D");
+        BOOST_ERROR("jdir::is_dir() failed to throw jexeption for non-existent directory.");
+    }
+    catch(const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_JDIR_STAT);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(create_delete_dir_recursive)
+{
+    cout << test_filename << ".create_delete_dir_recursive: " << flush;
+    // Use instances
+    check_dir_not_existing(test_dir + "/E");
+    jdir dir1(test_dir + "/E/F/G/H", "test_base");
+    dir1.create_dir();
+    BOOST_CHECK(jdir::is_dir(test_dir + "/E/F/G/H"));
+    dir1.delete_dir();
+    BOOST_CHECK(!jdir::exists(test_dir + "/E/F/G/H")); // only H deleted, E/F/G remain
+    BOOST_CHECK(jdir::exists(test_dir + "/E/F/G"));
+    jdir::delete_dir(test_dir + "/E"); // delete remaining dirs
+    BOOST_CHECK(!jdir::exists(test_dir + "/E"));
+
+    check_dir_not_existing(test_dir + "/F");
+    jdir dir2(test_dir + "/F/G/H/I/", "test_base"); // trailing '/'
+    dir2.create_dir();
+    BOOST_CHECK(jdir::is_dir(test_dir + "/F/G/H/I/"));
+    dir2.delete_dir();
+    BOOST_CHECK(!jdir::exists(test_dir + "/F/G/H/I/"));
+    BOOST_CHECK(jdir::exists(test_dir + "/F/G/H/"));
+    jdir::delete_dir(test_dir + "/F");
+    BOOST_CHECK(!jdir::exists(test_dir + "/F"));
+
+    check_dir_not_existing(test_dir + "/G");
+    jdir dir3(test_dir + "/G/H//I//J", "test_base"); // extra '/' in path
+    dir3.create_dir();
+    BOOST_CHECK(jdir::is_dir(test_dir + "/G/H//I//J"));
+    dir3.delete_dir();
+    BOOST_CHECK(!jdir::exists(test_dir + "/G/H//I//J"));
+    BOOST_CHECK(jdir::exists(test_dir + "/G/H//I"));
+    jdir::delete_dir(test_dir + "/F");
+    BOOST_CHECK(!jdir::exists(test_dir + "/F"));
+
+    // Use static fn
+    check_dir_not_existing(test_dir + "/H");
+    jdir::create_dir(test_dir + "/H/I/J/K");
+    BOOST_CHECK(jdir::is_dir(test_dir + "/H/I/J/K"));
+    jdir::delete_dir(test_dir + "/H/I/J/K");
+    BOOST_CHECK(!jdir::exists(test_dir + "/H/I/J/K")); // only J deleted, H/I/J remain
+    BOOST_CHECK(jdir::exists(test_dir + "/H/I/J"));
+    jdir::delete_dir(test_dir + "/H");
+    BOOST_CHECK(!jdir::exists(test_dir + "/H"));
+
+    check_dir_not_existing(test_dir + "/I");
+    jdir::create_dir(test_dir + "/I/J/K/L/"); // trailing '/'
+    BOOST_CHECK(jdir::is_dir(test_dir + "/I/J/K/L/"));
+    jdir::delete_dir(test_dir + "/I/J/K/L/");
+    BOOST_CHECK(!jdir::exists(test_dir + "/I/J/K/L/"));
+    BOOST_CHECK(jdir::exists(test_dir + "/I/J/K/"));
+    jdir::delete_dir(test_dir + "/I");
+    BOOST_CHECK(!jdir::exists(test_dir + "/I"));
+
+    check_dir_not_existing(test_dir + "//J");
+    jdir::create_dir(test_dir + "//J//K//L//M"); // extra '/' in path
+    BOOST_CHECK(jdir::is_dir(test_dir + "//J//K//L//M"));
+    jdir::delete_dir(test_dir + "//J//K//L//M");
+    BOOST_CHECK(!jdir::exists(test_dir + "//J//K//L//M"));
+    BOOST_CHECK(jdir::exists(test_dir + "//J//K//L"));
+    jdir::delete_dir(test_dir + "//J");
+    BOOST_CHECK(!jdir::exists(test_dir + "//J"));
+
+    // Non-empty dirs
+    check_dir_not_existing(test_dir + "/K");
+    jdir::create_dir(test_dir + "/K/L/M1/N1");
+    jdir::create_dir(test_dir + "/K/L/M1/N2");
+    jdir::create_dir(test_dir + "/K/L/M1/N3");
+    jdir::create_dir(test_dir + "/K/L/M1/N4");
+    create_file(test_dir + "/K/L/M1/N4/test_file_1.txt"); // mode 644 (default)
+    create_file(test_dir + "/K/L/M1/N4/test_file_2.txt", S_IRWXU | S_IRWXG | S_IRWXO); // mode 777
+    create_file(test_dir + "/K/L/M1/N4/test_file_3.txt", S_IRUSR | S_IRGRP | S_IROTH); // mode 444
+    create_file(test_dir + "/K/L/M1/N4/test_file_4.txt", 0); // mode 000 (no permissions)
+    jdir::create_dir(test_dir + "/K/L/M2");
+    jdir::create_dir(test_dir + "/K/L/M3/N5");
+    jdir::create_dir(test_dir + "/K/L/M3/N6");
+    BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M1/N1"));
+    BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M1/N2"));
+    BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M1/N3"));
+    BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M1/N4"));
+    BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M2"));
+    BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M3/N5"));
+    BOOST_CHECK(jdir::is_dir(test_dir + "/K/L/M3/N6"));
+    jdir::delete_dir(test_dir + "/K");
+    BOOST_CHECK(!jdir::exists(test_dir + "/K"));
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(clear_verify_dir)
+{
+    cout << test_filename << ".clear_verify_dir: " << flush;
+    // Use instances
+    const char* jrnl_dir = "/var/tmp/test_dir_1";
+    const char* bfn = "test_base";
+    check_dir_not_existing(jrnl_dir);
+    jdir test_dir_1(jrnl_dir, bfn);
+    test_dir_1.create_dir();
+    BOOST_CHECK(jdir::is_dir(jrnl_dir));
+    // add journal files, check they exist, then clear them
+    unsigned cnt = 0;
+    while (cnt < NUM_CLEAR_OPS)
+    {
+        create_jrnl_fileset(jrnl_dir, bfn);
+        check_dir_contents(jrnl_dir, bfn, cnt, true);
+        test_dir_1.clear_dir();
+        check_dir_contents(jrnl_dir, bfn, ++cnt, false);
+    }
+    // clean up
+    test_dir_1.delete_dir();
+    BOOST_CHECK(!jdir::exists(jrnl_dir));
+
+    // Non-existent dir with auto-create true
+    jrnl_dir = "/var/tmp/test_dir_2";
+    check_dir_not_existing(jrnl_dir);
+    jdir test_dir_2(jrnl_dir, bfn);
+    // clear dir
+    test_dir_2.clear_dir(); // create flag is true by default
+    check_dir_contents(jrnl_dir, bfn, 0, false);
+    // clear empty dir, should not create subdir
+    test_dir_2.clear_dir(); // create flag is true by default
+    check_dir_contents(jrnl_dir, bfn, 0, false);
+    // clean up
+    test_dir_2.delete_dir();
+    BOOST_CHECK(!jdir::exists(jrnl_dir));
+
+    // non-existent dir with auto-create false
+    jrnl_dir = "/var/tmp/test_dir_3";
+    check_dir_not_existing(jrnl_dir);
+    jdir test_dir_3(jrnl_dir, bfn);
+    try
+    {
+        test_dir_3.clear_dir(false);
+        BOOST_ERROR("jdir::clear_dir(flase) failed to throw jexeption for non-existent directory.");
+    }
+    catch(const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_JDIR_OPENDIR);
+    }
+
+    // Use static fn
+    jrnl_dir = "/var/tmp/test_dir_4";
+    check_dir_not_existing(jrnl_dir);
+    jdir::clear_dir(jrnl_dir, bfn); // should create dir if it does not exist
+    // add journal files, check they exist, then clear them
+    cnt = 0;
+    while (cnt < NUM_CLEAR_OPS)
+    {
+        create_jrnl_fileset(jrnl_dir, bfn);
+        check_dir_contents(jrnl_dir, bfn, cnt, true);
+        jdir::clear_dir(jrnl_dir, bfn);
+        check_dir_contents(jrnl_dir, bfn, ++cnt, false);
+    }
+    // clean up
+    jdir::delete_dir(jrnl_dir);
+    BOOST_CHECK(!jdir::exists(jrnl_dir));
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()

Added: qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jerrno.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jerrno.cpp?rev=1530301&view=auto
==============================================================================
--- qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jerrno.cpp (added)
+++ qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jerrno.cpp Tue Oct  8 15:09:00 2013
@@ -0,0 +1,47 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <cstring>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jerrno.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jerrno_suite)
+using namespace mrg::journal;
+
+const string test_filename("_ut_jerrno");
+
+QPID_AUTO_TEST_CASE(jerrno_val)
+{
+    cout << test_filename << ".jerrno_val: " << flush;
+    const char* m = "JERR__MALLOC";
+    string malloc_msg = string(jerrno::err_msg(jerrno::JERR__MALLOC));
+    BOOST_CHECK(malloc_msg.substr(0, std::strlen(m)).compare(m) == 0);
+    BOOST_CHECK(std::strcmp(jerrno::err_msg(0), "<Unknown error code>") == 0);
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()

Added: qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jexception.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jexception.cpp?rev=1530301&view=auto
==============================================================================
--- qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jexception.cpp (added)
+++ qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jexception.cpp Tue Oct  8 15:09:00 2013
@@ -0,0 +1,346 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <cstring>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jerrno.h"
+#include "qpid/legacystore/jrnl/jexception.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jexception_suite)
+
+const string test_filename("_ut_jexception");
+
+// === Helper functions ===
+
+void throw_exception(const jexception& e, std::size_t what_len, std::size_t ai_len,
+        std::size_t tc_len, std::size_t tf_len)
+{
+    try { throw e; }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(std::strlen(e.what()), what_len);
+        BOOST_CHECK_EQUAL(e.additional_info().size(), ai_len);
+        BOOST_CHECK_EQUAL(e.throwing_class().size(), tc_len);
+        BOOST_CHECK_EQUAL(e.throwing_fn().size(), tf_len);
+    }
+}
+
+void throw_exception(const jexception& e, std::size_t what_len, std::size_t ai_len)
+{
+    throw_exception(e, what_len, ai_len, 0, 0);
+}
+
+void throw_exception(const jexception& e, std::size_t what_len, std::size_t tc_len,
+        std::size_t tf_len)
+{
+    throw_exception(e, what_len, 0, tc_len, tf_len);
+}
+
+// === Test suite ===
+
+QPID_AUTO_TEST_CASE(constructor_1)
+{
+    cout << test_filename << ".constructor_1: " << flush;
+    try
+    {
+        jexception e1;
+        BOOST_CHECK_EQUAL(e1.err_code(), (u_int32_t)0);
+        BOOST_CHECK(e1.additional_info().size() == 0);
+        BOOST_CHECK(e1.throwing_class().size() == 0);
+        BOOST_CHECK(e1.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e1.what()) > 0);
+        throw e1;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), (u_int32_t)0);
+        BOOST_CHECK(e.additional_info().size() == 0);
+        BOOST_CHECK(e.throwing_class().size() == 0);
+        BOOST_CHECK(e.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_2)
+{
+    cout << test_filename << ".constructor_2: " << flush;
+    const u_int32_t err_code = 2;
+    try
+    {
+        jexception e2(err_code);
+        BOOST_CHECK_EQUAL(e2.err_code(), err_code);
+        BOOST_CHECK(e2.additional_info().size() == 0);
+        BOOST_CHECK(e2.throwing_class().size() == 0);
+        BOOST_CHECK(e2.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e2.what()) > 0);
+        throw e2;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), err_code);
+        BOOST_CHECK(e.additional_info().size() == 0);
+        BOOST_CHECK(e.throwing_class().size() == 0);
+        BOOST_CHECK(e.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_3a)
+{
+    cout << test_filename << ".constructor_3a: " << flush;
+    const char* err_msg = "exception3";
+    try
+    {
+        jexception e3(err_msg);
+        BOOST_CHECK_EQUAL(e3.err_code(), (u_int32_t)0);
+        BOOST_CHECK(e3.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e3.throwing_class().size() == 0);
+        BOOST_CHECK(e3.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e3.what()) > 0);
+        throw e3;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), (u_int32_t)0);
+        BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e.throwing_class().size() == 0);
+        BOOST_CHECK(e.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_3b)
+{
+    cout << test_filename << ".constructor_3b: " << flush;
+    const string err_msg("exception3");
+    try
+    {
+        jexception e3(err_msg);
+        BOOST_CHECK_EQUAL(e3.err_code(), (u_int32_t)0);
+        BOOST_CHECK(e3.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e3.throwing_class().size() == 0);
+        BOOST_CHECK(e3.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e3.what()) > 0);
+        throw e3;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), (u_int32_t)0);
+        BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e.throwing_class().size() == 0);
+        BOOST_CHECK(e.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_4a)
+{
+    cout << test_filename << ".constructor_4a: " << flush;
+    const u_int32_t err_code = 4;
+    const char* err_msg = "exception4";
+    try
+    {
+        jexception e4(err_code, err_msg);
+        BOOST_CHECK_EQUAL(e4.err_code(), err_code);
+        BOOST_CHECK(e4.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e4.throwing_class().size() == 0);
+        BOOST_CHECK(e4.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e4.what()) > 0);
+        throw e4;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), err_code);
+        BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e.throwing_class().size() == 0);
+        BOOST_CHECK(e.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_4b)
+{
+    cout << test_filename << ".constructor_4b: " << flush;
+    const u_int32_t err_code = 4;
+    const string err_msg("exception4");
+    try
+    {
+        jexception e4(err_code, err_msg);
+        BOOST_CHECK_EQUAL(e4.err_code(), err_code);
+        BOOST_CHECK(e4.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e4.throwing_class().size() == 0);
+        BOOST_CHECK(e4.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e4.what()) > 0);
+        throw e4;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), err_code);
+        BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e.throwing_class().size() == 0);
+        BOOST_CHECK(e.throwing_fn().size() == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_5a)
+{
+    cout << test_filename << ".constructor_5a: " << flush;
+    const u_int32_t err_code = 5;
+    const char* err_class = "class5";
+    const char* err_fn = "fn5";
+    try
+    {
+        jexception e5(err_code, err_class, err_fn);
+        BOOST_CHECK_EQUAL(e5.err_code(), err_code);
+        BOOST_CHECK(e5.additional_info().size() == 0);
+        BOOST_CHECK(e5.throwing_class().compare(err_class) == 0);
+        BOOST_CHECK(e5.throwing_fn().compare(err_fn) == 0);
+        BOOST_CHECK(std::strlen(e5.what()) > 0);
+        throw e5;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), err_code);
+        BOOST_CHECK(e.additional_info().size() == 0);
+        BOOST_CHECK(e.throwing_class().compare(err_class) == 0);
+        BOOST_CHECK(e.throwing_fn().compare(err_fn) == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_5b)
+{
+    cout << test_filename << ".constructor_5b: " << flush;
+    const u_int32_t err_code = 5;
+    const string err_class("class5");
+    const string err_fn("fn5");
+    try
+    {
+        jexception e5(err_code, err_class, err_fn);
+        BOOST_CHECK_EQUAL(e5.err_code(), err_code);
+        BOOST_CHECK(e5.additional_info().size() == 0);
+        BOOST_CHECK(e5.throwing_class().compare(err_class) == 0);
+        BOOST_CHECK(e5.throwing_fn().compare(err_fn) == 0);
+        BOOST_CHECK(std::strlen(e5.what()) > 0);
+        throw e5;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), err_code);
+        BOOST_CHECK(e.additional_info().size() == 0);
+        BOOST_CHECK(e.throwing_class().compare(err_class) == 0);
+        BOOST_CHECK(e.throwing_fn().compare(err_fn) == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_6a)
+{
+    cout << test_filename << ".constructor_6a: " << flush;
+    const u_int32_t err_code = 6;
+    const char* err_msg = "exception6";
+    const char* err_class = "class6";
+    const char* err_fn = "fn6";
+    try
+    {
+        jexception e6(err_code, err_msg, err_class, err_fn);
+        BOOST_CHECK_EQUAL(e6.err_code(), err_code);
+        BOOST_CHECK(e6.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e6.throwing_class().compare(err_class) == 0);
+        BOOST_CHECK(e6.throwing_fn().compare(err_fn) == 0);
+        BOOST_CHECK(std::strlen(e6.what()) > 0);
+        throw e6;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), err_code);
+        BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e.throwing_class().compare(err_class) == 0);
+        BOOST_CHECK(e.throwing_fn().compare(err_fn) == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(constructor_6b)
+{
+    cout << test_filename << ".constructor_6b: " << flush;
+    const u_int32_t err_code = 6;
+    const string err_msg("exception6");
+    const string err_class("class6");
+    const string err_fn("fn6");
+    try
+    {
+        jexception e6(err_code, err_msg, err_class, err_fn);
+        BOOST_CHECK_EQUAL(e6.err_code(), err_code);
+        BOOST_CHECK(e6.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e6.throwing_class().compare(err_class) == 0);
+        BOOST_CHECK(e6.throwing_fn().compare(err_fn) == 0);
+        BOOST_CHECK(std::strlen(e6.what()) > 0);
+        throw e6;
+    }
+    catch (const jexception& e)
+    {
+        BOOST_CHECK_EQUAL(e.err_code(), err_code);
+        BOOST_CHECK(e.additional_info().compare(err_msg) == 0);
+        BOOST_CHECK(e.throwing_class().compare(err_class) == 0);
+        BOOST_CHECK(e.throwing_fn().compare(err_fn) == 0);
+        BOOST_CHECK(std::strlen(e.what()) > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_CASE(msg_scope)
+{
+    cout << test_filename << ".msg_scope: " << flush;
+    try
+    {
+        // These will go out of scope as soon as jexception is thrown...
+        const string msg("Error message");
+        const string cls("class");
+        const string fn("function");
+        throw jexception(100, msg, cls, fn);
+    }
+    catch (const jexception& e)
+    {
+        stringstream ss;
+        ss << e;
+        BOOST_CHECK(ss.str().size() > 0);
+    }
+    cout << "ok" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()

Added: qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jinf.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jinf.cpp?rev=1530301&view=auto
==============================================================================
--- qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jinf.cpp (added)
+++ qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_jinf.cpp Tue Oct  8 15:09:00 2013
@@ -0,0 +1,402 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "../unit_test.h"
+
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(jinf_suite)
+
+const string test_filename("_ut_jinf");
+
+#include "_st_helper_fns.h"
+
+timespec ts;
+
+QPID_AUTO_TEST_CASE(write_constructor)
+{
+    string test_name = get_test_name(test_filename, "write_constructor");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    jdir::create_dir(test_dir); // Check test dir exists; create it if not
+    ::clock_gettime(CLOCK_REALTIME, &ts);
+    jinf ji(jid, test_dir, base_filename, NUM_JFILES, false, 0, JFSIZE_SBLKS, JRNL_WMGR_DEF_PAGE_SIZE, JRNL_WMGR_DEF_PAGES, ts);
+    BOOST_CHECK_EQUAL(ji.jver(), RHM_JDAT_VERSION);
+    BOOST_CHECK(ji.jid().compare(jid) == 0);
+    BOOST_CHECK(ji.jdir().compare(test_dir) == 0);
+    BOOST_CHECK(ji.base_filename().compare(base_filename) == 0);
+    const timespec this_ts = ji.ts();
+    BOOST_CHECK_EQUAL(this_ts.tv_sec, ts.tv_sec);
+    BOOST_CHECK_EQUAL(this_ts.tv_nsec, ts.tv_nsec);
+    BOOST_CHECK_EQUAL(ji.num_jfiles(), u_int16_t(NUM_JFILES));
+    BOOST_CHECK_EQUAL(ji.is_ae(), false);
+    BOOST_CHECK_EQUAL(ji.ae_max_jfiles(), u_int16_t(0));
+    BOOST_CHECK_EQUAL(ji.jfsize_sblks(), u_int32_t(JFSIZE_SBLKS));
+    BOOST_CHECK_EQUAL(ji.sblk_size_dblks(), u_int16_t(JRNL_SBLK_SIZE));
+    BOOST_CHECK_EQUAL(ji.dblk_size(), u_int32_t(JRNL_DBLK_SIZE));
+    BOOST_CHECK_EQUAL(ji.wcache_pgsize_sblks(), u_int32_t(JRNL_WMGR_DEF_PAGE_SIZE));
+    BOOST_CHECK_EQUAL(ji.wcache_num_pages(), u_int16_t(JRNL_WMGR_DEF_PAGES));
+    BOOST_CHECK_EQUAL(ji.rcache_pgsize_sblks(), u_int32_t(JRNL_RMGR_PAGE_SIZE));
+    BOOST_CHECK_EQUAL(ji.rcache_num_pages(), u_int16_t(JRNL_RMGR_PAGES));
+    ji.write();
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(read_constructor)
+{
+    string test_name = get_test_name(test_filename, "read_constructor");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map::create_new_jinf(jid, base_filename, false);
+
+    stringstream fn;
+    fn << test_dir << "/" <<base_filename  << "." << JRNL_INFO_EXTENSION;
+    jinf ji(fn.str(), false);
+    BOOST_CHECK_EQUAL(ji.jver(), RHM_JDAT_VERSION);
+    BOOST_CHECK(ji.jid().compare(jid) == 0);
+    BOOST_CHECK(ji.jdir().compare(test_dir) == 0);
+    BOOST_CHECK(ji.base_filename().compare(base_filename) == 0);
+//     const timespec this_ts = ji.ts();
+//     BOOST_CHECK_EQUAL(this_ts.tv_sec, ts.tv_sec);
+//     BOOST_CHECK_EQUAL(this_ts.tv_nsec, ts.tv_nsec);
+    BOOST_CHECK_EQUAL(ji.num_jfiles(), u_int16_t(NUM_JFILES));
+    BOOST_CHECK_EQUAL(ji.is_ae(), false);
+    BOOST_CHECK_EQUAL(ji.ae_max_jfiles(), u_int16_t(0));
+    BOOST_CHECK_EQUAL(ji.jfsize_sblks(), u_int32_t(JFSIZE_SBLKS));
+    BOOST_CHECK_EQUAL(ji.sblk_size_dblks(), u_int16_t(JRNL_SBLK_SIZE));
+    BOOST_CHECK_EQUAL(ji.dblk_size(), u_int32_t(JRNL_DBLK_SIZE));
+    BOOST_CHECK_EQUAL(ji.wcache_pgsize_sblks(), u_int32_t(JRNL_WMGR_DEF_PAGE_SIZE));
+    BOOST_CHECK_EQUAL(ji.wcache_num_pages(), u_int16_t(JRNL_WMGR_DEF_PAGES));
+    BOOST_CHECK_EQUAL(ji.rcache_pgsize_sblks(), u_int32_t(JRNL_RMGR_PAGE_SIZE));
+    BOOST_CHECK_EQUAL(ji.rcache_num_pages(), u_int16_t(JRNL_RMGR_PAGES));
+
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(set_functions)
+{
+    string test_name = get_test_name(test_filename, "set_functions");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map::create_new_jinf(jid, base_filename, false);
+
+    stringstream fn;
+    fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+    jinf ji(fn.str(), false);
+
+    ji.set_jdir("abc123");
+    BOOST_CHECK(ji.jdir().compare("abc123") == 0);
+    ji.set_jdir(test_dir);
+    BOOST_CHECK(ji.jdir().compare(test_dir) == 0);
+    ji.incr_num_jfiles();
+    BOOST_CHECK_EQUAL(ji.num_jfiles(), u_int16_t(NUM_JFILES+1));
+    ji.incr_num_jfiles();
+    BOOST_CHECK_EQUAL(ji.num_jfiles(), u_int16_t(NUM_JFILES+2));
+
+    lfid_pfid_map::clean_journal_info_file(test_dir);
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(validate)
+{
+    string test_name = get_test_name(test_filename, "validate");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map::create_new_jinf(jid, base_filename, false);
+
+    stringstream fn;
+    fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+    jinf ji(fn.str(), true);
+    // TODO: Check validation picks up conflict, but need to be friend to jinf to do it
+
+    lfid_pfid_map::clean_journal_info_file(test_dir);
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_empty_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_empty_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    jdir::create_dir(test_dir); // Check test dir exists; create it if not
+
+    lfid_pfid_map m(jid, base_filename);
+    m.journal_create(NUM_JFILES, 0, 0);
+    m.write_journal(false, 0);
+
+    stringstream fn;
+    fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+    jinf ji(fn.str(), false);
+    try { ji.analyze(); }
+    catch (const jexception& e)
+    {
+        if (e.err_code() != jerrno::JERR_JINF_JDATEMPTY)
+            BOOST_ERROR("Failed to throw expected exception jerrno::JERR_JINF_JDATEMPTY");
+    }
+
+    m.destroy_journal();
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_part_full_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_part_full_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map m(jid, base_filename);
+    for (u_int16_t num_files = 1; num_files < NUM_JFILES; num_files++)
+    {
+        m.journal_create(NUM_JFILES, num_files, 0);
+        m.write_journal(false, 0);
+
+        stringstream fn;
+        fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+        jinf ji(fn.str(), false);
+        ji.analyze();
+        m.check_analysis(ji);
+
+        m.destroy_journal();
+    }
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_full_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_full_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map m(jid, base_filename);
+    for (u_int16_t file_num = 0; file_num < NUM_JFILES; file_num++)
+    {
+        m.journal_create(NUM_JFILES, NUM_JFILES, file_num);
+        m.write_journal(false, 0);
+
+        stringstream fn;
+        fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+        jinf ji(fn.str(), false);
+        ji.analyze();
+        m.check_analysis(ji);
+
+        m.destroy_journal();
+    }
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_single_appended_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_single_appended_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map m(jid, base_filename);
+    for (u_int16_t oldest_lid = 0; oldest_lid < NUM_JFILES; oldest_lid++)
+       for (u_int16_t after_lid = 0; after_lid < NUM_JFILES; after_lid++)
+            for (u_int16_t num_files = 1; num_files <= 5; num_files++)
+            {
+                m.journal_create(NUM_JFILES, NUM_JFILES, oldest_lid);
+                m.journal_insert(after_lid, num_files);
+                m.write_journal(true, 16);
+
+                stringstream fn;
+                fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+                jinf ji(fn.str(), false);
+                ji.analyze();
+                m.check_analysis(ji);
+
+                m.destroy_journal();
+            }
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_multi_appended_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_multi_appended_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map m(jid, base_filename);
+    ::srand48(1);
+
+    for (u_int16_t num_appends = 1; num_appends <= 2*NUM_JFILES; num_appends++)
+    {
+        const u_int16_t oldest_lid = u_int16_t(NUM_JFILES * ::drand48());
+        m.journal_create(NUM_JFILES, NUM_JFILES, oldest_lid);
+        for (u_int16_t a = 0; a < num_appends; a++)
+        {
+            const u_int16_t num_files = u_int16_t(1 + (NUM_JFILES * ::drand48()));
+            const u_int16_t after_lid = u_int16_t(m.size() * ::drand48());
+            m.journal_insert(after_lid, num_files);
+        }
+        m.write_journal(true, 24);
+
+        stringstream fn;
+        fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+        jinf ji(fn.str(), false);
+        ji.analyze();
+        m.check_analysis(ji);
+
+        m.destroy_journal();
+    }
+
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_multi_appended_then_failed_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_multi_appended_then_failed_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map m(jid, base_filename);
+    ::srand48(1);
+
+    // As this test relies on repeatable but random sequences, use many iterations for coverage
+    for (int c = 1; c <= 100; c++)
+    {
+        for (u_int16_t num_appends = 1; num_appends <= 2*NUM_JFILES; num_appends++)
+        {
+            u_int16_t oldest_lid = u_int16_t(NUM_JFILES * ::drand48());
+            m.journal_create(NUM_JFILES, NUM_JFILES, oldest_lid);
+            for (u_int16_t a = 0; a < num_appends-1; a++)
+            {
+                const u_int16_t num_files = u_int16_t(1 + (NUM_JFILES * ::drand48()));
+                const u_int16_t after_lid = u_int16_t(m.size() * ::drand48());
+                m.journal_insert(after_lid, num_files);
+                if (after_lid < oldest_lid)
+                    oldest_lid += num_files;
+            }
+            const u_int16_t num_files = u_int16_t(1 + (NUM_JFILES * ::drand48()));
+            const u_int16_t after_lid = oldest_lid == 0 ? m.size() - 1 : oldest_lid - 1;
+            m.journal_insert(after_lid, num_files, false);
+            m.write_journal(true, 32);
+
+            stringstream fn;
+            fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+            jinf ji(fn.str(), false);
+            ji.analyze();
+            m.check_analysis(ji);
+
+            m.destroy_journal();
+        }
+    }
+
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_inconsistent_jdat_file_size_in_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_inconsistent_jdat_file_size_in_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map m(jid, base_filename);
+    ::srand48(1);
+
+    for (u_int16_t pfid = 1; pfid < NUM_JFILES; pfid++)
+    {
+        m.journal_create(NUM_JFILES, NUM_JFILES, 0);
+        m.write_journal(false, 0);
+
+        const std::string filename = m.create_journal_filename(pfid, base_filename);
+        std::ofstream of(filename.c_str(), ofstream::out | ofstream::app);
+        if (!of.good())
+            BOOST_FAIL("Unable to open test journal file \"" << filename << "\" for writing.");
+        std::size_t expand_size = std::size_t(10 * JRNL_DBLK_SIZE * JRNL_SBLK_SIZE * ::drand48());
+        std::vector<char> sblk_buffer(expand_size, 0);
+        of.write(&sblk_buffer[0], expand_size);
+        of.close();
+
+        stringstream fn;
+        fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+        jinf ji(fn.str(), false);
+        try
+        {
+            ji.analyze();
+            BOOST_FAIL("Failed to detect irregular journal file size in file \"" << filename << "\"");
+        }
+        catch (const jexception& e) {} // ignore - expected
+
+        m.destroy_journal();
+    }
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_owi_in_non_ae_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_owi_in_non_ae_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map m(jid, base_filename);
+    for (u_int16_t oldest_file = 1; oldest_file < NUM_DEFAULT_JFILES-1; oldest_file++)
+    {
+        for (u_int16_t bad_owi_file = oldest_file + 1; bad_owi_file < NUM_DEFAULT_JFILES; bad_owi_file++)
+        {
+            m.journal_create(NUM_DEFAULT_JFILES, NUM_DEFAULT_JFILES, oldest_file, bad_owi_file);
+            m.write_journal(false, 0);
+
+            stringstream fn;
+            fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+            jinf ji(fn.str(), false);
+            try
+            {
+                ji.analyze();
+                BOOST_FAIL("Failed to detect irregular OWI flag in non-ae journal file \"" << fn << "\"");
+            }
+            catch (const jexception& e) {} // ignore - expected
+
+            m.destroy_journal();
+        }
+    }
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_CASE(analyze_owi_in_ae_min_size_journal)
+{
+    string test_name = get_test_name(test_filename, "analyze_owi_in_ae_min_size_journal");
+    const string jid = test_name + "_jid";
+    const string base_filename = test_name + "_bfn";
+    lfid_pfid_map m(jid, base_filename);
+    for (u_int16_t oldest_file = 1; oldest_file < NUM_JFILES-1; oldest_file++)
+    {
+        for (u_int16_t bad_owi_file = oldest_file + 1; bad_owi_file < NUM_JFILES; bad_owi_file++)
+        {
+            m.journal_create(NUM_JFILES, NUM_JFILES, oldest_file, bad_owi_file);
+            m.write_journal(true, 16);
+
+            stringstream fn;
+            fn << test_dir << "/" << base_filename << "." << JRNL_INFO_EXTENSION;
+            jinf ji(fn.str(), false);
+            try
+            {
+                ji.analyze();
+                BOOST_FAIL("Failed to detect irregular OWI flag in min-sized ae journal file \"" << fn << "\"");
+            }
+            catch (const jexception& e) {} // ignore - expected
+
+            m.destroy_journal();
+        }
+    }
+    cout << "done" << endl;
+}
+
+QPID_AUTO_TEST_SUITE_END()

Added: qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_lpmgr.cpp
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_lpmgr.cpp?rev=1530301&view=auto
==============================================================================
--- qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_lpmgr.cpp (added)
+++ qpid/trunk/qpid/cpp/src/tests/legacystore/jrnl/_ut_lpmgr.cpp Tue Oct  8 15:09:00 2013
@@ -0,0 +1,886 @@
+/*
+ *
+ * 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.
+ *
+ */
+
+#include "../unit_test.h"
+#include <cmath>
+#include <iostream>
+#include "qpid/legacystore/jrnl/jcntl.h"
+#include "qpid/legacystore/jrnl/lpmgr.h"
+
+using namespace boost::unit_test;
+using namespace mrg::journal;
+using namespace std;
+
+QPID_AUTO_TEST_SUITE(arr_cnt_suite)
+
+const string test_filename("_ut_lpmgr");
+
+#include "_st_helper_fns.h"
+
+// === Helper functions and definitions ===
+
+typedef vector<u_int16_t> flist;
+typedef flist::const_iterator flist_citr;
+
+class lpmgr_test_helper
+{
+    lpmgr_test_helper() {}
+    virtual ~lpmgr_test_helper() {}
+
+public:
+    static void check_pfids_lfids(const lpmgr& lm, const u_int16_t pfids[], const u_int16_t lfids[],
+            const size_t pfid_lfid_size)
+    {
+        vector<u_int16_t> res;
+        lm.get_pfid_list(res);
+        vectors_equal(lm, pfids, pfid_lfid_size, res, true);
+        lm.get_lfid_list(res);
+        vectors_equal(lm, lfids, pfid_lfid_size, res, false);
+    }
+
+    static void check_pfids_lfids(const lpmgr& lm, const flist& pfids, const flist lfids)
+    {
+        vector<u_int16_t> res;
+        lm.get_pfid_list(res);
+        vectors_equal(lm, pfids, res, true);
+        lm.get_lfid_list(res);
+        vectors_equal(lm, lfids, res, false);
+    }
+
+    static void check_linear_pfids_lfids(const lpmgr& lm, const size_t pfid_lfid_size)
+    {
+        vector<u_int16_t> res;
+        lm.get_pfid_list(res);
+        linear_vectors_equal(lm, pfid_lfid_size, res, true);
+        lm.get_lfid_list(res);
+        linear_vectors_equal(lm, pfid_lfid_size, res, false);
+    }
+
+    static void rcvdat_init(rcvdat& rd, const u_int16_t num_jfiles, const bool ae, const u_int16_t ae_max_jfiles,
+        const u_int16_t pfids[])
+    {
+        rd.reset(num_jfiles, ae, ae_max_jfiles);
+        load_vector(pfids, num_jfiles, rd._fid_list);
+        rd._jempty = false;
+        rd._lfid = pfids[num_jfiles - 1];
+        rd._eo = 100 * JRNL_DBLK_SIZE * JRNL_SBLK_SIZE;
+    }
+
+    static void rcvdat_init(rcvdat& rd, const flist& pfidl, const bool ae, const u_int16_t ae_max_jfiles)
+    {
+        const u_int16_t num_jfiles = pfidl.size();
+        rd.reset(num_jfiles, ae, ae_max_jfiles);
+        load_vector(pfidl, rd._fid_list);
+        rd._jempty = false;
+        rd._lfid = pfidl[num_jfiles - 1];
+        rd._eo = 100 * JRNL_DBLK_SIZE * JRNL_SBLK_SIZE;
+    }
+
+    static void initialize(lpmgr& lm, test_jrnl& jc, const u_int16_t num_jfiles, const bool ae,
+            const u_int16_t ae_max_jfiles)
+    {
+        lm.initialize(num_jfiles, ae, ae_max_jfiles, &jc, &jc.new_fcntl);
+        BOOST_CHECK_EQUAL(lm.is_init(), true);
+        BOOST_CHECK_EQUAL(lm.is_ae(), ae);
+        BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+        BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles);
+        if (num_jfiles)
+            check_linear_pfids_lfids(lm, num_jfiles);
+        else
+            BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+    }
+
+    // version which sets up the lfid_pfid_map for later manipulation by insert tests
+    static void initialize(lfid_pfid_map& lfm, lpmgr& lm, test_jrnl& jc, const u_int16_t num_jfiles, const bool ae,
+            const u_int16_t ae_max_jfiles)
+    {
+        lfm.journal_create(num_jfiles, num_jfiles);
+        initialize(lm, jc, num_jfiles, ae, ae_max_jfiles);
+    }
+
+    static void prepare_recover(lfid_pfid_map& lfm, const u_int16_t size)
+    {
+        if (size < 4) BOOST_FAIL("prepare_recover(): size parameter (" << size << ") too small.");
+        lfm.journal_create(4, 4); // initial journal of size 4
+        u_int16_t s = 4; // cumulative size
+        while (s < size)
+        {
+            const u_int16_t ins_posn = u_int16_t(s * ::drand48()); // this insert posn
+            if (3.0 * ::drand48() > 1.0 || size - s < 2) // 2:1 chance of single insert when >= 2 still to insert
+            {
+                lfm.journal_insert(ins_posn); // single insert
+                s++;
+            }
+            else
+            {
+                // multiple insert, either 2 - 5
+                const u_int16_t max_ins_size = size - s >5 ? 5 : size - s;
+                const u_int16_t ins_size = 2 + u_int16_t((max_ins_size - 2) * ::drand48()); // this insert size
+                lfm.journal_insert(ins_posn, ins_size);
+                s += ins_size;
+            }
+        }
+    }
+
+    static void recover(lfid_pfid_map& lfm, lpmgr& lm, test_jrnl& jc, const bool ae, const u_int16_t ae_max_jfiles)
+    {
+        flist pfidl;
+        flist lfidl;
+        rcvdat rd;
+        const u_int16_t num_jfiles = lfm.size();
+
+        lfm.get_pfid_list(pfidl);
+        lfm.get_lfid_list(lfidl);
+        lm.finalize(); // clear all file handles before erasing old journal files
+        lfm.write_journal(ae, ae_max_jfiles, JFSIZE_SBLKS);
+
+        lpmgr_test_helper::rcvdat_init(rd, pfidl, ae, ae_max_jfiles);
+        lm.recover(rd, &jc, &jc.new_fcntl);
+        BOOST_CHECK_EQUAL(lm.is_init(), true);
+        BOOST_CHECK_EQUAL(lm.is_ae(), ae);
+        BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+        BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles);
+        if (num_jfiles)
+            check_pfids_lfids(lm, pfidl, lfidl);
+        else
+            BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+    }
+
+    static void finalize(lpmgr& lm)
+    {
+        lm.finalize();
+        BOOST_CHECK_EQUAL(lm.is_init(), false);
+        BOOST_CHECK_EQUAL(lm.is_ae(), false);
+        BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), u_int16_t(0));
+        BOOST_CHECK_EQUAL(lm.num_jfiles(), u_int16_t(0));
+        BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+        vector<u_int16_t> res;
+        lm.get_pfid_list(res);
+        BOOST_CHECK_EQUAL(res.size(), u_int16_t(0));
+        lm.get_lfid_list(res);
+        BOOST_CHECK_EQUAL(res.size(), u_int16_t(0));
+    }
+
+    static void insert(lfid_pfid_map& lfm, lpmgr& lm, test_jrnl& jc, const u_int16_t after_lfid, const u_int16_t incr = 1)
+    {
+        flist pfidl;
+        flist lfidl;
+        const u_int16_t num_jfiles = lm.num_jfiles();
+        lfm.journal_insert(after_lfid, incr);
+        lfm.get_pfid_list(pfidl);
+        lfm.get_lfid_list(lfidl);
+        lm.insert(after_lfid, &jc, &jc.new_fcntl, incr);
+        BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles + incr);
+        lpmgr_test_helper::check_pfids_lfids(lm, pfidl, lfidl);
+    }
+
+    static void check_ae_max_jfiles(lpmgr& lm, const u_int16_t num_jfiles, const u_int16_t ae_max_jfiles)
+    {
+        bool legal = ae_max_jfiles > num_jfiles || ae_max_jfiles == 0;
+
+        lm.set_ae(false);
+        BOOST_CHECK(!lm.is_ae());
+        if (legal)
+        {
+            lm.set_ae_max_jfiles(ae_max_jfiles);
+            BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+            lm.set_ae(true);
+            BOOST_CHECK(lm.is_ae());
+            BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), ae_max_jfiles
+                                                  ? ae_max_jfiles - num_jfiles
+                                                  : JRNL_MAX_NUM_FILES - num_jfiles);
+        }
+        else
+        {
+            lm.set_ae_max_jfiles(ae_max_jfiles);
+            BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+            try
+            {
+                lm.set_ae(true); // should raise exception
+                BOOST_ERROR("Auto-expand enabled with out-of-range ae_max_jfiles");
+            }
+            catch (const jexception& e) { BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_LFMGR_BADAEFNUMLIM); }
+            BOOST_CHECK(!lm.is_ae());
+            BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), 0);
+        }
+        BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), ae_max_jfiles);
+    }
+
+    static void check_multiple_initialization_recover(lfid_pfid_map& lfm, test_jrnl& jc,
+            const u_int16_t num_jfiles_arr[][2], const bool init_flag_0, const bool finalize_flag,
+            const bool init_flag_1)
+    {
+        unsigned i_njf = 0;
+        while (num_jfiles_arr[i_njf][0] && num_jfiles_arr[i_njf][1]) // cycle through each entry in num_jfiles_arr
+        {
+            for (unsigned i1_njf = 0; i1_njf <= 1; i1_njf++) // cycle through the two numbers in each entry of num_jfiles_arr
+            {
+                const u_int16_t num_jfiles_0 = num_jfiles_arr[i_njf][i1_njf == 0]; // first number in pair
+                const u_int16_t num_jfiles_1 = num_jfiles_arr[i_njf][i1_njf != 0]; // second number in pair
+
+                for (unsigned i_ae = 0; i_ae < 4; i_ae++) // cycle through combinations of enabling AE
+                {
+                    const bool ae_0 = i_ae & 0x1; // first bit: enable AE on first init
+                    const bool ae_1 = i_ae & 0x2; // second bit: enable AE on second init
+                    for (unsigned i_aemjf = 0; i_aemjf < 4; i_aemjf++) // cycle through combinations of enabling/disabling ae limit
+                    {
+                        const u_int16_t ae_max_jfiles_0 = i_aemjf & 0x1 ? 3 * num_jfiles_0 : 0; // max ae files, 0 = disable max
+                        const u_int16_t ae_max_jfiles_1 = i_aemjf & 0x2 ? 4 * num_jfiles_1 : 0; // max ae files, 0 = disable max
+
+                        lpmgr lm; // DUT
+
+                        if (init_flag_0)
+                            initialize(lm, jc, num_jfiles_0, ae_0, ae_max_jfiles_0);
+                        else
+                        {
+                            prepare_recover(lfm, num_jfiles_0);
+                            recover(lfm, lm, jc, ae_1, ae_max_jfiles_0);
+                            lfm.destroy_journal();
+                        }
+
+                        if (finalize_flag) finalize(lm);
+
+                        if (init_flag_1)
+                            initialize(lm, jc, num_jfiles_1, ae_1, ae_max_jfiles_1);
+                        else
+                        {
+                            prepare_recover(lfm, num_jfiles_1);
+                            recover(lfm, lm, jc, ae_1, ae_max_jfiles_1);
+                            lfm.destroy_journal();
+                        }
+                    }
+                }
+            }
+            i_njf++;
+        }
+    }
+
+    static void check_insert(lfid_pfid_map& lfm, lpmgr& lm, test_jrnl& jc, const u_int16_t after_lfid,
+            const u_int16_t incr = 1)
+    {
+        const u_int16_t num_jfiles = lm.num_jfiles();
+        const u_int16_t ae_max_jfiles = lm.ae_max_jfiles();
+        const u_int16_t effective_ae_max_jfiles = ae_max_jfiles ? ae_max_jfiles : JRNL_MAX_NUM_FILES;
+        BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), effective_ae_max_jfiles - num_jfiles);
+        bool legal = lm.is_ae() && num_jfiles + incr <= effective_ae_max_jfiles;
+        if (legal)
+        {
+            insert(lfm, lm, jc, after_lfid, incr);
+            BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles + incr);
+            BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), effective_ae_max_jfiles - num_jfiles - incr);
+        }
+        else
+        {
+            try
+            {
+                insert(lfm, lm, jc, after_lfid, incr);
+                if (lm.is_ae())
+                    BOOST_ERROR("lpmgr::insert() succeeded and exceeded limit");
+                else
+                    BOOST_ERROR("lpmgr::insert() succeeded with auto-expand disabled");
+            }
+            catch (const jexception& e)
+            {
+                if (lm.is_ae())
+                    BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_LFMGR_AEFNUMLIMIT);
+                else
+                    BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_LFMGR_AEDISABLED);
+            }
+            BOOST_CHECK_EQUAL(lm.num_jfiles(), num_jfiles);
+            BOOST_CHECK_EQUAL(lm.ae_jfiles_rem(), effective_ae_max_jfiles - num_jfiles);
+        }
+    }
+
+    static void check_limit(lfid_pfid_map& lfm, test_jrnl& jc, const bool ae, const u_int16_t num_jfiles,
+            const u_int16_t ae_max_jfiles)
+    {
+        lpmgr lm;
+
+        for (unsigned i = 0; i < 2; i++)
+        {
+            if (i)
+                initialize(lfm, lm, jc, num_jfiles, ae, ae_max_jfiles);
+            else
+            {
+                prepare_recover(lfm, num_jfiles);
+                recover(lfm, lm, jc, ae, ae_max_jfiles);
+            }
+
+            // use up all available files
+            unsigned j = ae_max_jfiles ? ae_max_jfiles : JRNL_MAX_NUM_FILES;
+            while (ae && j > num_jfiles)
+            {
+                const u_int16_t posn = static_cast<u_int16_t>((lm.num_jfiles() - 1) * ::drand48());
+                const u_int16_t incr = 1 + static_cast<u_int16_t>((lm.ae_jfiles_rem() > 4
+                        ? 3 : lm.ae_jfiles_rem() - 1) * ::drand48());
+                check_insert(lfm, lm, jc, posn, incr);
+                j -= incr;
+            }
+            // these should be over the limit or illegal
+            check_insert(lfm, lm, jc, 0);
+            check_insert(lfm, lm, jc, 2, 2);
+            lfm.destroy_journal();
+        }
+    }
+
+private:
+    static void load_vector(const u_int16_t a[], const size_t n, flist& v)
+    {
+        for (size_t i = 0; i < n; i++)
+            v.push_back(a[i]);
+    }
+
+    static void load_vector(const flist& a, flist& b)
+    {
+        for (flist_citr i = a.begin(); i < a.end(); i++)
+            b.push_back(*i);
+    }
+
+    static void vectors_equal(const lpmgr& lm, const u_int16_t a[], const size_t n, const flist& b,
+            const bool pfid_check)
+    {
+        BOOST_CHECK_EQUAL(n, b.size());
+        for (size_t i = 0; i < n; i++)
+        {
+            BOOST_CHECK_EQUAL(a[i], b[i]);
+            fcntl* fp = lm.get_fcntlp(i);
+            BOOST_CHECK_MESSAGE(fp != (void*)0, "Unexpected void pointer returned by lpmgr::get_fcntlp()");
+            if (fp) BOOST_CHECK_EQUAL(pfid_check ? fp->pfid() : fp->lfid(), pfid_check ? a[i] : i);
+        }
+    }
+
+    static void vectors_equal(const lpmgr& lm, const flist& a, const flist& b, const bool pfid_check)
+    {
+        BOOST_CHECK_EQUAL(a.size(), b.size());
+        for (size_t i = 0; i < a.size(); i++)
+        {
+            BOOST_CHECK_EQUAL(a[i], b[i]);
+            fcntl* fp = lm.get_fcntlp(i);
+            BOOST_CHECK_MESSAGE(fp != (void*)0, "Unexpected void pointer returned by lpmgr::get_fcntlp()");
+            if (fp) BOOST_CHECK_EQUAL(pfid_check ? fp->pfid() : fp->lfid(), pfid_check ? a[i] : i);
+        }
+    }
+
+    static void linear_vectors_equal(const lpmgr& lm, const size_t n, const flist& f, const bool pfid_check)
+    {
+        BOOST_CHECK_EQUAL(n, f.size());
+        for (size_t i = 0; i < n; i++)
+        {
+            BOOST_CHECK_EQUAL(i, f[i]);
+            fcntl* fp = lm.get_fcntlp(i);
+            BOOST_CHECK_MESSAGE(fp != (void*)0, "Unexpected void pointer returned by lpmgr::get_fcntlp()");
+            if (fp) BOOST_CHECK_EQUAL(pfid_check ? fp->pfid() : fp->lfid(), i);
+        }
+    }
+};
+
+// === Tests ===
+
+#ifndef LONG_TEST
+/*
+ * ==============================================
+ *                  NORMAL TESTS
+ * This section contains normal "make check" tests
+ * for building/packaging. These are built when
+ * LONG_TEST is _not_ defined.
+ * ==============================================
+ */
+
+/*
+ * Check that after construction, the fcntl array _fcntl_arr is empty and the is_init() function returns false.
+ */
+QPID_AUTO_TEST_CASE(default_constructor)
+{
+    string test_name = get_test_name(test_filename, "default_constructor");
+    try
+    {
+        lpmgr lm;
+        BOOST_CHECK_EQUAL(lm.is_init(), false);
+        BOOST_CHECK_EQUAL(lm.is_ae(), false);
+        BOOST_CHECK_EQUAL(lm.ae_max_jfiles(), u_int16_t(0));
+        BOOST_CHECK_EQUAL(lm.num_jfiles(), u_int16_t(0));
+        BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that initialize() correctly creates an ordered fcntl array _fcntl_arr.
+ */
+QPID_AUTO_TEST_CASE(initialize)
+{
+    string test_name = get_test_name(test_filename, "initialize");
+    const u_int16_t num_jfiles = 8;
+    try
+    {
+        jdir::create_dir(test_dir); // Check test dir exists; create it if not
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        {
+            lpmgr lm;
+            lpmgr_test_helper::initialize(lm, jc, num_jfiles, false, 0);
+        }
+        {
+            lpmgr lm;
+            lpmgr_test_helper::initialize(lm, jc, num_jfiles, true, 0);
+        }
+        {
+            lpmgr lm;
+            lpmgr_test_helper::initialize(lm, jc, num_jfiles, true, 5 * num_jfiles);
+        }
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that recover() correctly sets up the specified pfid list order.
+ */
+QPID_AUTO_TEST_CASE(recover)
+{
+    string test_name = get_test_name(test_filename, "recover");
+    ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+    try
+    {
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+
+        {
+            lpmgr lm;
+            lpmgr_test_helper::prepare_recover(lfm, 8);
+            lpmgr_test_helper::recover(lfm, lm, jc, false, 0);
+            lfm.destroy_journal();
+        }
+        {
+            lpmgr lm;
+            lpmgr_test_helper::prepare_recover(lfm, 8);
+            lpmgr_test_helper::recover(lfm, lm, jc, true, 0);
+            lfm.destroy_journal();
+        }
+        {
+            lpmgr lm;
+            lpmgr_test_helper::prepare_recover(lfm, 8);
+            lpmgr_test_helper::recover(lfm, lm, jc, true, 5 * lfm.size());
+            lfm.destroy_journal();
+        }
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that finalize() after an initialize() empties _fcntl_arr and that afterwards is_init() returns false.
+ */
+QPID_AUTO_TEST_CASE(initialize_finalize)
+{
+    string test_name = get_test_name(test_filename, "initialize_finalize");
+    const u_int16_t num_jfiles = 8;
+    try
+    {
+        jdir::create_dir(test_dir); // Check test dir exists; create it if not
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        {
+            lpmgr lm;
+            lpmgr_test_helper::initialize(lm, jc, num_jfiles, false, 0);
+            lpmgr_test_helper::finalize(lm);
+        }
+        {
+            lpmgr lm;
+            lpmgr_test_helper::initialize(lm, jc, num_jfiles, true, 0);
+            lpmgr_test_helper::finalize(lm);
+        }
+        {
+            lpmgr lm;
+            lpmgr_test_helper::initialize(lm, jc, num_jfiles, true, 5 * num_jfiles);
+            lpmgr_test_helper::finalize(lm);
+        }
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that finalize() after a recover() empties _fcntl_arr and that afterwards is_init() returns false.
+ */
+QPID_AUTO_TEST_CASE(recover_finalize)
+{
+    string test_name = get_test_name(test_filename, "recover_finalize");
+    const u_int16_t num_jfiles = 8;
+    ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+    try
+    {
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+
+        {
+            lpmgr lm;
+            lpmgr_test_helper::prepare_recover(lfm, num_jfiles);
+            lpmgr_test_helper::recover(lfm, lm, jc, false, 0);
+            lpmgr_test_helper::finalize(lm);
+            lfm.destroy_journal();
+        }
+        {
+            lpmgr lm;
+            lpmgr_test_helper::prepare_recover(lfm, num_jfiles);
+            lpmgr_test_helper::recover(lfm, lm, jc, true, 0);
+            lpmgr_test_helper::finalize(lm);
+            lfm.destroy_journal();
+        }
+        {
+            lpmgr lm;
+            lpmgr_test_helper::prepare_recover(lfm, num_jfiles);
+            lpmgr_test_helper::recover(lfm, lm, jc, true, 5 * lfm.size());
+            lpmgr_test_helper::finalize(lm);
+            lfm.destroy_journal();
+        }
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that 0 and/or null and other extreme/boundary parameters behave as expected.
+ */
+QPID_AUTO_TEST_CASE(zero_null_params)
+{
+    string test_name = get_test_name(test_filename, "zero_null_params");
+    const u_int16_t num_jfiles = 8;
+    try
+    {
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+        lpmgr lm;
+        lpmgr_test_helper::initialize(lfm, lm, jc, num_jfiles, true, 0);
+
+        // Check that inserting 0 files works ok
+        lpmgr_test_helper::insert(lfm, lm, jc, 0, 0);
+        lpmgr_test_helper::insert(lfm, lm, jc, 2, 0);
+        lpmgr_test_helper::insert(lfm, lm, jc, num_jfiles - 1, 0);
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that initialize()/recover() works correctly after a previous initialize()/recover() with/without an intervening
+ * finalize().
+ */
+QPID_AUTO_TEST_CASE(multiple_initialization_recover)
+{
+    string test_name = get_test_name(test_filename, "multiple_initialization_recover");
+    ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+
+    // Set combinations of value pairs to be used for number of journal files in first and second init
+    u_int16_t num_jfiles_arr[][2] = {{8, 12}, {4, 7}, {0, 0}}; // end with zeros
+    try
+    {
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+        for (unsigned p = 0; p < 8; p++)
+        {
+            const bool i_0 = p & 0x01; // first bit
+            const bool i_1 = p & 0x02; // second bit
+            const bool f = p & 0x04;   // third bit
+            lpmgr_test_helper::check_multiple_initialization_recover(lfm, jc, num_jfiles_arr, i_0, f, i_1);
+        }
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that insert() works correctly after initialize() and shifts the pfid sequence beyond the insert point correctly:
+ *
+ * The following sequence is tested:
+ * initialize 4            pfids=[0,1,2,3]           lfids=[0,1,2,3]
+ * insert 1 after lfid 0   pfids=[0,4,1,2,3]         lfids=[0,2,3,4,1]
+ * insert 2 after lfid 2   pfids=[0,4,1,5,6,2,3]     lfids=[0,2,5,6,1,3,4]
+ * insert 1 after lfid 6   pfids=[0,4,1,5,6,2,3,7]   lfids=[0,2,5,6,1,3,4,7]
+ * issert 1 after lfid 3   pfids=[0,4,1,5,8,6,2,3,7] lfids=[0,2,6,7,1,3,5,8,4]
+ */
+QPID_AUTO_TEST_CASE(initialize_insert)
+{
+    string test_name = get_test_name(test_filename, "initialize_insert");
+    const u_int16_t initial_num_jfiles = 8;
+    try
+    {
+        jdir::create_dir(test_dir); // Check test dir exists; create it if not
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+        lpmgr lm;
+        lpmgr_test_helper::initialize(lfm, lm, jc, initial_num_jfiles, true, 0);
+
+        lpmgr_test_helper::insert(lfm, lm, jc, 0);
+        lpmgr_test_helper::insert(lfm, lm, jc, 2, 2);
+        lpmgr_test_helper::insert(lfm, lm, jc, 6);
+        lpmgr_test_helper::insert(lfm, lm, jc, 3);
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that insert() works correctly after recover() and shifts the pfid sequence beyond the insert point correctly:
+ *
+ * The following sequence is tested:
+ * recover 4               pfids=[0,2,3,1]           lfids=[0,3,1,2]
+ * insert 1 after lfid 0   pfids=[0,4,2,3,1]         lfids=[0,4,2,3,1]
+ * insert 2 after lfid 2   pfids=[0,4,2,5,6,3,1]     lfids=[0,6,2,5,1,3,4]
+ * insert 1 after lfid 6   pfids=[0,4,2,5,6,3,1,7]   lfids=[0,6,2,5,1,3,4,7]
+ * issert 1 after lfid 3   pfids=[0,4,2,5,8,6,3,1,7] lfids=[0,7,2,6,1,3,5,8,4]
+ */
+QPID_AUTO_TEST_CASE(recover_insert)
+{
+    string test_name = get_test_name(test_filename, "recover_insert");
+    const u_int16_t initial_num_jfiles = 4;
+    ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+    try
+    {
+        jdir::create_dir(test_dir); // Check test dir exists; create it if not
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+        lpmgr lm;
+        lpmgr_test_helper::prepare_recover(lfm, initial_num_jfiles);
+        lpmgr_test_helper::recover(lfm, lm, jc, true, 0);
+
+        lpmgr_test_helper::insert(lfm, lm, jc, 0);
+        lpmgr_test_helper::insert(lfm, lm, jc, 2, 2);
+        lpmgr_test_helper::insert(lfm, lm, jc, 6);
+        lpmgr_test_helper::insert(lfm, lm, jc, 3);
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that illegal ae parameter combinations are caught and result in an exception being thrown.
+ */
+QPID_AUTO_TEST_CASE(ae_parameters)
+{
+    string test_name = get_test_name(test_filename, "ae_parameters");
+    ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+    try
+    {
+        jdir::create_dir(test_dir); // Check test dir exists; create it if not
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+        const u_int16_t num_jfiles = 8;
+        lpmgr lm;
+
+        for (unsigned i = 0; i < 2; i++)
+        {
+            if (i)
+                lpmgr_test_helper::initialize(lfm, lm, jc, num_jfiles, false, 0);
+            else
+            {
+                lpmgr_test_helper::prepare_recover(lfm, num_jfiles);
+                lpmgr_test_helper::recover(lfm, lm, jc, false, 0);
+            }
+
+            lpmgr_test_helper::check_ae_max_jfiles(lm, num_jfiles, num_jfiles - 2);
+            lpmgr_test_helper::check_ae_max_jfiles(lm, num_jfiles, 0);
+            lpmgr_test_helper::check_ae_max_jfiles(lm, num_jfiles, 2 * num_jfiles);
+            lpmgr_test_helper::check_ae_max_jfiles(lm, num_jfiles, num_jfiles);
+            lfm.destroy_journal();
+        }
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that initialized or recovered journals with auto-expand disabled will not allow either inserts or appends.
+ */
+QPID_AUTO_TEST_CASE(ae_disabled)
+{
+    string test_name = get_test_name(test_filename, "ae_disabled");
+    ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+    try
+    {
+        jdir::create_dir(test_dir); // Check test dir exists; create it if not
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+        lpmgr_test_helper::check_limit(lfm, jc, false, 8, 0);
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that initialized or recovered journals with auto-expand enabled and a file limit set will enforce the correct
+ * limits on inserts and appends.
+ */
+QPID_AUTO_TEST_CASE(ae_enabled_limit)
+{
+    string test_name = get_test_name(test_filename, "ae_enabled_limit");
+    ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+    try
+    {
+        jdir::create_dir(test_dir); // Check test dir exists; create it if not
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+        lpmgr_test_helper::check_limit(lfm, jc, true, 8, 32);
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+/*
+ * Check that initialized or recovered journals with auto-expand enabled and no file limit set (0) will allow inserts and
+ * appends up to the file limit JRNL_MAX_NUM_FILES.
+ */
+QPID_AUTO_TEST_CASE(ae_enabled_unlimited)
+{
+    string test_name = get_test_name(test_filename, "ae_enabled_unlimited");
+    ::srand48(1); // init random gen for repeatable tests when using lpmgr_test_helper::prepare_recover()
+    try
+    {
+        jdir::create_dir(test_dir); // Check test dir exists; create it if not
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lfid_pfid_map lfm(test_name, test_name);
+        lpmgr_test_helper::check_limit(lfm, jc, true, 8, 0);
+    }
+    catch(const exception& e) { BOOST_FAIL(e.what()); }
+    cout << "done" << endl;
+}
+
+#else
+/*
+ * ==============================================
+ *                  LONG TESTS
+ * This section contains long tests and soak tests,
+ * and are run using target check-long (ie "make
+ * check-long"). These are built when LONG_TEST is
+ * defined.
+ * ==============================================
+ */
+
+/*
+ * Tests randomized combinations of initialization/recovery, initial size, number, size and location of inserts.
+ *
+ * To reproduce a specific test, comment out the get_seed() statement and uncomment the literal below, adjusting the seed
+ * value to that required.
+ */
+QPID_AUTO_TEST_CASE(randomized_tests)
+{
+    string test_name = get_test_name(test_filename, "randomized_tests");
+    const long seed = get_seed();
+    // const long seed = 0x2d9b69d32;
+    cout << "seed=0x" << hex << seed << dec << " " << flush;
+    ::srand48(seed);
+
+    lfid_pfid_map lfm(test_name, test_name);
+    flist pfidl;
+    flist lfidl;
+    rcvdat rd;
+    u_int16_t curr_ae_max_jfiles = 0;
+    jdir::create_dir(test_dir); // Check test dir exists; create it if not
+
+    for (int test_num = 0; test_num < 250; test_num++)
+    {
+        test_jrnl_cb cb;
+        test_jrnl jc(test_name, test_dir, test_name, cb);
+        lpmgr lm;
+        // 50% chance of recovery except first run and if there is still ae space left
+        const bool recover_flag = test_num > 0 &&
+                                  curr_ae_max_jfiles > lfm.size() &&
+                                  2.0 * ::drand48() < 1.0;
+        if (recover_flag)
+        {
+            // Recover from previous iteration
+            lfm.get_pfid_list(pfidl);
+            lfm.get_lfid_list(lfidl);
+            lfm.write_journal(true, curr_ae_max_jfiles, JFSIZE_SBLKS);
+            lpmgr_test_helper::rcvdat_init(rd, pfidl, true, curr_ae_max_jfiles);
+            lm.recover(rd, &jc, &jc.new_fcntl);
+            lpmgr_test_helper::check_pfids_lfids(lm, pfidl, lfidl);
+        }
+        else
+        {
+            // Initialize from scratch
+            const u_int16_t num_jfiles = 4 + u_int16_t(21.0 * ::drand48()); // size: 4 - 25 files
+            curr_ae_max_jfiles = u_int16_t(4 * num_jfiles * ::drand48()); // size: 0 - 100 files
+            if (curr_ae_max_jfiles > JRNL_MAX_NUM_FILES) curr_ae_max_jfiles = JRNL_MAX_NUM_FILES;
+            else if (curr_ae_max_jfiles <= num_jfiles) curr_ae_max_jfiles = 0;
+            lfm.destroy_journal();
+            lfm.journal_create(num_jfiles, num_jfiles);
+            lfm.get_pfid_list(pfidl);
+            lfm.get_lfid_list(lfidl);
+            lm.initialize(num_jfiles, true, curr_ae_max_jfiles, &jc, &jc.new_fcntl);
+            lpmgr_test_helper::check_linear_pfids_lfids(lm, num_jfiles);
+        }
+
+        // Loop to insert pfids
+        const int num_inserts = 1 + int(lfm.size() * ::drand48());
+        for (int i = 0; i < num_inserts; i++)
+        {
+            const u_int16_t size = lm.num_jfiles();
+            const u_int16_t after_lfid = u_int16_t(1.0 * size * ::drand48());
+            const u_int16_t num_jfiles = 1 + u_int16_t(4.0 * ::drand48());
+            const bool legal = lm.ae_max_jfiles()
+                               ? size + num_jfiles <= lm.ae_max_jfiles()
+                               : size + num_jfiles <= JRNL_MAX_NUM_FILES;
+            if (legal)
+            {
+                lfm.journal_insert(after_lfid, num_jfiles);
+                lfm.get_pfid_list(pfidl);
+                lfm.get_lfid_list(lfidl);
+
+                lm.insert(after_lfid, &jc, &jc.new_fcntl, num_jfiles);
+                lpmgr_test_helper::check_pfids_lfids(lm, pfidl, lfidl);
+            }
+            else
+            {
+                try
+                {
+                    lm.insert(after_lfid, &jc, &jc.new_fcntl, num_jfiles);
+                    BOOST_FAIL("lpmgr::insert() succeeded and exceeded limit");
+                }
+                catch (const jexception& e)
+                {
+                    BOOST_CHECK_EQUAL(e.err_code(), jerrno::JERR_LFMGR_AEFNUMLIMIT);
+                    break; // no more inserts...
+                }
+            }
+        }
+        lm.finalize();
+        BOOST_CHECK_EQUAL(lm.is_init(), false);
+        BOOST_CHECK_EQUAL(lm.num_jfiles(), u_int16_t(0));
+        BOOST_CHECK_EQUAL(lm.get_fcntlp(0), (void*)0);
+    }
+    cout << "done" << endl;
+}
+
+#endif
+
+QPID_AUTO_TEST_SUITE_END()



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org