summaryrefslogtreecommitdiff
path: root/TAO/tests/Storable
diff options
context:
space:
mode:
authorstanleyk <stanleyk@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2013-02-05 21:11:03 +0000
committerstanleyk <stanleyk@ae88bc3d-4319-0410-8dbf-d08b4c9d3795>2013-02-05 21:11:03 +0000
commit5e030faf84086ab02059fcbcc3faed224bd57b95 (patch)
tree3a62df45ac6ccf599fb07cf6a03d672456ce2e3d /TAO/tests/Storable
parent9d296f7fa51116ff7040ecb2ad18612cd94b5fd1 (diff)
downloadATCD-5e030faf84086ab02059fcbcc3faed224bd57b95.tar.gz
Merge in OCI_Reliability_Enhancements branch.
Diffstat (limited to 'TAO/tests/Storable')
-rw-r--r--TAO/tests/Storable/README14
-rw-r--r--TAO/tests/Storable/Savable.cpp228
-rw-r--r--TAO/tests/Storable/Savable.h61
-rw-r--r--TAO/tests/Storable/Storable.mpc6
-rw-r--r--TAO/tests/Storable/data_files/bad_binary.dat6
-rw-r--r--TAO/tests/Storable/data_files/bad_int.dat3
-rw-r--r--TAO/tests/Storable/data_files/bad_string.dat2
-rw-r--r--TAO/tests/Storable/data_files/bad_unsigned_int.dat4
-rw-r--r--TAO/tests/Storable/data_files/good.dat11
-rwxr-xr-xTAO/tests/Storable/run_test.pl156
-rw-r--r--TAO/tests/Storable/test.cpp188
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;
+}