Merge pull request #2303 from jwillemsen/jwi-803
[ACE_TAO.git] / TAO / orbsvcs / tests / FT_App / FT_Client.cpp
blobdff92a135826b6d6a1c1ee40df6bbe23d2373335
1 #include "FT_TestReplicaC.h"
2 #include <ace/Vector_T.h>
3 #include <ace/SString.h>
4 #include <ace/Get_Opt.h>
5 // FUZZ: disable check_for_streams_include
6 #include "ace/streams.h"
7 #include "ace/OS_NS_unistd.h"
8 #include "ace/OS_NS_stdio.h"
10 class FTClientMain
12 typedef ACE_Vector<ACE_CString> StringVec;
13 public:
14 ///////////////////////////
15 // construction/destruction
16 FTClientMain ();
18 ~FTClientMain ();
20 /////////////////
21 // initialization
22 int parse_args (int argc, ACE_TCHAR *argv[]);
24 ////////////
25 // execution
26 int run ();
28 /////////////////
29 // implementation
30 private:
31 void usage (FILE* out)const;
32 void commandUsage (FILE* out);
33 int pass (
34 long & counter, // inout
35 int & more, // out
36 ACE_CString & command, // inout
37 int retry); // in
39 int next_replica ();
41 ////////////////////
42 // forbidden methods
43 private:
44 FTClientMain (const FTClientMain & rhs);
45 FTClientMain & operator = (const FTClientMain & rhs);
47 ////////////////
48 // Data members
49 private:
50 CORBA::ORB_var orb_;
52 int argc_;
53 ACE_TCHAR ** argv_;
54 const ACE_TCHAR * inFileName_;
55 FILE *inFile_;
56 FILE *commandIn_;
58 enum Verbosity{
59 SILENT,
60 QUIET,
61 NORMAL,
62 NOISY,
63 LOUD}
64 verbose_;
67 StringVec replica_iors_;
68 size_t replica_pos_;
69 const char * replica_name_;
70 FT_TEST::TestReplica_var replica_;
74 FTClientMain::FTClientMain ()
75 : inFile_(0)
76 , commandIn_(stdin)
77 , verbose_(NORMAL)
78 , replica_pos_(0)
79 , replica_name_("none")
83 FTClientMain::~FTClientMain ()
85 if (this->inFile_)
87 ACE_OS::fclose (this->inFile_);
88 this->inFile_ = 0;
92 void FTClientMain::commandUsage(FILE* out)
94 ACE_OS::fprintf (out,
95 "Each command must be at the beginning of a separate line.\n"
96 "Everything after the command (and operand if any) is ignored.\n"
97 "Valid commands are:\n"
98 " Access via method call:\n"
99 " =N set counter to N\n"
100 " cN get counter and compare to N (c stands for \"check\"\n"
101 " +N increment counter by N\n"
102 " -N decrement counter by N\n"
103 " Access as attribute:\n"
104 " >N set attribute to N\n"
105 " < get attribite\n"
106 " Try methods to be used by fault tolerant infrastructure:\n"
107 " ! is_alive\n"
108 " s get_state\n"
109 " S set_state\n"
110 " u get_update\n"
111 " U set_update\n"
112 " Simulate failure:\n"
113 " dN die on condition:\n"
114 " d%d don't die\n"
115 " d%d immediately\n"
116 " d%d while idle\n"
117 " (FT_TestReplica interface)\n"
118 " d%d before state change\n"
119 " d%d after state change, before replication\n"
120 " d%d after replication, before reply\n"
121 " (Monitorable interface)\n"
122 " d%d during is alive\n"
123 " d%d is_alive returns false\n"
124 " (Updatable interface)\n"
125 " d%d during get update\n"
126 " d%d before set update\n"
127 " d%d after set update\n"
128 " (Checkpointable interface)\n"
129 " d%d during get state\n"
130 " d%d before set state\n"
131 " d%d after set state\n"
132 " Logistics commands:\n"
133 " # ignore this line (comment).\n"
134 " v set verbosity:\n"
135 " 0 don't check counter value.\n"
136 " 1 only display counter value mismatch.\n"
137 " 2 display counter value after every command (default).\n"
138 " 3 display commands.\n"
139 " 4 display method calls.\n"
140 " zN sleep N seconds.\n"
141 " q quit (end the client, not the replica(s).)\n"
142 " q1 quit (end the client, and shutdown the currently active replica.)\n"
143 " ? help (this message)\n",
144 FT_TEST::TestReplica::NOT_YET,
145 FT_TEST::TestReplica::RIGHT_NOW,
146 FT_TEST::TestReplica::WHILE_IDLE,
147 FT_TEST::TestReplica::BEFORE_STATE_CHANGE,
148 FT_TEST::TestReplica::BEFORE_REPLICATION,
149 FT_TEST::TestReplica::BEFORE_REPLY,
150 FT_TEST::TestReplica::DURING_IS_ALIVE,
151 FT_TEST::TestReplica::DENY_IS_ALIVE,
152 FT_TEST::TestReplica::DURING_GET_UPDATE,
153 FT_TEST::TestReplica::BEFORE_SET_UPDATE,
154 FT_TEST::TestReplica::AFTER_SET_UPDATE,
155 FT_TEST::TestReplica::DURING_GET_STATE,
156 FT_TEST::TestReplica::BEFORE_SET_STATE,
157 FT_TEST::TestReplica::AFTER_SET_STATE);
161 FTClientMain::parse_args (int argc, ACE_TCHAR *argv[])
163 this->argc_ = argc;
164 this->argv_ = argv;
165 int result = 0;
167 // note: dfnkx are simple_util options
168 // include them here so we can detect bad args
169 ACE_Get_Opt get_opts (argc, argv, ACE_TEXT("c:f:"));
170 int c;
172 while (result == 0 && (c = get_opts ()) != -1)
174 switch (c)
176 case 'c':
178 this->inFileName_ = get_opts.opt_arg ();
179 this->inFile_ = ACE_OS::fopen (this->inFileName_, "r");
180 if(this->inFile_ && !ferror (this->inFile_))
182 ACE_OS::fprintf (stdout, "FT Client: Reading commands from %s\n",
183 ACE_TEXT_ALWAYS_CHAR (this->inFileName_));
184 this->commandIn_ = this->inFile_;
186 else
188 ACE_OS::fprintf (stderr, "FT Client: Can't open input file: %s\n",
189 ACE_TEXT_ALWAYS_CHAR (this->inFileName_));
190 result = -1;
192 break;
194 case 'f':
196 replica_iors_.push_back(ACE_TEXT_ALWAYS_CHAR(get_opts.opt_arg ()));
197 break;
200 default:
201 case '?':
202 usage(stderr);
203 result = 1;
206 return result;
209 void FTClientMain::usage(FILE* out)const
211 ACE_OS::fprintf (out, "usage"
212 " -c <command file>"
213 " [-f <ior file>]...\n");
216 int FTClientMain::pass (
217 long & counter,
218 int & more,
219 ACE_CString & command,
220 int retry)
222 int result = 0;
224 ::FT::State_var state;
225 unsigned long stateValue = 0;
226 ::FT::State_var update;
227 unsigned long updateValue = 0;
229 while(more && result == 0 && !feof (this->commandIn_))
231 if (! retry || command.length () == 0 )
233 char buffer[1000];
234 char *str_ = ACE_OS::fgets (buffer, sizeof(buffer)-1, this->commandIn_);
235 if ( str_ )
237 str_ = ACE_OS::strrchr (str_, '\n');
238 if ( str_ )
239 *str_ = '\0';
241 command = buffer;
243 retry = 0;
245 if (command.length() >0)
247 char op = command[0];
248 ACE_CString cdr = command.substr(1);
249 char * junque;
250 long operand = ACE_OS::strtol(cdr.c_str(),&junque, 10);
252 if (this->verbose_ >= NOISY)
254 ACE_OS::fprintf (stdout, "FT Client: %s\n", command.c_str());
257 // turn echo on (based on verbose)
258 // individual commands can turn it off
259 int echo = this->verbose_ >= QUIET;
261 switch(op)
263 case '#':
265 echo = 0;
266 break;
268 case '=':
270 if (this->verbose_ >= LOUD)
272 ACE_OS::fprintf (stdout, "FT Client: ->set(%ld);\n", operand);
274 this->replica_->set(operand);
275 counter = operand;
276 break;
278 case 'c':
280 if (this->verbose_ >= LOUD)
282 ACE_OS::fprintf (stdout, "FT Client: ->get();\n");
284 long value = this->replica_->counter();
285 if (value == operand)
287 ACE_OS::fprintf (stdout, "FT Client: Good: Read %ld expecting %ld\n", value, operand);
288 counter = operand;
290 else
292 ACE_OS::fprintf (stdout, "FT Client: Error: Read %ld expecting %ld\n", value, operand);
294 echo = 0;
295 break;
297 case '>':
299 if (this->verbose_ >= LOUD)
301 ACE_OS::fprintf (stdout, "FT Client: ->counter(%ld);\n", operand);
303 this->replica_->counter(operand);
304 counter = operand;
305 break;
307 case '+':
309 if (this->verbose_ >= LOUD)
311 ACE_OS::fprintf (stdout, "FT Client: ->increment(%ld);\n", operand);
313 this->replica_->increment(operand);
314 counter += operand;
315 break;
317 case '-':
319 if (this->verbose_ >= LOUD)
321 ACE_OS::fprintf (stdout, "FT Client: ->increment(%ld);\n", -operand);
323 this->replica_->increment(-operand);
324 counter -= operand;
325 break;
327 case '<':
329 if (this->verbose_ >= LOUD)
331 ACE_OS::fprintf (stdout, "FT Client: ->counter();\n");
333 long attribute = this->replica_->counter();
334 ACE_OS::fprintf (stdout, "FT Client: Attribute: %ld\n", attribute);
335 echo = 0;
336 break;
338 case '!':
340 if (this->verbose_ >= LOUD)
342 ACE_OS::fprintf (stdout, "FT Client: ->is_alive();\n");
344 int alive = this->replica_->is_alive();
345 ACE_OS::fprintf (stdout, "FT Client: Is alive? %d\n", alive);
346 break;
348 case 'd':
350 if (this->verbose_ >= LOUD)
352 ACE_OS::fprintf (stdout, "FT Client: ->die(%ld);\n", operand);
354 this->replica_->die(static_cast<FT_TEST::TestReplica::Bane> (operand));
355 echo = 0;
356 break;
358 case 's':
360 if (this->verbose_ >= LOUD)
362 ACE_OS::fprintf (stdout, "FT Client: ->get_state();\n");
364 state = this->replica_->get_state();
365 stateValue = counter;
366 break;
368 case 'S':
370 if (state->length () > 0)
372 if (this->verbose_ >= LOUD)
374 ACE_OS::fprintf (stdout, "FT Client: ->set_state(saved_state);\n");
376 this->replica_->set_state (state.in ());
377 counter = stateValue;
379 else
381 ACE_OS::fprintf (stdout, "FT Client: Error: no saved state.\n");
383 break;
385 case 'u':
387 if (this->verbose_ >= LOUD)
389 ACE_OS::fprintf (stdout, "FT Client: ->get_update();\n");
391 update = this->replica_->get_update();
392 updateValue = counter;
393 break;
395 case 'U':
397 if (update->length () > 0)
399 if (this->verbose_ >= LOUD)
401 ACE_OS::fprintf (stdout, "FT Client: ->set_update(saved_update);\n");
403 this->replica_->set_update(update.in ());
404 counter = updateValue;
406 else
408 ACE_OS::fprintf (stdout, "FT Client: ERROR: No saved update information.\n");
410 break;
412 case 'v':
414 this->verbose_ = static_cast<Verbosity> (operand);
415 break;
417 case 'z':
419 if (operand == 0)
421 operand = 1;
423 ACE_Time_Value tv (operand,0);
424 ACE_OS::sleep(tv);
425 break;
427 case 'q':
429 if (operand != 0)
433 if (this->verbose_ >= LOUD)
435 ACE_OS::fprintf (stdout, "FT Client: ->shutdown();\n");
437 this->replica_->shutdown();
438 // @@ Note: this is here because the corba event loop seems to go to sleep
439 // if there's nothing for it to do.
440 // not quite sure why, yet. Dale
441 this->replica_->is_alive();
443 catch (const CORBA::Exception&)
445 ACE_OS::fprintf (stdout, "FT Client: Ignoring expected exception during shutdown.\n");
446 ; // ignore exception during shutdown
449 echo = 0;
450 more = 0;
451 break;
453 default:
455 if (op != '?')
457 ACE_OS::fprintf (stdout, "FT Client: Unknown: %s\n", command.c_str());
459 commandUsage(stderr);
460 break;
463 if (echo && this->verbose_ >= QUIET)
465 if (this->verbose_ >= LOUD)
467 ACE_OS::fprintf (stdout, "FT Client: ->get();\n");
470 long value = this->replica_->get();
471 if (value == counter)
473 if (this->verbose_ >= NORMAL)
475 ACE_OS::fprintf (stdout, "FT Client: %ld\n", counter);
478 else
480 ACE_OS::fprintf (stdout, "FT Client: Error: read %ld expecting %ld\n", value, counter);
481 result = -1;
486 return result;
489 int FTClientMain::next_replica ()
491 int result = 0;
492 if (this->replica_pos_ < this->replica_iors_.size())
494 this->replica_name_ = this->replica_iors_[this->replica_pos_].c_str();
495 this->replica_pos_ += 1;
496 CORBA::Object_var rep_obj = this->orb_->string_to_object (this->replica_name_);
497 this->replica_ = FT_TEST::TestReplica::_narrow (rep_obj.in ());
498 if (! CORBA::is_nil (replica_.in ()))
500 result = 1;
502 else
504 ACE_OS::fprintf (stderr, "FT Client: Can't resolve IOR: %s\n", this->replica_name_);
507 else
509 ACE_OS::fprintf (stderr,
510 "***OUT_OF_REPLICAS*** "
511 ACE_SIZE_T_FORMAT_SPECIFIER_ASCII
512 "\n",
513 this->replica_pos_);
515 return result;
519 int FTClientMain::run ()
521 int result = 0;
523 this->orb_ = CORBA::ORB_init(this->argc_, this->argv_);
525 int ok = next_replica ();
526 if (ok)
528 // retry information
529 ACE_CString command;
530 int retry = 0;
531 long counter = this->replica_->get();
533 if (this->verbose_ >= NORMAL)
535 ACE_OS::fprintf (stdout, "FT Client: Initial counter %ld\n", counter);
537 if (ACE_OS::isatty(ACE_OS::fileno(stdin)))
539 ACE_OS::fprintf (stdout, "FT Client: Commands(? for help):\n");
542 int more = 1;
543 while (more && result == 0 && !feof (this->commandIn_))
547 result = pass (counter, more, command, retry);
549 catch (const CORBA::SystemException& sysex)
551 ACE_OS::fprintf (stdout, "FT Client: Caught system exception:\n");
552 sysex._tao_print_exception ("FT Client");
554 retry = 0;
555 int handled = 0;
557 handled = next_replica();
558 if (handled)
560 ACE_OS::fprintf (stdout, "FT Client: Recovering from fault.\n");
561 ACE_OS::fprintf (stdout, "FT Client: Activate %s\n", this->replica_name_);
562 if (command.length () == 0)
564 ACE_OS::fprintf (stdout, "FT Client: No command to retry.\n");
566 else if (command[0] == 'd')
568 ACE_OS::fprintf (stdout, "FT Client: Not retrying \"die\" command.\n");
570 else if (sysex.completed () == CORBA::COMPLETED_YES)
572 ACE_OS::fprintf (stdout, "FT Client: Last command completed. No retry needed.\n");
574 else
576 if (sysex.completed () == CORBA::COMPLETED_MAYBE)
578 ACE_OS::fprintf (stdout, "FT Client: Last command may have completed. Retrying anyway.\n");
580 retry = 1;
581 ACE_OS::fprintf (stdout, "FT Client: Retrying command: %s\n", command.c_str());
584 if (! handled)
586 ACE_OS::fprintf (stdout, "FT Client: Exception not handled. Rethrow. ");
587 throw;
592 else
594 ACE_OS::fprintf (stderr, "FT Client: Can't connect to replica.\n");
596 return result;
601 ACE_TMAIN(int argc, ACE_TCHAR *argv[])
603 FTClientMain app;
604 int result = app.parse_args(argc, argv);
605 if (result == 0)
609 result = app.run ();
611 catch (const CORBA::Exception& ex)
613 ex._tao_print_exception ("FT_Client::main\t\n");
614 result = -1;
617 return result;