Remove dynamic exceptions
[anna.git] / include / anna / testing / TestStep.hpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 #ifndef anna_testing_TestStep_hpp
10 #define anna_testing_TestStep_hpp
11
12 // Standard
13 #include <string>
14 #include <vector>
15 #include <thread>
16 #include <atomic>
17
18 // Project
19 #include <anna/core/DataBlock.hpp>
20 #include <anna/testing/TestDiameterCondition.hpp>
21 #include <anna/core/util/Millisecond.hpp>
22
23
24 namespace anna {
25   class Millisecond;
26
27   namespace xml {
28     class Node;
29   }
30   namespace diameter {
31     namespace codec {
32       class Message;
33     }
34     namespace comm {
35       class OriginHost;
36       class ClientSession;
37       class ServerSession;
38     }
39   }
40
41 namespace testing {
42
43 class TestCase;
44 class TestTimer;
45
46 class TestStep {
47
48     int a_number; // step number used for xml (informational)
49     anna::Millisecond a_beginTimestamp; // unix time
50     anna::Millisecond a_endTimestamp; // unix time
51     bool a_executed; // used for interactive mode in order to not repeat a execution step if before completing, the user add interactive amount
52
53     void setBeginTimestamp(const anna::Millisecond &t) { a_beginTimestamp = t; }
54     const anna::Millisecond &getBeginTimestamp() const { return a_beginTimestamp; }
55     void setEndTimestamp(const anna::Millisecond &t) { a_endTimestamp = t; }
56     const anna::Millisecond &getEndTimestamp() const { return a_endTimestamp; }
57
58     void initialize(TestCase *testCase);
59
60   public:
61     struct Type { enum _v { Unconfigured, Timeout, Sendxml2e, Sendxml2c, Delay, Wait, Cmd, IpLimit }; };
62     static const char* asText(const Type::_v type) ;
63
64     TestStep(TestCase *testCase) : a_message(true), a_messageCodec(NULL), a_executed(false) { initialize(testCase); }
65     virtual ~TestStep() {;}
66
67     // setter & getters
68     const Type::_v &getType() const { return a_type; }
69     const int &getNumber() const { return a_number; }
70     bool isCompleted() const { return a_completed; }
71     anna::Millisecond getLapseMs() const { return a_endTimestamp - a_beginTimestamp; }
72
73     bool execute() ;
74     void complete() ;
75     void reset() ;
76     void next() ;
77     virtual anna::xml::Node* asXML(anna::xml::Node* parent) ;
78     std::string asXMLString() ;
79
80   protected:
81     TestCase *a_testCase;
82     bool a_completed;
83     Type::_v a_type;
84
85     // Message (not for all step types)
86     anna::DataBlock a_message;
87     anna::diameter::codec::Message *a_messageCodec; // used as helper and for traffic logs
88     bool decodeMessage(bool trust = false) ; // If trust=true: decoding the previously encoded message (sendxml sentences).
89                                                     // The only error would be validation ones, and we are going to ignore them here.
90
91     virtual bool do_execute()  = 0; // returns true if next step must be executed
92     virtual void do_complete()  = 0; // end of transaction (delay/timeout expired, wait condition fulfilled, sending done)
93                                             // In all cases, the next step will be executed except 'timeout' which is asynchronous
94                                             //  and will move to the next step just after timer creation (no complete waited)
95     virtual void do_reset()  = 0;
96 };
97
98
99 class TestStepTimeout : public TestStep {
100
101     anna::Millisecond a_timeout;
102     TestTimer *a_timer; // just in case i would need to cancel
103
104   public:
105     TestStepTimeout(TestCase *testCase) : TestStep(testCase), a_timeout(0), a_timer(NULL) { a_type = Type::Timeout; }
106     ~TestStepTimeout() { do_reset(); }
107
108     // setter & getters
109     void setTimeout(const anna::Millisecond &t) { a_timeout = t; }
110     const anna::Millisecond &getTimeout() const { return a_timeout; }
111
112     // virtuals
113     bool do_execute() ;
114     void do_complete() ; // timeout reached, test case failed
115     void do_reset() ;
116     void cancelTimer() ;
117     anna::xml::Node* asXML(anna::xml::Node* parent) ;
118 };
119
120
121 class TestStepSendDiameterXml : public TestStep {
122
123   protected:
124     // possible end points:
125     anna::diameter::comm::OriginHost *a_originHost;
126
127     // Step number reference ('wait for request' step)
128     int a_waitForRequestStepNumber;
129
130     // Expired ?
131     bool a_expired; // a_endTimestamp will be the expiration reception timestamp
132
133   public:
134     TestStepSendDiameterXml(TestCase *testCase) : TestStep(testCase),
135       a_expired(false),
136       a_originHost(NULL),
137       a_waitForRequestStepNumber(-1) {;}
138     ~TestStepSendDiameterXml() { do_reset(); }
139
140     // setter & getters
141     void setOriginHost(anna::diameter::comm::OriginHost *host) { a_originHost = host; }
142     anna::diameter::comm::OriginHost *getOriginHost() const { return a_originHost; }
143     void setWaitForRequestStepNumber(int stepNumber) { a_waitForRequestStepNumber = stepNumber; }
144     int getWaitForRequestStepNumber() const { return a_waitForRequestStepNumber; }
145     void setMsgDataBlock(const anna::DataBlock &db) { a_message = db; }
146     const anna::DataBlock &getMsgDataBlock() const { return a_message; }
147
148     // virtuals
149     bool do_execute() ;
150     void do_complete() {;}
151     void do_reset() ;
152     anna::xml::Node* asXML(anna::xml::Node* parent) ;
153 };
154
155 class TestStepSendDiameterXml2e : public TestStepSendDiameterXml {
156   public:
157     TestStepSendDiameterXml2e(TestCase *testCase) : TestStepSendDiameterXml(testCase) { a_type = Type::Sendxml2e; }
158 };
159
160 class TestStepSendDiameterXml2c : public TestStepSendDiameterXml {
161   public:
162     TestStepSendDiameterXml2c(TestCase *testCase) : TestStepSendDiameterXml(testCase) { a_type = Type::Sendxml2c; }
163 };
164
165
166 class TestStepDelay : public TestStep {
167     anna::Millisecond a_delay;
168     TestTimer *a_timer; // just in case i would need to cancel
169
170   public:
171     TestStepDelay(TestCase *testCase) : TestStep(testCase), a_delay(0), a_timer(NULL) { a_type = Type::Delay; }
172     ~TestStepDelay() { do_reset(); }
173
174     // setter & getters
175     void setDelay(const anna::Millisecond &d) { a_delay = d; }
176     const anna::Millisecond &getDelay() const { return a_delay; }
177
178     // virtuals
179     bool do_execute() ;
180     void do_complete() ; // delay reached
181     void do_reset() ;
182     void cancelTimer() ;
183     anna::xml::Node* asXML(anna::xml::Node* parent) ;
184 };
185
186
187 class TestStepWaitDiameter : public TestStep {
188
189     TestDiameterCondition a_condition;
190     anna::diameter::comm::ClientSession *a_clientSession;
191     anna::diameter::comm::ServerSession *a_serverSession;
192
193   public:
194     TestStepWaitDiameter(TestCase *testCase) : TestStep(testCase) {
195       a_type = Type::Wait;
196       a_clientSession = NULL;
197       a_serverSession = NULL;
198     }
199     ~TestStepWaitDiameter() { do_reset(); }
200
201     // setter & getters
202     void setCondition(bool fromEntity,
203                         const std::string &code, const std::string &bitR, const std::string &hopByHop, const std::string &applicationId,
204                         const std::string &sessionId, const std::string &resultCode,
205                         const std::string &msisdn, const std::string &imsi, const std::string &serviceContextId) ;
206     void setConditionRegexpXml(bool fromEntity, const std::string &regexp) ;
207     void setConditionRegexpHex(bool fromEntity, const std::string &regexp) ;
208
209     void setClientSession(anna::diameter::comm::ClientSession *cs) { a_clientSession = cs; }
210     void setServerSession(anna::diameter::comm::ServerSession *ss) { a_serverSession = ss; }
211     anna::diameter::comm::ClientSession *getClientSession() const { return a_clientSession; }
212     anna::diameter::comm::ServerSession *getServerSession() const { return a_serverSession; }
213
214     const TestDiameterCondition &getCondition() const { return a_condition; }
215     //void setMsgDataBlock(const anna::DataBlock &db) { a_message = db; }
216     bool fulfilled(const anna::DataBlock &db/*, bool matchSessionId = true*/) ;
217     const anna::DataBlock &getMsgDataBlock() const { return a_message; }
218
219
220     // virtuals
221     bool do_execute() ; // this will be executed when test case starts (at least we could measure the time until condition is fulfilled)
222     void do_complete() ; // condition fulfilled
223     void do_reset() ;
224     anna::xml::Node* asXML(anna::xml::Node* parent) ;
225 };
226
227
228 class TestStepCmd : public TestStep {
229
230   std::string a_script;
231   std::thread a_thread;
232   std::atomic<bool> a_threadRunning;
233   bool a_threadDeprecated;
234   int a_resultCode;
235   std::string a_errorMsg;
236   //std::string a_output; // for POPEN
237
238   pid_t a_childPid;
239
240   public:
241     TestStepCmd(TestCase *testCase) : TestStep(testCase), a_threadRunning(false), a_threadDeprecated(false), a_resultCode(-2)/*, a_output("")*/, a_errorMsg(""), a_childPid(-1) { a_type = Type::Cmd; }
242     ~TestStepCmd() { do_reset(); }
243
244     // setter & getters
245     void setThreadRunning() { a_threadRunning = true; }
246     void setThreadNotRunning() { a_threadRunning = false; }
247     bool threadRunning() const { return a_threadRunning; }
248     bool threadNotRunning() const { return !a_threadRunning; }
249
250     void setResultCode(int rc) { a_resultCode = rc; }
251     int getResultCode() const { return a_resultCode; }
252     void setErrorMsg(const std::string &em) { a_errorMsg = em; }
253     const std::string &getErrorMsg() const { return a_errorMsg; }
254     //void appendOutput(const std::string &output) { a_output += output; }
255     //const std::string &getOutput() const { return a_output; }
256     void setChildPid(pid_t pid) { a_childPid = pid; }
257     const pid_t &getChildPid() const { return a_childPid; }
258
259     void setScript(const std::string &script) { a_script = script; }
260     const std::string &getScript() const { return a_script; }
261
262     // virtuals
263     bool do_execute() ;
264     void do_complete() ;
265     void do_reset() ;
266     anna::xml::Node* asXML(anna::xml::Node* parent) ;
267 };
268
269
270 class TestStepIpLimit : public TestStep {
271
272     unsigned int a_ipLimit;
273
274   public:
275     TestStepIpLimit(TestCase *testCase) : TestStep(testCase), a_ipLimit(1) { a_type = Type::IpLimit; }
276     ~TestStepIpLimit() { do_reset(); }
277
278     // setter & getters
279     void setIpLimit(unsigned int limit) { a_ipLimit = limit; }
280     unsigned int getIpLimit() const { return a_ipLimit; }
281
282     // virtuals
283     bool do_execute() ;
284     void do_complete() ;
285     void do_reset() {;}
286     anna::xml::Node* asXML(anna::xml::Node* parent) ;
287 };
288
289 }
290 }
291
292 #endif
293