EMMA Coverage Report (generated Sat Jul 01 16:38:45 PDT 2006)
[all classes][jade.jademx.unit]

COVERAGE SUMMARY FOR SOURCE FILE [UnitTestBehaviour.java]

nameclass, %method, %block, %line, %
UnitTestBehaviour.java100% (2/2)95%  (18/19)89%  (1223/1371)89%  (296.6/335)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class UnitTestBehaviour100% (1/1)94%  (16/17)89%  (1088/1224)89%  (261.8/294)
getAmsTimeout (): String 0%   (0/1)0%   (0/3)0%   (0/1)
stopSniffing (): void 100% (1/1)31%  (8/26)44%  (4/9)
startSniffing (): void 100% (1/1)45%  (5/11)60%  (3/5)
setSniffing (boolean): void 100% (1/1)65%  (34/52)86%  (6/7)
action (): void 100% (1/1)65%  (87/133)82%  (27.8/34)
inject (): void 100% (1/1)71%  (15/21)71%  (5/7)
doSniff (): void 100% (1/1)83%  (109/131)78%  (28/36)
sendJmxNotification (): void 100% (1/1)86%  (31/36)80%  (8/10)
getSniffRequestMessage (boolean): ACLMessage 100% (1/1)94%  (128/136)91%  (29/32)
compare (): void 100% (1/1)97%  (117/121)92%  (22/24)
UnitTestBehaviour (JademxAgent, ACLMessage, ACLMessage, Duration, Properties)... 100% (1/1)100% (342/342)100% (76/76)
addSniffedAgent (AID): void 100% (1/1)100% (37/37)100% (6/6)
done (): boolean 100% (1/1)100% (3/3)100% (1/1)
globalizeAID (AID): void 100% (1/1)100% (11/11)100% (3/3)
globalizeAgentIds (ACLMessage): void 100% (1/1)100% (110/110)100% (35/35)
injectMessage (): void 100% (1/1)100% (40/40)100% (5/5)
setAmsTimeout (String): void 100% (1/1)100% (11/11)100% (3/3)
     
