libmoost
/home/mhx/git/github/libmoost/test/io/async_writer.cpp
Go to the documentation of this file.
00001 /* vim:set ts=3 sw=3 sts=3 et: */
00028 #include <boost/test/unit_test.hpp>
00029 #include <boost/test/test_tools.hpp>
00030 
00031 #include <vector>
00032 #include <istream>
00033 #include <ostream>
00034 #include <fstream>
00035 
00036 #include <boost/filesystem/path.hpp>
00037 #include <boost/filesystem/operations.hpp>
00038 
00039 #include "../../include/moost/thread/xtime_util.hpp"
00040 #include "../../include/moost/io/async_writer.hpp"
00041 
00042 #ifdef _WIN32
00043    #define gmtime_r( _clock, _result ) \
00044       ( *(_result) = *gmtime( (_clock) ), \
00045       (_result) )
00046 #endif
00047 
00048 using namespace boost::filesystem;
00049 using namespace moost::thread;
00050 using namespace moost::io;
00051 
00052 BOOST_AUTO_TEST_SUITE( async_writer_test )
00053 
00054 struct Item
00055 {
00056   int x;
00057 
00058   void read(std::istream & in)
00059   {
00060     in.read(reinterpret_cast<char *>(&x), sizeof(x));
00061   }
00062 
00063   void write(std::ostream & out)
00064   {
00065     out.write(reinterpret_cast<const char *>(&x), sizeof(x));
00066   }
00067 };
00068 
00069 struct Fixture
00070 {
00071   struct TempDirectory
00072   {
00073     path Path;
00074     TempDirectory(const std::string & path_name) : Path(path_name) { create_directory(Path); }
00075     ~TempDirectory() { remove_all(Path); }
00076   };
00077   TempDirectory temp_dir;
00078   async_writer<Item> aw_simple;
00079   async_writer<Item> aw_roll;
00080   Item item;
00081 
00082   Fixture()
00083   : temp_dir("async_writer_test"),
00084     aw_simple((temp_dir.Path / "simple").string()),
00085     aw_roll((temp_dir.Path / "roll").string(), count_rollover(3))
00086   {
00087     item.x = 22;
00088   }
00089   ~Fixture()
00090   {
00091   }
00092 
00093   void sleep(int seconds)
00094   {
00095     boost::thread::sleep(xtime_util::add_sec(xtime_util::now(), seconds));
00096   }
00097 };
00098 
00099 // what happens when we do nothing?
00100 BOOST_FIXTURE_TEST_CASE( test_nothing, Fixture )
00101 {
00102    aw_simple.stop();
00103    aw_roll.stop();
00104 
00105    directory_iterator end_it; // default construction yields past-the-end
00106 
00107    for (directory_iterator it( temp_dir.Path ); it != end_it; ++it )
00108    {
00109      BOOST_CHECK(false);
00110    }
00111 }
00112 
00113 // what happens when we write something
00114 BOOST_FIXTURE_TEST_CASE( test_something, Fixture )
00115 {
00116   aw_simple.enqueue(item);
00117   aw_simple.stop();
00118 
00119   directory_iterator it( temp_dir.Path );
00120   BOOST_REQUIRE(it != directory_iterator());
00121 
00122   std::ifstream in(it->string().c_str(), std::ios::binary);
00123   Item item2;
00124   item2.read(in);
00125   BOOST_CHECK_EQUAL(item2.x, item.x);
00126   BOOST_CHECK(++it == directory_iterator());
00127 }
00128 
00129 // what happens when we stop and then start?
00130 BOOST_FIXTURE_TEST_CASE( test_stopstart, Fixture )
00131 {
00132   aw_simple.enqueue(item);
00133   aw_simple.stop();
00134 
00135   aw_simple.start();
00136   aw_simple.enqueue(item);
00137   aw_simple.stop();
00138 
00139   directory_iterator it( temp_dir.Path );
00140   BOOST_REQUIRE(it != directory_iterator());
00141 
00142   std::ifstream in(it->string().c_str(), std::ios::binary);
00143 
00144   Item item2;
00145   item2.read(in);
00146   BOOST_CHECK_EQUAL(item2.x, item.x);
00147 
00148   BOOST_REQUIRE(++it != directory_iterator());
00149 
00150   in.close();
00151   in.clear();
00152   in.open(it->string().c_str(), std::ios::binary);
00153   item2.x = 0;
00154   item2.read(in);
00155   BOOST_CHECK_EQUAL(item2.x, item.x);
00156   BOOST_REQUIRE(++it == directory_iterator());
00157 }
00158 
00159 // can we force a rollover
00160 BOOST_FIXTURE_TEST_CASE( test_rollover, Fixture )
00161 {
00162   for (int i = 0; i != 4; ++i)
00163     aw_roll.enqueue(item);
00164 
00165   aw_roll.stop();
00166 
00167   // we should have two files, one should have 1000, the other 1
00168   int first_file_count = 0;
00169   int second_file_count = 0;
00170 
00171   directory_iterator it( temp_dir.Path );
00172   BOOST_REQUIRE(it != directory_iterator());
00173 
00174   std::ifstream in(it->string().c_str(), std::ios::binary);
00175   Item item2;
00176   for ( ;in.is_open(); )
00177   {
00178     item2.read(in);
00179     if (in.eof())
00180       break;
00181     ++first_file_count;
00182   }
00183   in.close(); in.clear();
00184 
00185   BOOST_REQUIRE(++it != directory_iterator());
00186   in.open(it->string().c_str(), std::ios::binary);
00187   for ( ;in.is_open(); )
00188   {
00189     item2.read(in);
00190     if (in.eof())
00191       break;
00192     ++second_file_count;
00193   }
00194 
00195   BOOST_CHECK(++it == directory_iterator());
00196   BOOST_CHECK((first_file_count == 3 && second_file_count == 1) || (first_file_count == 1 && second_file_count == 3));
00197 }
00198 
00199 // how about timeofday rollover
00200 BOOST_FIXTURE_TEST_CASE( test_timeofday_rollover, Fixture )
00201 {
00202   struct tm time_info;
00203   time_t now;
00204   time(&now);
00205   gmtime_r(&now, &time_info);
00206   async_writer<Item, timeofday_rollover> aw_timeofday_roll((temp_dir.Path / "roll").string(),
00207       timeofday_rollover(time_info.tm_hour, time_info.tm_min, time_info.tm_sec + 2));
00208   aw_timeofday_roll.enqueue(item);
00209   sleep(3);
00210   aw_timeofday_roll.enqueue(item);
00211   aw_timeofday_roll.stop();
00212 
00213   directory_iterator it( temp_dir.Path );
00214   BOOST_REQUIRE(it != directory_iterator());
00215 
00216   std::ifstream in(it->string().c_str(), std::ios::binary);
00217 
00218   Item item2;
00219   item2.read(in);
00220   BOOST_CHECK_EQUAL(item2.x, item.x);
00221 
00222   BOOST_REQUIRE(++it != directory_iterator());
00223 
00224   in.close();
00225   in.clear();
00226   in.open(it->string().c_str(), std::ios::binary);
00227   item2.x = 0;
00228   item2.read(in);
00229   BOOST_CHECK_EQUAL(item2.x, item.x);
00230   BOOST_REQUIRE(++it == directory_iterator());
00231 }
00232 
00233 BOOST_AUTO_TEST_SUITE_END()