diff options
author | stanleyk <stanleyk@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2013-02-05 21:11:03 +0000 |
---|---|---|
committer | stanleyk <stanleyk@ae88bc3d-4319-0410-8dbf-d08b4c9d3795> | 2013-02-05 21:11:03 +0000 |
commit | 5e030faf84086ab02059fcbcc3faed224bd57b95 (patch) | |
tree | 3a62df45ac6ccf599fb07cf6a03d672456ce2e3d /TAO/tests/Storable | |
parent | 9d296f7fa51116ff7040ecb2ad18612cd94b5fd1 (diff) | |
download | ATCD-5e030faf84086ab02059fcbcc3faed224bd57b95.tar.gz |
Merge in OCI_Reliability_Enhancements branch.
Diffstat (limited to 'TAO/tests/Storable')
-rw-r--r-- | TAO/tests/Storable/README | 14 | ||||
-rw-r--r-- | TAO/tests/Storable/Savable.cpp | 228 | ||||
-rw-r--r-- | TAO/tests/Storable/Savable.h | 61 | ||||
-rw-r--r-- | TAO/tests/Storable/Storable.mpc | 6 | ||||
-rw-r--r-- | TAO/tests/Storable/data_files/bad_binary.dat | 6 | ||||
-rw-r--r-- | TAO/tests/Storable/data_files/bad_int.dat | 3 | ||||
-rw-r--r-- | TAO/tests/Storable/data_files/bad_string.dat | 2 | ||||
-rw-r--r-- | TAO/tests/Storable/data_files/bad_unsigned_int.dat | 4 | ||||
-rw-r--r-- | TAO/tests/Storable/data_files/good.dat | 11 | ||||
-rwxr-xr-x | TAO/tests/Storable/run_test.pl | 156 | ||||
-rw-r--r-- | TAO/tests/Storable/test.cpp | 188 |
11 files changed, 679 insertions, 0 deletions
diff --git a/TAO/tests/Storable/README b/TAO/tests/Storable/README new file mode 100644 index 00000000000..b5086ded191 --- /dev/null +++ b/TAO/tests/Storable/README @@ -0,0 +1,14 @@ +$Id$ + +This test verifies that TAO::Storable_FlatFileStream along +with TAO::Storable_File_Guard can be used to save/restore +the state of an object (an instance of Savable) to the +file system. To verifing Storable_File_Guard's file locking, +two processes that read/write from the persistent store run +in parallel. + +Note that this test does not explicitly validate the code in +Storable_File_Guard that deals with the persistent store +being obsolete. + + diff --git a/TAO/tests/Storable/Savable.cpp b/TAO/tests/Storable/Savable.cpp new file mode 100644 index 00000000000..6ec1318a6ae --- /dev/null +++ b/TAO/tests/Storable/Savable.cpp @@ -0,0 +1,228 @@ +// $Id$ + +#include "Savable.h" +#include "tao/Storable_Base.h" +#include "tao/Storable_Factory.h" +#include "tao/Storable_File_Guard.h" + +const int Savable::bytes_size_max = 128; + +class Savable_File_Guard: public TAO::Storable_File_Guard +{ +public: + + Savable_File_Guard (Savable & savable, Method_Type method_type); + + ~Savable_File_Guard (); + + virtual void set_object_last_changed (const time_t & time); + + virtual time_t get_object_last_changed (); + + virtual void load_from_stream (); + + virtual bool is_loaded_from_stream (); + + virtual TAO::Storable_Base * create_stream (const char * mode); + +private: + Savable & savable_; +}; + +Savable_File_Guard::Savable_File_Guard (Savable & savable, + Method_Type method_type) + : TAO::Storable_File_Guard(false) + , savable_(savable) +{ + try + { + this->init(method_type); + } + catch (TAO::Storable_Read_Exception &) + { + throw Savable_Exception(); + } +} + +Savable_File_Guard::~Savable_File_Guard () +{ + this->release (); +} + +void +Savable_File_Guard::set_object_last_changed (const time_t & time) +{ + savable_.last_changed_ = time; +} + +time_t +Savable_File_Guard::get_object_last_changed () +{ + return savable_.last_changed_; +} + +void +Savable_File_Guard::load_from_stream () +{ + savable_.read (this->peer ()); + savable_.loaded_from_stream_ = true; + this->peer ().rewind (); +} + +bool +Savable_File_Guard::is_loaded_from_stream () +{ + return savable_.loaded_from_stream_; +} + +TAO::Storable_Base * +Savable_File_Guard::create_stream (const char * mode) +{ + return savable_.storable_factory_.create_stream ("test.dat", mode); +} + +typedef TAO::Storable_File_Guard SFG; + +Savable::Savable (TAO::Storable_Factory & storable_factory) + : storable_factory_(storable_factory) + , loaded_from_stream_ (false) +{ + + for (int index = 0; index < 2; ++index) + { + this->i_[index] = 0; + this->ui_[index] = 0; + this->bytes_size_[index] = 0; + this->bytes_[index] = new char [this->bytes_size_max]; + for (int i = 0; i < this->bytes_size_max; ++i) + { + this->bytes_[index][i] = ACE_CHAR_MAX; + } + } + + ACE_Auto_Ptr<TAO::Storable_Base> + stream (storable_factory_.create_stream("test.dat", "r")); + if (stream->exists ()) + { + Savable_File_Guard fg(*this, SFG::CREATE_WITH_FILE); + } + else + { + Savable_File_Guard fg(*this, SFG::CREATE_WITHOUT_FILE); + this->write (fg.peer ()); + } +} + +Savable::~Savable () +{ + for (int index = 0; index < 2; ++index) + { + delete []this->bytes_[index]; + } +} + +bool +Savable::is_loaded_from_stream () +{ + return this->loaded_from_stream_; +} + +void +Savable::read (TAO::Storable_Base & stream) +{ + stream.rewind (); + + for (int index = 0; index < 2; ++index) + { + stream >> this->string_[index]; + stream >> this->i_[index]; + stream >> this->ui_[index]; + stream >> this->bytes_size_[index]; + stream.read (this->bytes_size_[index], this->bytes_[index]); + } +} + +void +Savable::write (TAO::Storable_Base & stream) +{ + stream.rewind (); + + for (int index = 0; index < 2; ++index) + { + stream << this->string_[index]; + stream << this->i_[index]; + stream << this->ui_[index]; + stream << this->bytes_size_[index]; + stream.write (this->bytes_size_[index], this->bytes_[index]); + } + + stream.flush (); +} + +void +Savable::string_set (int index, const ACE_CString &s) +{ + Savable_File_Guard fg(*this, SFG::MUTATOR); + this->string_[index] = s; + this->write (fg.peer ()); +} + +const ACE_CString & +Savable::string_get (int index) +{ + Savable_File_Guard fg(*this, SFG::ACCESSOR); + return this->string_[index]; +} + +void +Savable::int_set (int index, int i) +{ + Savable_File_Guard fg(*this, SFG::MUTATOR); + this->i_[index] = i; + this->write (fg.peer ()); +} + +int +Savable::int_get (int index) +{ + Savable_File_Guard fg(*this, SFG::ACCESSOR); + return this->i_[index]; +} + +void +Savable::unsigned_int_set (int index, unsigned int ui) +{ + Savable_File_Guard fg(*this, SFG::MUTATOR); + this->ui_[index] = ui; + this->write (fg.peer ()); +} + +unsigned int +Savable::unsigned_int_get (int index) +{ + Savable_File_Guard fg(*this, SFG::ACCESSOR); + return this->ui_[index]; +} + +void +Savable::bytes_set (int index, int size, char * bytes) +{ + Savable_File_Guard fg(*this, SFG::MUTATOR); + this->bytes_size_[index] = size; + for (int i = 0; i < this->bytes_size_[index]; ++i) + { + this->bytes_[index][i] = bytes[i]; + } + this->write (fg.peer ()); +} + +int +Savable::bytes_get (int index, char * bytes) +{ + Savable_File_Guard fg(*this, SFG::ACCESSOR); + for (int i = 0; i < this->bytes_size_[index]; ++i) + { + bytes[i] = this->bytes_[index][i]; + } + return this->bytes_size_[index]; +} diff --git a/TAO/tests/Storable/Savable.h b/TAO/tests/Storable/Savable.h new file mode 100644 index 00000000000..c227e90639e --- /dev/null +++ b/TAO/tests/Storable/Savable.h @@ -0,0 +1,61 @@ +// $Id$ + +#include "tao/Storable_Base.h" + +#include "ace/SString.h" + +namespace TAO +{ + class Storable_Factory; +} + +class Savable_Exception +{ +}; + +/// A simple class to use for testing whose contents +/// are to be persisted. It has attributes for each basic +/// type that can be saved. +/// There are two attributes for each type so that +/// one process can write one attribute of the same +/// type while another process reads another attribute +/// of the same type. +class Savable +{ + public: + Savable (TAO::Storable_Factory & storable_factory); + + ~Savable (); + + void string_set (int index, const ACE_CString &s); + const ACE_CString & string_get (int index); + + void int_set (int index, int i); + int int_get (int index); + + void unsigned_int_set (int index, unsigned int ui); + unsigned int unsigned_int_get (int index); + + void bytes_set (int index, int size, char * bytes); + int bytes_get (int index, char * bytes); + + bool is_loaded_from_stream (); + + private: + TAO::Storable_Factory & storable_factory_; + bool loaded_from_stream_; + time_t last_changed_; + void read (TAO::Storable_Base & stream); + void write (TAO::Storable_Base & stream); + + ACE_CString string_[2]; + int i_[2]; + unsigned int ui_[2]; + + static const int bytes_size_max; + int bytes_size_[2]; + char * bytes_[2]; + + friend class Savable_File_Guard; +}; + diff --git a/TAO/tests/Storable/Storable.mpc b/TAO/tests/Storable/Storable.mpc new file mode 100644 index 00000000000..8dc0de72161 --- /dev/null +++ b/TAO/tests/Storable/Storable.mpc @@ -0,0 +1,6 @@ +// -*- MPC -*- +// $Id$ + +project : taoclient { + exename = test +} diff --git a/TAO/tests/Storable/data_files/bad_binary.dat b/TAO/tests/Storable/data_files/bad_binary.dat new file mode 100644 index 00000000000..eda0d4e6b50 --- /dev/null +++ b/TAO/tests/Storable/data_files/bad_binary.dat @@ -0,0 +1,6 @@ +11 +test_string +-100 +100 +8 +
\ No newline at end of file diff --git a/TAO/tests/Storable/data_files/bad_int.dat b/TAO/tests/Storable/data_files/bad_int.dat new file mode 100644 index 00000000000..19e69d4a464 --- /dev/null +++ b/TAO/tests/Storable/data_files/bad_int.dat @@ -0,0 +1,3 @@ +11 +test_string +-10
\ No newline at end of file diff --git a/TAO/tests/Storable/data_files/bad_string.dat b/TAO/tests/Storable/data_files/bad_string.dat new file mode 100644 index 00000000000..0519db270cc --- /dev/null +++ b/TAO/tests/Storable/data_files/bad_string.dat @@ -0,0 +1,2 @@ +11 +test_st
\ No newline at end of file diff --git a/TAO/tests/Storable/data_files/bad_unsigned_int.dat b/TAO/tests/Storable/data_files/bad_unsigned_int.dat new file mode 100644 index 00000000000..c3dcc1cdc45 --- /dev/null +++ b/TAO/tests/Storable/data_files/bad_unsigned_int.dat @@ -0,0 +1,4 @@ +11 +test_string +-100 +10
\ No newline at end of file diff --git a/TAO/tests/Storable/data_files/good.dat b/TAO/tests/Storable/data_files/good.dat new file mode 100644 index 00000000000..a34d7bdac3e --- /dev/null +++ b/TAO/tests/Storable/data_files/good.dat @@ -0,0 +1,11 @@ +11 +test_string +-100 +100 +8 + 11 +test_string +-100 +100 +8 +
\ No newline at end of file diff --git a/TAO/tests/Storable/run_test.pl b/TAO/tests/Storable/run_test.pl new file mode 100755 index 00000000000..10d340d34e6 --- /dev/null +++ b/TAO/tests/Storable/run_test.pl @@ -0,0 +1,156 @@ +eval '(exit $?0)' && eval 'exec perl -S $0 ${1+"$@"}' + & eval 'exec perl -S $0 $argv:q' + if 0; + +# $Id$ +# -*- perl -*- + +use lib "$ENV{ACE_ROOT}/bin"; +use PerlACE::TestTarget; +use File::Copy; + +my $status = 0; + +my $test1 = PerlACE::TestTarget::create_target (1) || die "Create target 1 failed\n"; + +my $stdout_file = "test.out"; +my $stderr_file = "test.err"; +my $test_stdout_file = $test1->LocalFile ($stdout_file); +my $test_stderr_file = $test1->LocalFile ($stderr_file); + +sub cat_file($) +{ + my $file_name = shift; + if (-s $file_name ) # size of file is greater than zero + { + open TESTFILE, $file_name or die "Couldn't open file: $!"; + my @teststring = <TESTFILE>; # read in all of the file + print STDERR "\n@teststring\n"; + close TESTFILE; + } +} + +sub redirect_output() +{ + open (OLDOUT, ">&", \*STDOUT) or die "Can't dup STDOUT: $!"; + open (OLDERR, ">&", \*STDERR) or die "Can't dup STDERR: $!"; + open STDERR, '>', $test_stderr_file; + open STDOUT, '>', $test_stdout_file; +} + +sub restore_output() +{ + open (STDERR, ">&OLDERR") or die "Can't dup OLDERR: $!"; + open (STDOUT, ">&OLDOUT") or die "Can't dup OLDOUT: $!"; +} + + +my $persistent_file = "test.dat"; +$test1->DeleteFile ($persistent_file); + +my $num_loops = 5; +my $loop_sleep_msec = 200; + +if ($#ARGV >= 0) { + for (my $i = 0; $i <= $#ARGV; $i++) { + if ($ARGV[$i] eq '-num_loops') { + $i++; + $num_loops = $ARGV[$i]; + } + elsif ($ARGV[$i] eq "-loop_sleep") { + $i++; + $loop_sleep_msec = $ARGV[$i]; + } + else { + print "Usage: run_test.pl ". + "[-num_loops <num=$num_loops>] ". + "[-loop_sleep <msec=$loop_sleep_msec>]\n"; + exit 1; + } + } +} + +$T1 = $test1->CreateProcess ("test", "-i 0 -n $num_loops"); + +my $test2 = PerlACE::TestTarget::create_target (2) || die "Create target 1 failed\n"; + +$T2 = $test2->CreateProcess ("test", "-i 1 -n $num_loops -s $loop_sleep_msec"); + +$test1_status = $T1->Spawn (); + +if ($test1_status != 0) { + print STDERR "ERROR: test 1 returned $test1_status\n"; + $status = 1; +} + +$test2_status = $T2->SpawnWaitKill ($test2->ProcessStartWaitInterval()); + +if ($test2_status != 0) { + print STDERR "ERROR: test 2 returned $test2_status\n"; + $status = 1; +} + +$test1_status = $T1->WaitKill ($test1->ProcessStopWaitInterval()); + +if ($test1_status != 0) { + print STDERR "ERROR: test 1 returned $test1_status\n"; + $status = 1; +} + +$test1->DeleteFile ($persistent_file); + +sub test_backup_recovery($) +{ + my $bad_file = shift; + + my $status = 0; + + print STDERR "Testing recovery of backup file for $bad_file.\n"; + + my $backup_file = "test.dat.bak"; + copy($bad_file, "test.dat") or die "Copy failed: $!"; + copy("data_files/good.dat", $backup_file) or die "Copy failed: $!"; + + $T = $test1->CreateProcess ("test", "-b"); + # Redirect output so that expected error messages are not interpreted as + # test failure and rely instead of return status. + redirect_output(); + my $test_status = $T->SpawnWaitKill ($test1->ProcessStartWaitInterval()); + restore_output(); + if ($test_status != 0) { + $status = 1; + print STDERR "ERROR: Backup recovery test using $bad_file failed\n"; + cat_file($test_stderr_file); + cat_file($test_stdout_file); + } + else { + print STDERR "Recovery successful\n"; + } + + if (-e $backup_file) { + $test1->DeleteFile ($backup_file); + } + else { + $status = 1; + print STDERR "ERROR: Backup file was not created\n"; + } + $test1->DeleteFile ($persistent_file); + $test1->DeleteFile ($stdout_file); + $test1->DeleteFile ($stderr_file); + return $status; +} + +@bad_files = ( + "data_files/bad_binary.dat", + "data_files/bad_int.dat", + "data_files/bad_string.dat", + "data_files/bad_unsigned_int.dat" + ); + +foreach $bad_file (@bad_files) { + if (test_backup_recovery ($bad_file) != 0) { + $status = 1; + } +} + +exit $status diff --git a/TAO/tests/Storable/test.cpp b/TAO/tests/Storable/test.cpp new file mode 100644 index 00000000000..d9f74cb7763 --- /dev/null +++ b/TAO/tests/Storable/test.cpp @@ -0,0 +1,188 @@ +// $Id$ + +// Assumed to be one of two processes that +// writes/reads from persistent store. +// Each process writes one group of attributes +// and reads from the group written by the +// other process. After reading a check is +// made that expected values are read. +// A sleep is done at the end of the loop +// to account for limitation in resolution +// of timestamp on file used to determine +// if the file is stale. + +#include "Savable.h" + +#include "tao/Storable_FlatFileStream.h" + +#include "ace/Get_Opt.h" + +#include "ace/OS_NS_unistd.h" + +#include <iostream> + +const ACE_TCHAR *persistence_file = ACE_TEXT("test.dat"); + +int num_loops = 1; +int sleep_msecs = 100; +int write_index = 0; +bool use_backup = false; + +int +parse_args (int argc, ACE_TCHAR *argv[]) +{ + ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("n:s:i:b")); + int c; + + while ((c = get_opts ()) != -1) + switch (c) + { + case 'n': + num_loops = ACE_OS::atoi (get_opts.opt_arg ()); + break; + + case 's': + sleep_msecs = ACE_OS::atoi (get_opts.opt_arg ()); + break; + + case 'i': + write_index = ACE_OS::atoi (get_opts.opt_arg ()); + break; + + case 'b': + use_backup = true; + break; + + case '?': + default: + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("usage: %s ") + ACE_TEXT("-n <number-of-loops> ") + ACE_TEXT("-s <milliseconds-to-sleep-in-loop> ") + ACE_TEXT("-i <index-used-for-writing> ") + ACE_TEXT("-b (use backup) ") + ACE_TEXT("\n"), + argv [0]), + -1); + } + + if (write_index != 0 && write_index != 1) + { + ACE_ERROR_RETURN ((LM_ERROR, + ACE_TEXT("Error: Value passed to -i should be ") + ACE_TEXT("0 or 1.")), + -1); + } + + // Indicates successful parsing of the command line + return 0; +} + +int +ACE_TMAIN(int argc, ACE_TCHAR *argv[]) +{ + int exit_status = 0; + + if (parse_args (argc, argv) != 0) + return 1; + + int read_index = write_index ? 0 : 1; + + TAO::Storable_Base::use_backup_default = use_backup; + + TAO::Storable_FlatFileFactory factory ("./"); + + ACE_CString str_write_value = "test_string"; + int int_write_value = -100; + unsigned int unsigned_int_write_value = 100; + + const int bytes_size = 8; + char bytes_write_value[bytes_size]; + char bytes_read[bytes_size]; + // Set 1st byte to 32 (ASCII space) to + // make sure fscanf doesn't consume it + // when reading the size. + bytes_write_value[0] = 32; + for (int i = 1; i < bytes_size; ++i) + { + bytes_write_value[i] = i; + } + + ACE_Time_Value sleep_time (0, 1000*sleep_msecs); + + try + { + for (int j = 0; j < num_loops; ++j) + { + + // Constructor called num_loops times. + // Each time state read from persistent store. + Savable savable(factory); + + // If the file was read, verify what was + // written from other process is correct. + if (savable.is_loaded_from_stream ()) + { + + int int_read = savable.int_get(read_index); + // If value read is not 0 then the other + // process has written to persistent store. + // If not, it's too soon to test. + if (int_read != 0) + { + ACE_ASSERT (int_read == int_write_value); + + const ACE_CString & str_read = savable.string_get(read_index); + ACE_ASSERT (str_read == str_write_value); + + unsigned int unsigned_int_read = + savable.unsigned_int_get (read_index); + ACE_ASSERT (unsigned_int_read == unsigned_int_write_value); + + int bytes_read_size = + savable.bytes_get (read_index, bytes_read); + ACE_ASSERT (bytes_read_size == bytes_size); + for (int k = 0; k < bytes_size; ++k) + { + ACE_ASSERT (bytes_read[k] == bytes_write_value[k]); + } + } + } + + // Write out state + savable.string_set(write_index, str_write_value); + savable.int_set(write_index, int_write_value); + savable.unsigned_int_set(write_index, unsigned_int_write_value); + savable.bytes_set(write_index, bytes_size, bytes_write_value); + int bytes_size = savable.bytes_get (write_index, bytes_read); + for (int k = 0; k < bytes_size; ++k) + { + ACE_ASSERT (bytes_read[k] == bytes_write_value[k]); + } + + ACE_OS::sleep (sleep_time); + } + } + + catch (Savable_Exception &) + { + std::cout << "Savable_Exception thrown" << std::endl; + exit_status = 1; + } + + catch (TAO::Storable_Read_Exception &ex) + { + std::cout << "TAO::Storable_Read_Exception thrown with state " << + ex.get_state () << std::endl; + exit_status = 1; + } + + catch (TAO::Storable_Write_Exception &ex) + { + std::cout << "TAO::Storable_Write_Exception thrown with state " << + ex.get_state () << std::endl; + exit_status = 1; + } + + return exit_status; +} |