class UnitTestBehaviour$SenderReceiverMatchExpression100% (1/1)100% (2/2)92%  (135/147)85%  (34.8/41)
match (ACLMessage): boolean 100% (1/1)88%  (88/100)77%  (20.8/27)
UnitTestBehaviour$SenderReceiverMatchExpression (UnitTestBehaviour, ACLMessag... 100% (1/1)100% (47/47)100% (14/14)

1// jademx - JADE management using JMX
2// Copyright 2005-2006 Caboodle Networks, Inc.
3//
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8//
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12// Lesser General Public License for more details.
13//
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 
18package jade.jademx.unit;
19 
20import jade.content.AgentAction;
21import jade.content.ContentElement;
22import jade.content.onto.basic.Action;
23import jade.core.AID;
24import jade.core.behaviours.Behaviour;
25import jade.domain.FIPAException;
26import jade.domain.FIPANames;
27import jade.domain.FIPAService;
28import jade.domain.JADEAgentManagement.JADEManagementOntology;
29import jade.domain.JADEAgentManagement.JADEManagementVocabulary;
30import jade.domain.JADEAgentManagement.SniffOff;
31import jade.domain.JADEAgentManagement.SniffOn;
32import jade.domain.introspection.AMSSubscriber;
33import jade.domain.introspection.Event;
34import jade.domain.introspection.EventRecord;
35import jade.domain.introspection.IntrospectionOntology;
36import jade.domain.introspection.Occurred;
37import jade.domain.introspection.PostedMessage;
38import jade.domain.introspection.ReceivedMessage;
39import jade.domain.introspection.SentMessage;
40import jade.jademx.agent.JademxAgent;
41import jade.jademx.util.AclMsgCmp;
42import jade.jademx.util.ThrowableUtil;
43import jade.jademx.util.iso8601.Duration;
44import jade.lang.acl.ACLMessage;
45import jade.lang.acl.MessageTemplate;
46import jade.util.Logger;
47 
48import java.util.Arrays;
49import java.util.Iterator;
50import java.util.LinkedList;
51import java.util.List;
52import java.util.Properties;
53 
54/** 
55 * behaviour to perform unit test on agent: inject msg and see msg out.
56 * @author David Bernstein, <a href="http://www.caboodlenetworks.com"
57 *  >Caboodle Networks, Inc.</a>
58 */
59public class UnitTestBehaviour extends Behaviour {
60    
61    // logger
62    
63    /** logger for this class */
64    private final Logger logger =
65        Logger.getMyLogger(UnitTestBehaviour.class.getName());
66 
67    // AMS timeout
68    
69    /** default value for AMS timeout */
70    private String DFLT_AMS_TIMEOUT_STR = "PT1M";
71    /** how long to wait for AMS response */
72    private long amsTimeoutMS = 0;
73    /** AMS timeout expressed as ISO 8601 duration */
74    private String amsTimeoutStr = null;
75 
76    // AMS messaging
77 
78    /** message instantiated once to request subscription to AMS */
79    private ACLMessage amsSubscribeMsg = new ACLMessage( ACLMessage.SUBSCRIBE );
80    /** message instantiated once to request cancellation to AMS */
81    private ACLMessage amsCancelMsg = new ACLMessage( ACLMessage.CANCEL );
82    /** message instantiated once to request specific action from AMS */
83    private ACLMessage amsRequestMsg = new ACLMessage( ACLMessage.REQUEST );
84    /** prefix for conversation-id talking to AMS */
85    private String AMS_CONV_ID_PREFIX = "ams-";    
86 
87    // sniffing
88    
89    /** list of agents to sniff - DO NOT include self */
90    private List sniffedAgents = new LinkedList();
91    /** count how many times sniffing turned on */
92    private int sniffOnCount = 0;
93    /** count how many times sniffing turned off */
94    private int sniffOffCount = 0;
95    /** message that was sniffed */
96    private ACLMessage sniffedMessage = null;
97    /** are we currently sniffing */
98    private boolean sniffing = false;
99    
100    // timeout
101    
102    /** once msg injected, can compute absolute testcase timeout in ms */
103    private long testcaseStartMsAbs = 0;
104    /** once msg injected, can compute absolute testcase timeout in ms */
105    private long testcaseTimeoutMsAbs = 0;
106    
107    // testcase parameters
108    
109    /** timeout for testcase */
110    private Duration testcaseTimeout = null;
111    /** message to inject */
112    private ACLMessage messageToInject = null;
113    /** variable strings: each key is string that may change, value is group */
114    private Properties varProps = null;
115    /** expected message to be sniffed */
116    private ACLMessage expectedMessage = null;
117    /** agent-under-test */
118    private JademxAgent jademxAgent = null;
119    
120    // message templates
121    
122    /** template for messages being sniffed */
123    private MessageTemplate matchSenderReceiverTemplate = null;
124    /** pattern for messages that might hold sniffed messages */
125    private MessageTemplate eventPattern = null;
126    
127    // state
128 
129    /** start off in this state */
130    private final static int STATE_INIT = 0;
131    /** inject the test message */
132    private final static int STATE_INJECT = 1;
133    /** wait for matching sniffed message or timeout */
134    private final static int STATE_WAIT = 2;
135    /** compare expected message with sniffed message, if any */
136    private final static int STATE_COMPARE = 3;
137    /** send unit testing success or failure JMX notification */
138    private final static int STATE_NOTIFY = 4;
139    /** behaviour is done */
140    private final static int STATE_COMPLETE = 5;
141    /** behaviour state variable */
142    private int state = STATE_INIT;
143 
144    /** is this behaviour finished */
145    private boolean finished = false;
146    
147    /** text describing why test failed */
148    private String failMsg = null;
149 
150 
151    /**
152     * make behaviour to run a unit test on a JademxAgent.
153     * this is done by injecting a message and waiting for an expected message.
154     * @param jademxAgent agent to test
155     * @param expectedMessage message to expect
156     * @param messageToInject message to inject
157     * @param testcaseTimeout timeout for the testcase
158     * @param varProps variable strings
159     */
160    public UnitTestBehaviour(
161            JademxAgent jademxAgent, 
162            ACLMessage expectedMessage, 
163            ACLMessage messageToInject, 
164            Duration testcaseTimeout,
165            Properties varProps ) {
166        
167        super( jademxAgent );
168        
169        if ( null == jademxAgent ) {
170            throw new IllegalArgumentException("null agent");
171        }
172        if ( null == expectedMessage ) {
173            throw new IllegalArgumentException("null expected message");
174        }
175        if ( null == messageToInject ) {
176            throw new IllegalArgumentException("null message to inject");
177        }
178        if ( null == testcaseTimeout ) {
179            throw new IllegalArgumentException("null testcase timeout");
180        }
181        if ( null == varProps ) {
182            throw new IllegalArgumentException("null variable properties");
183        }
184    
185        this.jademxAgent = jademxAgent;
186        this.expectedMessage = expectedMessage;
187        this.messageToInject = messageToInject;
188        this.testcaseTimeout = testcaseTimeout;
189        this.varProps = varProps;
190        
191        String conversationId = AMS_CONV_ID_PREFIX + myAgent.getLocalName();
192        
193        amsSubscribeMsg.setSender( myAgent.getAID() );
194        amsSubscribeMsg.clearAllReceiver( );
195        amsSubscribeMsg.addReceiver( myAgent.getAMS() );
196        amsSubscribeMsg.setLanguage( FIPANames.ContentLanguage.FIPA_SL0 );
197        amsSubscribeMsg.setOntology( IntrospectionOntology.NAME );
198        amsSubscribeMsg.setReplyWith( AMSSubscriber.AMS_SUBSCRIPTION );
199        amsSubscribeMsg.setConversationId( conversationId );
200        amsSubscribeMsg.setContent( AMSSubscriber.PLATFORM_EVENTS );
201        
202        amsCancelMsg.setSender( myAgent.getAID() );
203        amsCancelMsg.clearAllReceiver( );
204        amsCancelMsg.addReceiver( myAgent.getAMS() );
205        amsCancelMsg.setLanguage( FIPANames.ContentLanguage.FIPA_SL0 );
206        amsCancelMsg.setOntology( IntrospectionOntology.NAME );
207        amsCancelMsg.setReplyWith( AMSSubscriber.AMS_CANCELLATION );
208        amsCancelMsg.setConversationId( conversationId );
209        
210        amsRequestMsg.setSender( myAgent.getAID() );
211        amsRequestMsg.clearAllReceiver( );
212        amsRequestMsg.addReceiver( myAgent.getAMS() );
213        amsRequestMsg.setProtocol( FIPANames.InteractionProtocol.FIPA_REQUEST );
214        amsRequestMsg.setLanguage( FIPANames.ContentLanguage.FIPA_SL0 );
215        amsRequestMsg.setConversationId( conversationId );
216        
217        matchSenderReceiverTemplate = 
218            new MessageTemplate(
219                    new SenderReceiverMatchExpression(
220                            expectedMessage ) );
221 
222        // set agents to sniff
223        logger.log( Logger.FINEST,"expected message "+expectedMessage);
224        logger.log( Logger.FINEST,"expected message sender "+expectedMessage.getSender());
225        addSniffedAgent( expectedMessage.getSender() );
226        jade.util.leap.Iterator rcvrI = expectedMessage.getAllReceiver();
227        while ( rcvrI.hasNext() ) {
228            AID rcvr = (AID)rcvrI.next();
229            logger.log( Logger.FINEST,"expected message receiver "+rcvr);
230            addSniffedAgent( rcvr );
231        }
232        
233        // only msgs matching eventPattern might hold sniffed msgs
234        eventPattern =
235            MessageTemplate.MatchConversationId( 
236                    myAgent.getAID().getName()+"-event" );
237        
238        // set default timeout for AMS communication
239        setAmsTimeout( DFLT_AMS_TIMEOUT_STR );
240        
241    }
242    
243    
244    /**
245     * set the AMS timeout
246     * @param amsTimeoutStr ISO 8601 duration specification of timeout
247     */
248    public void setAmsTimeout( String amsTimeoutStr ) {
249        this.amsTimeoutStr = amsTimeoutStr;
250        amsTimeoutMS = new Duration( amsTimeoutStr ).toMilliseconds();
251    }
252    
253    /**
254     * get the current value of AMS timeout
255     * @return ISO 8601 duration specification of timeout
256     */
257    public String getAmsTimeout() {
258        return amsTimeoutStr;
259    }
260 
261    
262    /**
263     * start or stop the agent sniffing
264     * @param sniffing true => on, false => off
265     * @throws FIPAException on problem
266     */
267    private void setSniffing( boolean sniffing ) throws FIPAException {
268        ACLMessage msg = getSniffRequestMessage( sniffing );
269        logger.log( Logger.FINEST, "sniff "+sniffing+" msg:"+msg);
270        ACLMessage successMsg = 
271            FIPAService.doFipaRequestClient( myAgent, msg, amsTimeoutMS );
272        if ( null == successMsg ) {
273            throw new FIPAException("AMS timeout on SNIFF"+
274                    (sniffing?"ON":"OFF")+" request");
275        }
276        this.sniffing = sniffing;
277    }
278    
279    /**
280     * create and return message to turn sniffing on or off for agents to watch.
281     * assumes that <code>sniffedAgents</code> set.
282     * @param on whether to turn sniffing on or off
283     * @return message to turn sniffing on or off (null if none in list)
284     */
285    private ACLMessage getSniffRequestMessage( boolean on ) {
286        
287        ACLMessage sniffMessage = null; // the message to return
288        
289        // create an agent action for turning sniffing on or off.
290        
291        AgentAction sniffAction;
292        String replyId;
293        
294        if ( on ) {
295            SniffOn sniffOn = new SniffOn();
296            replyId = JADEManagementVocabulary.SNIFFON + sniffOnCount++;
297            sniffOn.setSniffer( myAgent.getAID() );
298            Iterator sniffedAgentsI = sniffedAgents.iterator();
299            while ( sniffedAgentsI.hasNext() ) {
300                sniffOn.addSniffedAgents( (AID)sniffedAgentsI.next() );
301            }
302            sniffAction = sniffOn;
303        }
304        else {
305            SniffOff sniffOff = new SniffOff();
306            replyId = JADEManagementVocabulary.SNIFFOFF + sniffOffCount++;
307            sniffOff.setSniffer( myAgent.getAID() );
308            Iterator sniffedAgentsI = sniffedAgents.iterator();
309            while ( sniffedAgentsI.hasNext() ) {
310                sniffOff.addSniffedAgents( (AID)sniffedAgentsI.next() );
311            }
312            sniffAction = sniffOff;
313        }
314        
315        // fill in message
316        
317        try {
318            Action action = new Action();
319            action.setActor( myAgent.getAMS() );
320            action.setAction( sniffAction );
321            amsRequestMsg.setOntology( JADEManagementOntology.NAME );
322            amsRequestMsg.setReplyWith( replyId );
323            logger.log( Logger.FINEST,"action:"+action);
324            myAgent.getContentManager().fillContent( amsRequestMsg, action );
325        }
326        catch ( Exception e ) {
327            e.printStackTrace();
328            throw new RuntimeException( e );
329        }
330        sniffMessage = amsRequestMsg;
331        
332        // return constructed message
333        return sniffMessage;
334    }
335 
336    
337    /**
338     * convert local sender/receiver/replyTo to ISGUID format
339     * @param m message for which to globalize each agent id
340     */
341    private void globalizeAgentIds( ACLMessage m ) {
342        
343        // perhaps should clone AIDs before they're globalized?
344        
345        // sender
346        AID sender = m.getSender();
347        globalizeAID( sender );
348        m.setSender( sender );
349        
350        // receiver
351        jade.util.leap.Iterator receivers = m.getAllReceiver();
352        jade.util.leap.List globalizedReceivers = 
353            new jade.util.leap.LinkedList();
354        while ( receivers.hasNext() ) {
355            AID receiver = (AID)receivers.next();
356            globalizeAID( receiver );
357            globalizedReceivers.add( receiver );
358        }
359        m.clearAllReceiver();
360        receivers = globalizedReceivers.iterator();
361        while ( receivers.hasNext() ) {
362            m.addReceiver( (AID)receivers.next() );
363        }
364        
365        // reply-to
366        jade.util.leap.Iterator replyTos = m.getAllReplyTo();
367        jade.util.leap.List globalizedReplyTos = 
368            new jade.util.leap.LinkedList();
369        while ( replyTos.hasNext() ) {
370            AID replyTo = (AID)replyTos.next();
371            globalizeAID( replyTo );
372            globalizedReplyTos.add( replyTo );
373        }
374        m.clearAllReplyTo();
375        replyTos = globalizedReplyTos.iterator();
376        while ( replyTos.hasNext() ) {
377            m.addReplyTo( (AID)replyTos.next() );
378        }
379        
380        // content
381        if ( !m.hasByteSequenceContent() ) {
382            // wanted globalize method to be static, but was bit messy
383            // doubt object creation will be huge performance hit.
384            AclMsgCmp amc = new AclMsgCmp();
385            AID fooAID = new AID( "foo", false );
386            globalizeAID( fooAID );
387            String hap = fooAID.getHap();
388            String content = 
389                amc.globalizeContentAgentIds( m.getContent(), hap );
390            m.setContent( content );
391        }
392        
393    }
394    
395    /**
396     * run a testcase
397     */
398    private void injectMessage() throws Throwable {
399        // make sure local names turned into global
400        globalizeAgentIds( messageToInject );
401        logger.log( Logger.FINER,
402                "globalized ACLMessage to inject:"+messageToInject );
403        // send message
404        myAgent.send( messageToInject );
405        logger.log( Logger.FINER,
406                myAgent.getAID() + " sent " + messageToInject );
407    }
408 
409    // string, aidlist, and message comparator classes used for
410    // comparing and imposing an order on multiple messages, which
411    // is functionality not currently used.
412    
413//    /**
414//     * helper class for string sorting
415//     */
416//    class StringComparator implements Comparator {
417//        /** collator to use for string comparison */
418//        Collator collator = Collator.getInstance();
419//        /**
420//         * compare two strings
421//         * @param source left object to compare
422//         * @param target right object to compare
423//         * @return &lt;0 if 1st &gt;, 0 if equal, &gt;0 if 2nd &gt;
424//         * @throws ClassCastException if args aren't strings
425//         */
426//        public int compare( Object source, Object target ) {
427//            return collator.compare( (String)source,(String)target );
428//        }
429//    }
430//    
431//    /**
432//     * this helper class used to compare lists of AIDs.
433//     * Iterator is passed in for comparison rather than the list
434//     * itself. criterion is local part of each AID.
435//     */
436//    class AIDListComparator implements Comparator {
437//        /** comparator for strings */
438//        StringComparator stringComparator = new StringComparator();
439//        /**
440//         * compare two lists of AIDs
441//         * @param o1 the first object to be compared.
442//         * @param o2 the second object to be compared.
443//         * @return &lt;0 if 1st &gt;, 0 if equal, &gt;0 if 2nd &gt;
444//         * @throws ClassCastException if args aren't messages
445//         */
446//        public int compare( Object o1, Object o2 ) {
447//            int result = 0;
448//            // check for null arguments
449//            if ( ( null == o1 ) && ( null == o2 ) ) {
450//                result = 0;
451//            }
452//            else if ( ( null == o1 ) && ( null != o2 ) ) {
453//                result = -1;
454//            }
455//            else if ( ( null != o1 ) && ( null == o2 ) ) {
456//                result = 1;
457//            }
458//            else {
459//                // non-null arguments
460//                // translate list of AID to list of strings
461//                // of local names
462//                Iterator iter1 = (Iterator)o1;
463//                Iterator iter2 = (Iterator)o2;
464//                List list1 = new LinkedList();
465//                List list2 = new LinkedList();
466//                while ( iter1.hasNext() ) {
467//                    AID aid1 = (AID)iter1.next();
468//                    list1.add( aid1.getLocalName() );
469//                }
470//                while ( iter2.hasNext() ) {
471//                    AID aid2 = (AID)iter2.next();
472//                    list2.add( aid2.getLocalName() );
473//                }
474//                Collections.sort( list1 );
475//                Collections.sort( list2 );
476//                iter1 = list1.iterator();
477//                iter2 = list2.iterator();
478//                boolean done = false;
479//                while ( !done ) {
480//                    boolean hasNext1 = iter1.hasNext();
481//                    boolean hasNext2 = iter2.hasNext();
482//                    if ( !hasNext1 && !hasNext2 ) {
483//                        // ran off end of both lists
484//                        result = 0;
485//                        done = true;
486//                    }
487//                    else if ( !hasNext1 && hasNext2 ) {
488//                        // length mismatch
489//                        result = -1;
490//                        done = true;
491//                    }
492//                    else if ( hasNext1 && !hasNext2 ) {
493//                        // length mismatch
494//                        result = 1;
495//                        done = true;
496//                    }
497//                    else {
498//                        // compare strings at this point
499//                        result = stringComparator.compare( 
500//                                iter1.next(),
501//                                iter2.next() );
502//                        if ( 0 != result ) {
503//                            // found a difference
504//                            done = true;
505//                        }
506//                    }
507//                }
508//            }
509//            
510//            return result;
511//        }
512//    }
513//    
514//    /**
515//     * this helper class used to compare messages.
516//     * in descending order, criteria are:
517//     * <ol>
518//     * <li>local part of sender AID</li>
519//     * <li>sorted list of local part of receiver AIDs</li>
520//     * <li>message envelope date</li>
521//     * Assuming that no agent sends more than one message to the
522//     * same group of agents within a millisecond, this 
523//     * is a total ordering.
524//     * </ol>
525//     */
526//    class MessageComparator implements Comparator {
527//        /** comparator for strings */
528//        StringComparator stringComparator = 
529//            new StringComparator();
530//        /** comparator for list of AIDs */
531//        AIDListComparator aidListComparator =
532//            new AIDListComparator();
533//        /**
534//         * compare two messages
535//         * @param o1 the first object to be compared.
536//         * @param o2 the second object to be compared.
537//         * @return &lt;0 if 1st &lt;, 0 if =, &gt;0 if 1st &gt;
538//         * @throws ClassCastException if args aren't messages
539//         */
540//        public int compare( Object o1, Object o2 ) {
541//            int result;
542//            // check for null arguments
543//            if ( ( null == o1 ) && ( null == o2 ) ) {
544//                result = 0;
545//            }
546//            else if ( ( null == o1 ) && ( null != o2 ) ) {
547//                result = -1;
548//            }
549//            else if ( ( null != o1 ) && ( null == o2 ) ) {
550//                result = 1;
551//            }
552//            else {
553//                // non-null arguments
554//                ACLMessage m1 = (ACLMessage)o1;
555//                ACLMessage m2 = (ACLMessage)o2;
556//                AID sender1 = m1.getSender();
557//                AID sender2 = m2.getSender();
558//                // check for null senders
559//                if ( ( null == sender1 ) && ( null != sender2 ) ) {
560//                    result = -1;
561//                }
562//                else if ( ( null != sender1 ) && 
563//                        ( null == sender2 ) ) {
564//                    result = 1;
565//                }
566//                else {
567//                    // compare senders
568//                    if ( ( null == sender1 ) && 
569//                            ( null == sender2 ) ) {
570//                        result = 0;
571//                    }
572//                    else {
573//                        String localSender1 = sender1.getLocalName();
574//                        String localSender2 = sender2.getLocalName();
575//                        result =
576//                            stringComparator.compare( localSender1,
577//                                    localSender2 );
578//                    }
579//                    if ( 0 == result ) {
580//                        // equal senders, now check receivers
581//                        result = 
582//                            aidListComparator.compare( 
583//                                    m1.getAllReceiver(),
584//                                    m2.getAllReceiver() );
585//                        if ( 0 == result ) {
586//                            // equal receivers, now check time
587//                            Envelope e1 = m1.getEnvelope();
588//                            Envelope e2 = m2.getEnvelope();
589//                            if ( ( null == e1 ) && ( null == e2 ) ) {
590//                                result = 0;
591//                            }
592//                            else if ( ( null == e1 ) && 
593//                                    ( null != e2 ) ) {
594//                                result = -1;
595//                            }
596//                            else if ( ( null != e1 ) && 
597//                                    ( null == e2 ) ) {
598//                                result = 1;
599//                            }
600//                            else {
601//                                Date d1 = e1.getDate();
602//                                Date d2 = e2.getDate();
603//                                if ( ( null == d1 ) && 
604//                                        ( null == d2 ) ) {
605//                                    result = 0;
606//                                }
607//                                else if ( ( null == d1 ) && 
608//                                        ( null != d2 ) ) {
609//                                    result = -1;
610//                                }
611//                                else if ( ( null != d1 ) && 
612//                                        ( null == d2 ) ) {
613//                                    result = 1;
614//                                }
615//                                else {
616//                                    long longResult = 
617//                                        d1.getTime() - d2.getTime();
618//                                    if ( 0 == longResult ) {
619//                                        result = 0;
620//                                    }
621//                                    else if ( longResult < 0 ) {
622//                                        result = -1;
623//                                    }
624//                                    else if ( longResult > 0 ) {
625//                                        result = 1;
626//                                    }
627//                                    else {
628//                                        throw new RuntimeException(
629//                                        "unreachable");
630//                                    }
631//                                }
632//                            }
633//                        }
634//                    }
635//                }
636//            }
637//            
638//            return result;
639//        }
640//    }
641    
642    /** 
643     * A match expression on local part of sender and receivers.
644     * @author David Bernstein, <a href="http://www.caboodlenetworks.com"
645     *  >Caboodle Networks, Inc.</a>
646     */
647    private class SenderReceiverMatchExpression 
648      implements MessageTemplate.MatchExpression {
649        
650        /** local part of expected sender AID */
651        private String templateSender = null;
652        /** sorted list of local part of expected receiver AIDs */
653        private Object templateReceivers[] = null;
654        
655        /**
656         * construct match expression on local parts of sender and receiver
657         * @param templateMsg message to use as template
658         */
659        public SenderReceiverMatchExpression( ACLMessage templateMsg ) {
660            AID templateSenderAID = templateMsg.getSender();
661            if ( null != templateSenderAID ) {
662                templateSender = templateSenderAID.getLocalName();
663            }
664            jade.util.leap.Iterator rcvrI = templateMsg.getAllReceiver();
665            List templateReceiverList = new LinkedList();
666            while ( rcvrI.hasNext() ) {
667                templateReceiverList.add( ((AID)rcvrI.next()).getLocalName() );
668            }
669            templateReceivers = templateReceiverList.toArray();
670            Arrays.sort( templateReceivers );
671        }
672 
673        /* (non-Javadoc)
674         * @see jade.lang.acl.MessageTemplate$MatchExpression#match(
675         * jade.lang.acl.ACLMessage)
676         */
677        public boolean match(ACLMessage msg) {
678            boolean isMatch = true;
679 
680            // sender part
681            AID senderAID = msg.getSender();
682            String sender = null;
683            if ( null != senderAID ) {
684                sender = senderAID.getLocalName();
685            }
686            if ( ( ( null == templateSender ) && ( null != sender ) ) ||
687                 ( ( null != templateSender ) && ( null == sender ) ) ) {
688                isMatch = false;
689            }
690            else if ( ( null != templateSender ) && ( null != sender ) ) {
691                isMatch = sender.equals(templateSender);
692            }
693            
694            // receivers part
695            if ( isMatch ) {
696                List receiverList = new LinkedList();
697                jade.util.leap.Iterator rcvrI = msg.getAllReceiver();
698                while ( rcvrI.hasNext() ) {
699                    receiverList.add( ((AID)rcvrI.next()).getLocalName() );
700                }
701                if ( receiverList.size() != templateReceivers.length ) {
702                    isMatch = false;
703                }
704                else {
705                    Object receivers[] = receiverList.toArray();
706                    Arrays.sort( receivers );
707                    int receiverCount = receivers.length;
708                    for ( int i = 0; i < receiverCount; i++ ) {
709                        if ( !receivers[i].equals( templateReceivers[i])) {
710                            isMatch = false;
711                            break;
712                        }
713                    }
714                }
715            }
716            
717            return isMatch;
718        }
719        
720    }
721    
722    /**
723     * add AID for agent whose messages should be sniffed.
724     * take care not to add self or will drown in see of self-referential
725     * messages.
726     * @param aid AID of agent to be sniffed
727     */
728    private void addSniffedAgent( AID aid ) {
729        String localName = aid.getLocalName();
730        if ( !myAgent.getAID().getLocalName().equalsIgnoreCase( localName ) ) {
731            AID sniffedAgent = new AID( localName, AID.ISLOCALNAME );
732            sniffedAgents.add( sniffedAgent );
733            logger.log( Logger.FINER,"adding "+sniffedAgent.getName()+" to sniff");
734        }
735    }
736    
737 
738    /**
739     * convert local AID to ISGUID format
740     * @param aid AID to globalize
741     */
742    private void globalizeAID( AID aid ) {
743        if ( aid.getName().equals( aid.getLocalName() ) ) {
744            aid.setLocalName( aid.getName() );
745        }
746    }
747    
748    /** 
749     * this behaviour's action: inject message and see if get expected back
750     */
751    public void action() {
752 
753        switch ( state ) {
754            case STATE_INIT:
755                jademxAgent.setUnitTestActualMessage( null );
756                startSniffing();
757                state = ( ( null == failMsg ) ? STATE_INJECT : STATE_NOTIFY );
758                break;
759            case STATE_INJECT:
760                inject();
761                state = ( ( null == failMsg ) ? STATE_WAIT   : STATE_NOTIFY );
762                break;
763            case STATE_WAIT:
764                doSniff();
765                if ( ( null == failMsg ) && ( null == sniffedMessage ) ) {
766                    // check for timeout
767                    long nowMS = System.currentTimeMillis();
768                    if ( nowMS >= testcaseTimeoutMsAbs ) {
769                        failMsg = "test timeout after "+
770                          ( (nowMS-testcaseStartMsAbs) / 1000.0 ) + " seconds";
771                    }
772                }
773                if ( null != failMsg ) {
774                    state = STATE_NOTIFY;
775                }
776                else if ( null != sniffedMessage ) {
777                    jademxAgent.setUnitTestActualMessage( sniffedMessage );
778                    state = STATE_COMPARE;
779                }
780                else {
781                    // stay in STATE_WAIT
782                    block();
783                    logger.log( Logger.FINE,
784                            "blocking: matching msg not yet sniffed and "+
785                            "timeout not yet reached");
786                }
787 
788                break;
789            case STATE_COMPARE:
790                compare();
791                state = STATE_NOTIFY;
792                break;
793            case STATE_NOTIFY:
794                sendJmxNotification();
795                finished = true;
796                state = STATE_COMPLETE;
797                break;
798            case STATE_COMPLETE:
799                logger.warning("behaviour running even though complete");
800                break;
801            default:
802                throw new RuntimeException( 
803                        getClass().getName()+": unknown state "+state);
804        }
805        
806    }
807    
808    /**
809     * start sniffing
810     */
811    private void startSniffing() {
812        try {
813            setSniffing( true );
814        }
815        catch ( Throwable t ) {
816            failMsg = 
817                ThrowableUtil.errMsg( "problem starting sniffing", t );
818        }
819    }
820    
821    /**
822     * inject test message and set absolute testcase timeout
823     */
824    private void inject() {
825        // inject test message
826        try {
827            injectMessage();
828        }
829        catch ( Throwable t ) {
830            failMsg = 
831                ThrowableUtil.errMsg( "problem injecting test message", t );
832        }
833        // set testcase start and timeout
834        testcaseStartMsAbs = System.currentTimeMillis(); 
835        testcaseTimeoutMsAbs = 
836            testcaseStartMsAbs + testcaseTimeout.toMilliseconds();
837    }
838 
839    /** 
840     * do the sniffing until decide it's time to stop.
841     * criteria to stop listening for sniffed messages:
842     * <ol>
843     * <li>timeout for running this testcase</li>
844     * <li>seen message that matches pattern</li>
845     * </ol>
846     * @throws Exception on problem
847     */
848    private void doSniff() {
849        
850        // sniff messages look like:
851        //
852        //
853        // (INFORM
854        // :sender    ( agent-identifier 
855        //                :name tester-on-Main-Container@picturebook:1099/JADE  
856        //                :addresses (sequence http://picturebook:7778/acc ))
857        // :receiver  ( set 
858        //                ( agent-identifier 
859        //                    :name tester@picturebook:1099/JADE  
860        //            :addresses (sequence http://picturebook:7778/acc )) )
861        // :content  "(
862        //             (occurred 
863        //               (event-record 
864        //                 :what 
865        //                   (posted-message 
866        //                     :receiver 
867        //                        (agent-identifier 
868        //                          :name testee1@picturebook:1099/JADE 
869        //                          :addresses (sequence http://picturebook:7778/acc)) 
870        //                          :message (acl-message :payload \"
871        //    (REQUEST
872        //     :sender  ( agent-identifier :name testee2@picturebook:1099/JADE  
873        //                                 :addresses (sequence http://picturebook:7778/acc ))
874        //     :receiver  (set ( agent-identifier :name testee1@picturebook:1099/JADE ) )
875        //     :content  \\"?How are you testee1@picturebook:1099/JADE\\" 
876        //     :reply-with  msg1  
877        //     :in-reply-to  msg1  
878        //     :language  my-language  
879        //     :conversation-id  
880        //     scripted-conversation1 )\")) 
881        //                 :when 20040802T023026649Z 
882        //                 :where (container-ID :name Main-Container 
883        //                                      :address picturebook))))" 
884        // :language  fipa-sl0  
885        // :ontology  JADE-Introspection  
886        // :conversation-id  tester@picturebook:1099/JADE-event )
887        //
888        
889        // the occurred->event-record->:what can be one of:
890        // 1. sent-message
891        // 2. posted-message
892        // 3. received-message
893        // the injected message just causes the last two. 
894        // the real messages cause all three, so just look for
895        // the "sent-message" notifications to filter out
896        // the injected message.
897        
898        try {
899            ACLMessage matchedMessage = null;
900            // get next message matching event pattern
901            ACLMessage m = myAgent.receive( eventPattern );
902            if ( null == m ) {
903                // nothing currently available
904                logger.log( Logger.FINEST, "no message yet matches" );
905            }
906            else {
907                // got an event pattern message
908                logger.log( Logger.FINEST,"received message: "+m);
909                // decode the event pattern message
910                ContentElement ce = null; 
911                ce = myAgent.getContentManager().extractContent( m );
912                if ( ce instanceof Occurred ) {
913                    // it's an occurred notification
914                    Occurred occurred = (Occurred)ce;
915                    EventRecord eventRecord = occurred.getWhat();
916                    Event event = eventRecord.getWhat();
917                    jade.domain.introspection.ACLMessage 
918                    sniffedMessageAsContent = null;
919                    // take whichever shows up first
920                    // sent/posted/received should share a superclass...
921                    if ( event instanceof SentMessage ) {
922                        // it's a sent-message notification
923                        SentMessage sentMessage = (SentMessage)event;
924                        // now have a message that was sniffed, 
925                        // as content element
926                        sniffedMessageAsContent =
927                            sentMessage.getMessage();
928                    }
929                    else if ( event instanceof PostedMessage ) {
930                        // it's a posted-message notification
931                        PostedMessage postedMessage = (PostedMessage)event;
932                        // now have a message that was sniffed, 
933                        // as content element
934                        sniffedMessageAsContent =
935                            postedMessage.getMessage();
936                    }
937                    else if ( event instanceof ReceivedMessage ) {
938                        // it's a received-message notification
939                        ReceivedMessage receivedMessage = (ReceivedMessage)event;
940                        // now have a message that was sniffed, 
941                        // as content element
942                        sniffedMessageAsContent =
943                            receivedMessage.getMessage();
944                    }
945                    if ( null != sniffedMessageAsContent ) {
946                        logger.log( Logger.FINEST,
947                                "sniffed message as content:"+
948                                sniffedMessageAsContent);
949                        // cvt jade.domain.introspection.ACLMessage
950                        // to jade.lang.acl.ACLMessage
951                        String msgPayload = 
952                            sniffedMessageAsContent.getPayload();
953                        ACLMessage sniffedMessage = 
954                            AclMsgCmp.stringToMessage( msgPayload );
955                        // see if user pattern filters out this msg
956                        if ( matchSenderReceiverTemplate.match( sniffedMessage ) ) {
957                            // now sniffed msg that want to compare!
958                            logger.log( Logger.FINE,
959                                    "matching message:"+sniffedMessage);
960                            matchedMessage = sniffedMessage;
961                        }
962                    }
963                }
964            }
965            // set sniffed message to matched message, if any
966            sniffedMessage = matchedMessage;
967        }
968        catch ( Exception e ) {
969            failMsg = 
970                ThrowableUtil.errMsg( 
971                   "exception caught looking for matching sniffed message", e );
972        }
973        
974    }
975 
976    /**
977     * compare sniffed message (if any) with expected message.
978     * use agent mbean attributes to decide slots are significant.
979     */
980    private void compare() {
981        if ( null == sniffedMessage ) {
982            failMsg = 
983                "no message matching expected sender and receiver(s) seen";
984        }
985        else {
986            logger.log( Logger.FINER,"sniffed message:"+sniffedMessage);
987            AclMsgCmp aclMsgCmp = new AclMsgCmp();
988            aclMsgCmp.setCmpContent( jademxAgent.isUnitTestCmpContent() );
989            aclMsgCmp.setCmpConversationId( jademxAgent.isUnitTestCmpConversationId() );
990            aclMsgCmp.setCmpEncoding( jademxAgent.isUnitTestCmpEncoding() );
991            aclMsgCmp.setCmpEnvelope( jademxAgent.isUnitTestCmpEnvelope() );
992            aclMsgCmp.setCmpInReplyTo( jademxAgent.isUnitTestCmpInReplyTo() );
993            aclMsgCmp.setCmpLanguage( jademxAgent.isUnitTestCmpLanguage() );
994            aclMsgCmp.setCmpOntology( jademxAgent.isUnitTestCmpOntology() );
995            aclMsgCmp.setCmpPerformative( jademxAgent.isUnitTestCmpPerformative() );
996            aclMsgCmp.setCmpProtocol( jademxAgent.isUnitTestCmpProtocol() );
997            aclMsgCmp.setCmpReceiver( jademxAgent.isUnitTestCmpReceiver() );
998            aclMsgCmp.setCmpReplyBy( jademxAgent.isUnitTestCmpReplyBy() );
999            aclMsgCmp.setCmpReplyTo( jademxAgent.isUnitTestCmpReplyTo() );
1000            aclMsgCmp.setCmpReplyWith( jademxAgent.isUnitTestCmpReplyWith() );
1001            aclMsgCmp.setCmpSender( jademxAgent.isUnitTestCmpSender() );
1002            aclMsgCmp.setCmpUserProperties( jademxAgent.isUnitTestCmpUserProperties() );
1003            aclMsgCmp.setIgnoreContentAIDAddresses( jademxAgent.isUnitTestIgnoreContentAIDAddresses() );
1004            aclMsgCmp.setNewlinesNormalized( jademxAgent.isUnitTestNewlinesNormalized() );
1005            failMsg = aclMsgCmp.compare( 
1006                    expectedMessage, sniffedMessage, 
1007                    varProps );
1008        }
1009    }
1010    
1011    /**
1012     * stop sniffing if currently are
1013     */
1014    private void stopSniffing() {
1015        if ( sniffing ) {
1016            try {
1017                setSniffing( false );
1018            }
1019            catch ( Exception e ) {
1020                String err = "problem stopping sniffing";
1021                logger.log( Logger.WARNING, err, e );
1022                if ( null == failMsg ) {
1023                    failMsg = ThrowableUtil.errMsg( err, e );
1024                }
1025            }
1026        }
1027    }
1028    
1029    /**
1030     * send a unit testing success or failure JMX notification
1031     */
1032    private void sendJmxNotification() {
1033        // we always want to exit through here, so make sure sniffing off
1034        stopSniffing();
1035        // now generate and send notification
1036        String notifType;
1037        String notifMsg = null;
1038        logger.log( Logger.FINEST,"failure message:"+failMsg);
1039        if ( null == failMsg ) {
1040            notifType = JademxAgent.NOTIF_UNIT_TEST_SUCCESS_NAME;
1041        }
1042        else {
1043            notifType = JademxAgent.NOTIF_UNIT_TEST_FAILURE_NAME;
1044            notifMsg = failMsg;
1045        }
1046        jademxAgent.notifyListeners( notifType, notifMsg, null );
1047    }
1048    
1049    
1050    /* (non-Javadoc)
1051     * @see jade.core.behaviours.Behaviour#done()
1052     */
1053    public boolean done() {
1054        return finished;
1055    }
1056 
1057    
1058}

[all classes][jade.jademx.unit]
EMMA 2.0.5312 (C) Vladimir Roubtsov