diff options
| author | Martin Ritchie <ritchiem@apache.org> | 2007-07-31 15:53:37 +0000 |
|---|---|---|
| committer | Martin Ritchie <ritchiem@apache.org> | 2007-07-31 15:53:37 +0000 |
| commit | d38b1e9610db7b6b84c2830a004e7032b04b1a0b (patch) | |
| tree | ee8295a834c7ac296c57b8aeb67c4d9619e5d5b4 /java/systests/src | |
| parent | 81d0ea9cdc425348d19651eab8a6013a1e34ea39 (diff) | |
| download | qpid-python-d38b1e9610db7b6b84c2830a004e7032b04b1a0b.tar.gz | |
Merged revisions 1-447993,447995-448007,448009-448141,448143-448157,448161-448194,448196-448210,448212-448218,448220-448223,448225-448233,448235,448237-448241,448243-448596,448598-448623,448625-448850,448852-448880,448882-448982,448984-449635,449637-449639,449641-449642,449644-449645,449647-449674,449676-449719,449721-449749,449751-449762,449764-449933,449935-449941,449943-450383,450385,450387-450400,450402-450433,450435-450503,450505-450555,450557-450860,450862-451024,451026-451149,451151-451316,451318-451931,451933-452139,452141-452162,452164-452320,452322,452324-452325,452327-452333,452335-452429,452431-452528,452530-452545,452547-453192,453194-453195,453197-453536,453538,453540-453656,453658-454676,454678-454735,454737,454739-454781,454783-462728,462730-462819,462821-462833,462835-462839,462841-463071,463073-463178,463180-463308,463310-463362,463364-463375,463377-463396,463398-463402,463404-463409,463411-463661,463663-463670,463672-463673,463675-464493,464495-464502,464504-464576,464578-464613,464615-464628,464630,464632-464866,464868-464899,464901-464942,464944-464949,464951-465004,465006-465016,465018-465053,465055-465165,465167-465321,465323-465406,465408-465427,465429-465431,465433-465548,465550-466044,466047-466075,466077,466079-466081,466083-466099,466101-466112,466114-466126,466128-466240,466242-466971,466973-466978,466980-467309,467311-467312,467316-467328,467330-467485,467487-467588,467590-467604,467606-467699,467701-467706,467708-467749,467751-468069,468071-468537,468539-469241,469244-469246,469248-469318,469320-469421,469423,469425-469429,469431-469435,469437-469462,469464-469469,469472-469477,469479-469490,469492-469503,469505-469529,469531-469598,469600-469624,469626-469737,469739-469752,469754-469806,469808-469928,469930-469953,469955-470011,470013-470109,470111-470335,470338-470339,470341-470379,470381,470383-470399,470401-470446,470448-470741,470743-470758,470760-470809,470811-470817,470819-470993,470995-471001,471003-471788,471790-471792,471794-472028,472030-472032,472034-472036,472038,472040,472043,472045-472059,472061,472063,472065-472066,472068,472070-472072,472074-472080,472082,472084-472092,472094-472107,472109-472123,472125-472158,472160-472165,472167-472172,472174-472457,472459-472460,472462-472464,472466-472470,472472-472483,472486-472491,472493-472494,472496-472497,472499,472501-472503,472505-472512,472514-472544,472546-472556,472558-472560,472562-472572,472574-472587,472589-472591,472593-472605,472607,472609-472731,472733-472786,472788-472843,472845-472849,472851-472859,472861-472878,472880-472903,472905,472907-472988,472990-472991,472993-473071,473073-473086,473088-473090,473093,473095-473096,473098-473106,473108-473110,473112-473185,473187-473260,473262,473268-473270,473275-473279,473281,473284-473287,473289-473295,473297-473306,473308-473330,473332-473335,473337,473339-473344,473346-473351,473353-473355,473357-473358,473361-473471,473473-473497,473499-473535,473537-473567,473569-473888,473890-474451,474454-474492,474494-474563,474565-474843,474845-474865,474867-474932,474934-475035,475037-475144,475146-475180,475182-475265,475267-475285,475287,475289-475293,475295-475296,475298-475302,475304-475631,475633-475649,475651-475748,475750-475752,475754-476107,476109-476302,476304-476413,476415-476430,476432-476700,476702-476868,476870-477147,477149-477213,477215-477263,477265-477340,477342-477635,477637-477789,477791-477825,477827-477841,477843,477846-477852,477854,477856,477858-477865,477867-477894,477896-478022,478024-478182,478184-478211,478213-478233,478235-478236,478238-478241,478243-478252,478254-478259,478261-478263,478265,478267-478269,478271-478286,478288-478342,478344-478379,478381-478412,478414-478443,478445-478636,478639-478658,478660-478821,478823-478853,478855-478922,478924-478962,478965-478974,478976-479029,479031-479049,479051-479210,479212-479214,479216-479407,479409-479415,479417-479425,479427-479559,479561-479639,479641-479676,479678-479685,479687-480030,480033-480086,480091-480093,480095-480118,480120-480139,480141,480143-480148,480150-480156,480158-480163,480165-480177,480179-480189,480191-480193,480195-480198,480200-480220,480222-480282,480284-480292,480294-480308,480310-480317,480320-480422,480424,480426-480581,480583-480656,480658-480692,480695-480702,480704,480706-480710,480712-480910,480913-480933,480935-480945,480947-480972,480974-480993,480995-481034,481036-481158,481161-481174,481176-481220,481222-481234,481236-481260,481263-481264,481266-481296,481298-481304,481306-481311,481313-481332,481334,481336-481380,481382-481441,481443-482144,482146-482180,482182-482193,482195-482232,482234-482236,482239,482241-482242,482244-482247,482250-482251,482253,482256-482261,482264-482288,482290-482364,482366,482368,482370-482554,482556,482558-482569,482572-482636,482638,482640-482696,482698-482722,482724-482732,482734-482771,482774-482957,482959-483045,483047-483105,483108,483110-483115,483117,483119-483127,483130-483134,483136-483148,483150-483158,483160-483164,483166-483178,483180-483391,483393-483400,483402-483403,483405-483418,483420-483421,483425-483436,483438-483470,483472-483502,483504-483558,483560-483599,483601-483637,483639-483644,483646-483659,483661-483670,483672-483878,483880-483910,483912-483915,483917-483940,483942,483944-483968,483970-483972,483974-483976,483978,483980-484612,484614-484657,484659-484693,484695-484718,484720-484842,484844-484847,484849-484986,484988-485019,485021-485489,485491-485544,485546-485591,485593,485595-485697,485699-485729,485731-485734,485736-485779,485781-485787,485789-485851,485853,485855-486007,486009,486011-486020,486022-486083,486085-486097,486099-486117,486120-486131,486133-486148,486150-486161,486163-486164,486166-486197,486199-486205,486208-486247,486249-486253,486256-486427,486429-486431,486433-486554,486556-486573,486575-486593,486595,486597-486609,486611-486619,486622,486625,486627-486641,486643-486645,486649-486687,486689-486721,486723-486730,486732-486746,486748-486759,486761,486763-486777,486779-486782,486784-486788,486790,486792,486794-486796,486798-487175,487178,487180-487213,487215,487217-487267,487269-487284,487286-487298,487300-487358,487360-487367,487369-487382,487384-487434,487436-487480,487482-487547,487549-487561,487563-487565,487567-487578,487580-487615,487617-487622,487624,487626,487628,487630-487635,487637-487703,487705-487777,487780-487781,487783-487800,487802-487803,487805-487820,487822-487848,487850-487902,487904-488103,488105-488133,488135-488158,488160-488163,488165-488187,488189-488216,488218-488248,488250-488278,488280,488282-488303,488305-488313,488315-488342,488344-488351,488353-488376,488378-488449,488451-488593,488595,488597-488623,488625-488700,488702-488704,488706-488710,488714,488716-488725,488727-488744,488746-488770,488772-488798,488800,488802-488807,488809,488811-488829,488831-488843,488845-488851,488853-489069,489071-489077,489079-489081,489084-489102,489104-489105,489107-489109,489111-489112,489114-489139,489141-489178,489181-489203,489205-489211,489213,489216-489329,489332-489402,489404-489417,489419-489421,489423-489643,489645-489690,489692-489703,489705-489714,489716-489747,489749-489753,489755-489803,489805-489904,489906-490372,490374-490504,490506-490604,490606-490707,490710-490733,490735-490871,490873-490984,490986-491028,491030,491032-491071,491073-491119,491121-491576,491578-491672,491674-491800,491802-491838,491840-491878,491880-492183,492185-492279,492281-492317,492319-492513,492515-492584,492586-492587,492589-492601,492603-492635,492637-492640,492642-492717,492719-492723,492725-492729,492731-492755,492757-492901,492903-492955,492957-492962,492964-492997,492999-493002,493004-493041,493043-493059,493062-493063,493065-493086,493088-493125,493127-493139,493141-493150,493152-493871,493873-494017,494019-494030,494032-494041,494043-494091,494093-494120,494122-494354,494356-494436,494438-494539,494541-494552,494554-494586,494588-494649,494651,494653-494654,494656-494657,494659-494764,494766-494768,494770-494796,494798-494799,494802,494804-494860,494862-494903,494905-494906,494908-495019,495021-495160,495162-495168,495171-495188,495190-495229,495231-495254,495256-495303,495305-495313,495315-495336,495338-495372,495374-495379,495381-495454,495457-495459,495462-495516,495518-495524,495526-495531,495533-495548,495551-495553,495555,495557-495558,495560,495562-495573,495575-495583,495585-495594,495596-495628,495630-495638,495640-495651,495653-495660,495662-495753,495755-496259,496261-496262,496264-496269,496271-496275,496277-496301,496303-496316,496318-496383,496385-496413,496415-496495,496497-496625,496627-496636,496638-496640,496642-496647,496650-496657,496659-496660,496663-496664,496666-496677,496679-496681,496683-496730,496732-496750,496752,496754-496784,496786-496832,496834-496840,496842-496990,496992-496995,496997-497340,497343-497351,497353-497403,497405-497424,497426-497438,497440-497481,497483-497497,497499-497765,497767-497769,497771-497775,497777-497778,497780,497782-497783,497785,497787-497812,497814-497871,497873-497877,497879-498573,498575-498588,498590,498592,498594-498636,498638-498669,498671-498686,498688-498689,498691-498719,498721-498964,498966-498969,498971-498973,498975-498982,498985-499035,499037-499040,499042,499044-499048,499050-499082,499084-499086,499088-499164,499167-499169,499171-499355,499357-499370,499372-499373,499375-499391,499393,499395-499425,499428,499430-499445,499447-499455,499457-499460,499462-499465,499467,499469-499489,499491-499492,499494-499531,499533-499562,499566-499627,499629-499715,499717-499732,499734-499755,499758-499763,499765-499780,499782-499795,499797-499802,499804-499844,499846,499848-499850,499852-499863,499865-499873,499875-499974,499976-499978,499980-500263,500265-500283,500285-500309,500311-501000,501002,501012-501057,501059-501095,501097-501390,501392-501410,501413-501447,501449-501454,501456,501458-501464,501466-501471,501473-501803,501805-501913,501915-501916,501918-501919,501921-501944,501946-502171,502173-502177,502181,502183-502247,502250-502252,502254-502260,502262-502267,502270,502272,502274-502575,502577-502609,502611-502619,502621-502626,502628-502654,502656-503592,503594-503603,503605-503608,503610-503636,503638-503645,503647-503705,503707-503789,503791-504024,504026-504111,504113-504506,504508-504735,504737-504863,504865-504867,504869-504914,504916-505241,505243-505254,505257-505267,505269-505354,505356-505891,505893-505971,505973-506400,506402-506404,506407-506438,506440-506516,506518-506541,506543-506966,506968-506971,506973-507095,507097-507108,507111-507454,507456,507459-507471,507473-507556,507558,507560-507581,507585-507594,507597,507599-507608,507610-507728,507730-507893,507895-507937,507940-508234,508236-508350,508352-508365,508367-508380,508383,508386-508415,508417-508648,508650-508941,508943-509146,509148-509171,509173-509175,509179-509201,509203-509207,509209-509215,509217-509222,509224-509477,509480-509627,509629-509634,509636-509641,509643-509736,509738-509931,509933-510059,510061-510075,510077-510158,510161-510896,510898-510938,510940-511388,511390-511922,511924-512287,512289-512698,512702-512813,512815-512817,512819-513359,513361-513370,513372-514702,514704-514886,514888-514902,514904-515126,515129-515141,515143-515516,515518-515534,515536-515538,515540-515648,515650-515651,515653-516070,516072-516411,516413-516448,516450,516452-517637,517639-517647,517649-517659,517661-517663,517665-517677,517679-517682,517684-517744,517746-518085,518087-518175,518177-518558,518560-518568,518571-518666,518668,518670-518699,518701-518987,518990-518992,518994-519908,519910-519932,519934-520414,520416-520842,520844-520937,520939-521362,521364-521681,521683-521704,521706-521709,521711-521714,521716-521781,521783-521792,521794-522462,522464-522527,522529-522534,522536-522566,522568-522958,522960,522962-522966,522968-522976,522978-522980,522982-522988,522992-522993,522995-523244,523246-523746,523748-524049,524051-524738,524741-524742,524744-524762,524764,524766,524768-525486,525488-525530,525532,525534,525537-525552,525554-525765,525767-525776,525778-525784,525789-525803,525805-525816,525818-525828,525830-525861,525863-525866,525868-526090,526092-526112,526114-526116,526119-526121,526123-526149,526151-526153,526155-526156,526160-526165,526167-526186,526188-526193,526196-526197,526200-526665,526667-526682,526686-526690,526693,526695-526708,526710-526713,526715-526775,526777-526802,526804-526806,526808-527048,527051-527052,527054-527181,527183-527486,527488-527492,527494-527498,527500-527508,527510-527517,527519-527536,527538-527555,527559-527802,527804-527842,527844-527847,527849-527875,527877-527940,527942-527958,527960-527971,527973-528002,528004,528006-528423,528425-529232,529234-529245,529247-529296,529298-529634,529636-529658,529660-529665,529667-529668,529670-530033,530035-530036,530038-530040,530045-530046,530050-530051,530053-530431,530433-530436,530439-530440,530443,530445-530446,530448,530450-530682,530684,530687-530696,530698-530733,530735-530776,530778-530795,530799,530801-530811,530813-530818,530820-530837,530839-531436,531438-531455,531457,531459-531511,531514,531516,531519-531523,531525,531528-531858,531860-531864,531866-531907,531909-531916,531918-531936,531938-531988,531990-532001,532003-532371,532373-532465,532467-532727,532729-532765,532767-532785,532788-532790,532792-532793,532795-533064,533066-533074,533076,533080-533130,533132-533139,533142-533703,533705-533720,533722-533763,533766-533818,533820-533839,533841-533859,533862-534035,534037-534112,534114-534116,534118-534472,534474-534477,534479-534762,534764-534896,534898-534902,534904-535253,535255-535308,535310-535808,535810-535873,535875-536007,536009-536140,536142-536162,536165-536242,536244-536252,536254-536278,536280-536338,536340-536448,536450-536479,536481-536482,536484-536485,536487-536495,536497,536500-536505,536507-536561,536563-536570,536572,536574-536583,536586-536823,536825-537014,537016-537018,537020-537025,537027-537028,537030-537160,537162-537170,537172-537672,537674-537781,537783-537833,537836-537840,537842-537844,537846-537953,537955-538034,538036-538078,538080-538083,538085-538097,538099-538108,538110-538239,538241-538881,538883-538906,538908-538911,538913-538921,538923-539177,539179-539190,539192-539469,539471-539475,539477-539480,539482-539483,539485-539500,539502-539593,539595-539782,539784-539787,539789-540106,540108-540168,540170-540510,540512-541246,541248-542483,542485-542788,542790-543495,543497-544108,544110-544421,544423-544507,544509-544865,544867-545145,545147-546095,546097-546189,546191-546440,546442-546457,546459-547177,547179-547626,547628-548275,548277-548278,548280-548301,548303-548307,548309-548311,548313-548314,548316,548318,548320-548380,548382-549010,549012-549529,549531-549848,549850-550508,550510-550747,550749-550772,550774-550848,550850-551116,551122-553446,553448-561282 via svnmerge from
https://svn.apache.org/repos/asf/incubator/qpid/branches/M2
........
r541920 | tomasr | 2007-05-26 18:35:51 +0100 (Sat, 26 May 2007) | 1 line
QPID-136 Initial Prefetch Implementation
........
r549112 | arnaudsimon | 2007-06-20 15:11:03 +0100 (Wed, 20 Jun 2007) | 1 line
changed setText to use UTF8 as default encoder
........
r551167 | arnaudsimon | 2007-06-27 15:08:50 +0100 (Wed, 27 Jun 2007) | 1 line
added public void declareAndBind(AMQDestination amqd)
........
r551174 | ritchiem | 2007-06-27 15:23:21 +0100 (Wed, 27 Jun 2007) | 3 lines
Caused each of these tests to run 10 times to help identify any race conditions that were occuring.
Updated the CommitRollbackTest to be more robust in the detection of failure.
........
r551175 | ritchiem | 2007-06-27 15:23:52 +0100 (Wed, 27 Jun 2007) | 1 line
Allowed more of the constants to be set via system properties.
........
r551176 | ritchiem | 2007-06-27 15:25:13 +0100 (Wed, 27 Jun 2007) | 1 line
renamed the passwd programme qpid-passwd to match the change in bin directory.
........
r552441 | rupertlssmith | 2007-07-02 10:23:54 +0100 (Mon, 02 Jul 2007) | 1 line
Added log4j as slfj logger for perftests.
........
r552499 | rupertlssmith | 2007-07-02 15:17:45 +0100 (Mon, 02 Jul 2007) | 1 line
Added some documentation.
........
r553172 | rupertlssmith | 2007-07-04 12:11:04 +0100 (Wed, 04 Jul 2007) | 1 line
Messages moved by management console now commited on the message store.
........
r553248 | ritchiem | 2007-07-04 17:05:55 +0100 (Wed, 04 Jul 2007) | 6 lines
Addition of the MessageStore Tool.
Small changes to the Exchanges to allow the extraction of currently listed items.
Extracted initial broker configuration mechanism to a reusable class. Have modified broker to use it.
Move the Passwd.java to new tools package structure on the broker.
........
r553265 | ritchiem | 2007-07-04 17:42:59 +0100 (Wed, 04 Jul 2007) | 1 line
Tidied up some extranious logging.
........
r553432 | rupertlssmith | 2007-07-05 10:28:33 +0100 (Thu, 05 Jul 2007) | 1 line
Fixed test state carrying over to mandatory message test from immediate. Also added in-vm clean up to other tests.
........
r553480 | ritchiem | 2007-07-05 13:40:50 +0100 (Thu, 05 Jul 2007) | 2 lines
Minor changes and tidy up when running via command line.
Added Copy command.
........
r553482 | ritchiem | 2007-07-05 13:44:42 +0100 (Thu, 05 Jul 2007) | 2 lines
Forgot to compile before committing. Missed a method change in the Select command.
........
r554964 | rupertlssmith | 2007-07-10 15:40:04 +0100 (Tue, 10 Jul 2007) | 1 line
Added message copy method.
........
r555249 | rupertlssmith | 2007-07-11 12:52:39 +0100 (Wed, 11 Jul 2007) | 1 line
Update perftests to center better around current performance.
........
r556011 | rupertlssmith | 2007-07-13 15:24:03 +0100 (Fri, 13 Jul 2007) | 1 line
Moved test framework into its own package and cleaned it up.
........
r556024 | rupertlssmith | 2007-07-13 16:02:06 +0100 (Fri, 13 Jul 2007) | 1 line
Completed javadoc for test framework.
........
r556628 | rgodfrey | 2007-07-16 14:50:57 +0100 (Mon, 16 Jul 2007) | 1 line
QPID-537 : Make AMQMessage.incrementReference public
........
r556675 | cctrieloff | 2007-07-16 18:36:21 +0100 (Mon, 16 Jul 2007) | 2 lines
added notice entries
........
r556680 | cctrieloff | 2007-07-16 18:56:40 +0100 (Mon, 16 Jul 2007) | 2 lines
clean up
........
r556682 | cctrieloff | 2007-07-16 18:58:37 +0100 (Mon, 16 Jul 2007) | 2 lines
removed optional cppunit as not in distributed packages
........
r556845 | ritchiem | 2007-07-17 09:26:33 +0100 (Tue, 17 Jul 2007) | 3 lines
Additional logging in case of broker failure at startup.
Use broker logger at error level as well as System.out
........
r556847 | ritchiem | 2007-07-17 09:35:35 +0100 (Tue, 17 Jul 2007) | 3 lines
Update to the MessageStore Tool to provide Move and Purge functionality.
Updated to remove the AMQExceptions that will be removed from the Exchange class.
........
r556861 | ritchiem | 2007-07-17 10:26:47 +0100 (Tue, 17 Jul 2007) | 2 lines
QPID-538 Check to ensure a duplicate binding is not created.
........
r556868 | ritchiem | 2007-07-17 10:55:56 +0100 (Tue, 17 Jul 2007) | 1 line
Addition of simple pub/sub examples.
........
r556869 | ritchiem | 2007-07-17 10:56:17 +0100 (Tue, 17 Jul 2007) | 1 line
QPID-540 Prevent NPE when purging message from the main _message queue in the ConcurrentSelectorDeliveryManager that have been delivered via a Subscribers _messageQueue. Ensuring that any expired messages are still correctly handled. i.e. the Queue size/depth is reduced and the message correctly dequeued from the underlying store.
........
r556871 | ritchiem | 2007-07-17 10:57:35 +0100 (Tue, 17 Jul 2007) | 1 line
White space & code formatting change
........
r556872 | ritchiem | 2007-07-17 10:58:35 +0100 (Tue, 17 Jul 2007) | 3 lines
Added additional information to hard-error logging in exceptionReceived.
Fully expanded imports
........
r556888 | ritchiem | 2007-07-17 12:33:08 +0100 (Tue, 17 Jul 2007) | 1 line
Change to allow the management port to be specified on the command line, via -m or --mport
........
r556890 | ritchiem | 2007-07-17 12:38:10 +0100 (Tue, 17 Jul 2007) | 4 lines
QPID-541 A large portion of memory was being wasted in 32k ByteBuffers being held by the AMQShortStrings.
Patch submitted by Robert Godfrey to intern() the AMQSSs to reduce memory usage. Current implementation *will* impact performance due to the usage of a static Map for storage. However, a thread local implementation is in the works.
........
r556898 | rgodfrey | 2007-07-17 13:00:57 +0100 (Tue, 17 Jul 2007) | 1 line
QPID-541 : Change to use threadlocal maps for intern for the common case to avoid excessive synchronization. In the uncommon case will require more lookup.
........
r556958 | rupertlssmith | 2007-07-17 17:22:16 +0100 (Tue, 17 Jul 2007) | 1 line
Refactored the distributed test clients and coordinator to support different distribution and sequencing engines.
........
r556967 | rupertlssmith | 2007-07-17 17:40:14 +0100 (Tue, 17 Jul 2007) | 1 line
Removed unused package.
........
r556968 | rupertlssmith | 2007-07-17 17:42:00 +0100 (Tue, 17 Jul 2007) | 1 line
Retired old interop tests.
........
r556969 | rupertlssmith | 2007-07-17 17:43:49 +0100 (Tue, 17 Jul 2007) | 1 line
Properties file not needed any more. Test properties all driven from MessagingTestConfigProperties.
........
r557276 | ritchiem | 2007-07-18 15:36:11 +0100 (Wed, 18 Jul 2007) | 1 line
Updates to pom files and Licensing/Notice files for M2 release.
........
r557279 | ritchiem | 2007-07-18 15:51:42 +0100 (Wed, 18 Jul 2007) | 1 line
This is left over from ANT
........
r557281 | ritchiem | 2007-07-18 15:54:06 +0100 (Wed, 18 Jul 2007) | 1 line
updated comment to refelect property values
........
r557286 | ritchiem | 2007-07-18 16:02:22 +0100 (Wed, 18 Jul 2007) | 1 line
Set default mvn build to assembly:assembly
........
r557288 | ritchiem | 2007-07-18 16:09:07 +0100 (Wed, 18 Jul 2007) | 1 line
Ensure the top level release-docs directory is included in the builds
........
r557306 | ritchiem | 2007-07-18 17:01:58 +0100 (Wed, 18 Jul 2007) | 1 line
Update fix incorrect license headers.
........
r557312 | ritchiem | 2007-07-18 17:07:01 +0100 (Wed, 18 Jul 2007) | 1 line
added license
........
r557314 | ritchiem | 2007-07-18 17:11:17 +0100 (Wed, 18 Jul 2007) | 1 line
added license
........
r557452 | aconway | 2007-07-19 03:03:02 +0100 (Thu, 19 Jul 2007) | 14 lines
* lib/broker/Daemon.cpp, .h
- Rewrote to remove libdaemon dependency.
- PID file stored in /var/run if root, /tmp otherwise.
* src/qpidd.cpp: Use new Daemon.cpp.
- lock files stored in /var/run (for root) or /tmp.
- updated to trunk daemon flag behavior.
* lib/broker/Makefile.am (libqpidbroker_la_LIBADD):
- Daemon.cpp now needs -lboost_iostreams
* NOTICE, README: Removed mention of libdaemon.
........
r558027 | ritchiem | 2007-07-20 17:08:05 +0100 (Fri, 20 Jul 2007) | 1 line
Added a logger but only used to control the toString inclusion of password. If in debug mode it will include password otherwise the password is "********".
........
r558072 | astitcher | 2007-07-20 18:49:41 +0100 (Fri, 20 Jul 2007) | 2 lines
Fixed the license from the "old" apache copyright notice
........
r558083 | aconway | 2007-07-20 19:29:08 +0100 (Fri, 20 Jul 2007) | 2 lines
Remove -ldaemon, we no longer require libdaemon.
........
r558099 | aconway | 2007-07-20 20:20:01 +0100 (Fri, 20 Jul 2007) | 2 lines
Ignore QPID_ env variables that don't correspond to known options.
........
r558108 | cctrieloff | 2007-07-20 20:55:40 +0100 (Fri, 20 Jul 2007) | 2 lines
typo fix
........
r558114 | rajith | 2007-07-20 21:11:03 +0100 (Fri, 20 Jul 2007) | 1 line
added release notes
........
r558115 | rajith | 2007-07-20 21:12:20 +0100 (Fri, 20 Jul 2007) | 1 line
Checking in the release notes
........
r558116 | aconway | 2007-07-20 21:16:20 +0100 (Fri, 20 Jul 2007) | 3 lines
Removed .txt from RELEASE_NOTES
Added RELEASE_NOTES to EXTRA_DIST in Makefile.am
........
r558168 | rajith | 2007-07-20 23:03:42 +0100 (Fri, 20 Jul 2007) | 1 line
added release notes
........
r558170 | rajith | 2007-07-20 23:04:11 +0100 (Fri, 20 Jul 2007) | 1 line
added release notes
........
r558630 | gsim | 2007-07-23 08:21:49 +0100 (Mon, 23 Jul 2007) | 3 lines
Revised release notes: removed bug fixed on this branch, removed outstanding feature lists as it is not terribly accurate or helpful.
........
r559419 | rupertlssmith | 2007-07-25 13:17:59 +0100 (Wed, 25 Jul 2007) | 1 line
Refactored interop tests into general distributed test framework. Moved framework under systests from integrationtests.
........
r559427 | ritchiem | 2007-07-25 13:40:24 +0100 (Wed, 25 Jul 2007) | 2 lines
AMQMessage - added //todo-s and removed unused parameter StoreContext from expired() method call.
ConcurrentSelectorDeliveryManager - Update to reflect expired() call change. Created new _reaperContextStore to be used when performing reaper operations such as message dequeue due to expiration. Removed old commented code.
........
r559455 | rupertlssmith | 2007-07-25 14:40:16 +0100 (Wed, 25 Jul 2007) | 1 line
Added to comments.
........
r559456 | rupertlssmith | 2007-07-25 14:41:21 +0100 (Wed, 25 Jul 2007) | 1 line
Removed redundant method.
........
r559458 | rupertlssmith | 2007-07-25 14:57:21 +0100 (Wed, 25 Jul 2007) | 1 line
Refactored packaging of test framework.
........
r559461 | rupertlssmith | 2007-07-25 15:00:16 +0100 (Wed, 25 Jul 2007) | 1 line
Removed redundant packages.
........
r559943 | rhs | 2007-07-26 20:15:17 +0100 (Thu, 26 Jul 2007) | 1 line
adding missing ack
........
r559944 | rhs | 2007-07-26 20:15:44 +0100 (Thu, 26 Jul 2007) | 1 line
removed old script
........
r560198 | ritchiem | 2007-07-27 12:30:34 +0100 (Fri, 27 Jul 2007) | 1 line
Added files to ignore list
........
r560225 | ritchiem | 2007-07-27 14:33:50 +0100 (Fri, 27 Jul 2007) | 1 line
Converted namespaces from Qpid.* to Apache.Qpid.*
........
r560471 | tomasr | 2007-07-28 03:35:41 +0100 (Sat, 28 Jul 2007) | 1 line
Removed using directives causing compilation failure in .NET 1.1
........
r561278 | ritchiem | 2007-07-31 10:07:57 +0100 (Tue, 31 Jul 2007) | 8 lines
Changes to POMs.
Client pom now builds a single jar with all dependancies included in the single bundle.
systests/pom.xml adjusted to include only *Test.class items. This will fix the current Error on OptOutTestCase
management/eclipse-plugin/pom.xml - editied to include there required MANIFEST.MF to identify plugin to eclipse
distribution/src/main/assembly/management-eclipse-plugin.xml editied to include there required MANIFEST.MF to identify the plugin
distribution/pom.xml - white space
Also updated log4j.xml default to create an alert.log file from the AMQQueue alerting. Added a debug.log4j.xml that gives example of debugging the broker via log4j.
........
git-svn-id: https://svn.apache.org/repos/asf/incubator/qpid/trunk/qpid@561365 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'java/systests/src')
41 files changed, 5201 insertions, 952 deletions
diff --git a/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java b/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java index 20de0d5df0..370c2b43a7 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java +++ b/java/systests/src/main/java/org/apache/qpid/server/AMQBrokerManagerMBeanTest.java @@ -1,30 +1,34 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ package org.apache.qpid.server; import junit.framework.TestCase; + +import org.apache.qpid.framing.AMQShortString; import org.apache.qpid.server.exchange.ExchangeRegistry; import org.apache.qpid.server.management.ManagedBroker; import org.apache.qpid.server.queue.QueueRegistry; import org.apache.qpid.server.registry.ApplicationRegistry; import org.apache.qpid.server.registry.IApplicationRegistry; import org.apache.qpid.server.virtualhost.VirtualHost; -import org.apache.qpid.framing.AMQShortString; public class AMQBrokerManagerMBeanTest extends TestCase { @@ -33,9 +37,9 @@ public class AMQBrokerManagerMBeanTest extends TestCase public void testExchangeOperations() throws Exception { - String exchange1 = "testExchange1_" + System.currentTimeMillis(); - String exchange2 = "testExchange2_" + System.currentTimeMillis(); - String exchange3 = "testExchange3_" + System.currentTimeMillis(); + String exchange1 = "testExchange1_" + System.currentTimeMillis(); + String exchange2 = "testExchange2_" + System.currentTimeMillis(); + String exchange3 = "testExchange3_" + System.currentTimeMillis(); assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) == null); assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) == null); @@ -43,10 +47,10 @@ public class AMQBrokerManagerMBeanTest extends TestCase VirtualHost vHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"); - ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean)vHost.getManagedObject()); - mbean.createNewExchange(exchange1,"direct",false); - mbean.createNewExchange(exchange2,"topic",false); - mbean.createNewExchange(exchange3,"headers",false); + ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean) vHost.getManagedObject()); + mbean.createNewExchange(exchange1, "direct", false); + mbean.createNewExchange(exchange2, "topic", false); + mbean.createNewExchange(exchange3, "headers", false); assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange1)) != null); assertTrue(_exchangeRegistry.getExchange(new AMQShortString(exchange2)) != null); @@ -66,10 +70,10 @@ public class AMQBrokerManagerMBeanTest extends TestCase String queueName = "testQueue_" + System.currentTimeMillis(); VirtualHost vHost = ApplicationRegistry.getInstance().getVirtualHostRegistry().getVirtualHost("test"); - ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean)vHost.getManagedObject()); + ManagedBroker mbean = new AMQBrokerManagerMBean((VirtualHost.VirtualHostMBean) vHost.getManagedObject()); assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) == null); - + mbean.createNewQueue(queueName, "test", false); assertTrue(_queueRegistry.getQueue(new AMQShortString(queueName)) != null); @@ -82,7 +86,7 @@ public class AMQBrokerManagerMBeanTest extends TestCase { super.setUp(); IApplicationRegistry appRegistry = ApplicationRegistry.getInstance(); - _queueRegistry = appRegistry.getVirtualHostRegistry().getVirtualHost("test").getQueueRegistry(); + _queueRegistry = appRegistry.getVirtualHostRegistry().getVirtualHost("test").getQueueRegistry(); _exchangeRegistry = appRegistry.getVirtualHostRegistry().getVirtualHost("test").getExchangeRegistry(); } } diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java index 048fcfb0b3..4a0a27bb06 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java +++ b/java/systests/src/main/java/org/apache/qpid/server/exchange/ImmediateMessageTest.java @@ -20,34 +20,15 @@ */
package org.apache.qpid.server.exchange;
-import junit.framework.TestCase;
-
-import org.apache.log4j.NDC;
-
-import org.apache.qpid.client.AMQNoConsumersException;
-import org.apache.qpid.client.AMQNoRouteException;
-import org.apache.qpid.client.AMQSession;
-import org.apache.qpid.client.transport.TransportConnection;
-import static org.apache.qpid.server.exchange.MessagingTestConfigProperties.*;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.qpid.test.framework.sequencers.TestCaseSequencer;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
+import org.apache.qpid.test.framework.MessagingTestConfigProperties;
+import static org.apache.qpid.test.framework.MessagingTestConfigProperties.*;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
-import javax.jms.*;
-import javax.naming.Context;
-import javax.naming.InitialContext;
-import javax.naming.NamingException;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicLong;
-
/**
* ImmediateMessageTest tests for the desired behaviour of immediate messages. Immediate messages are a non-JMS
* feature. A message may be marked with an immediate delivery flag, which means that a consumer must be connected
@@ -58,60 +39,68 @@ import java.util.concurrent.atomic.AtomicLong; * <tr><th> Responsibilities <th> Collaborations
* <tr><td> Check that an immediate message is sent succesfully not using transactions when a consumer is connected.
* <tr><td> Check that an immediate message is committed succesfully in a transaction when a consumer is connected.
- * <tr><td> Check that an immediate message results in no consumers code, not using transactions, when no consumer is
+ * <tr><td> Check that an immediate message results in no consumers code, not using transactions, when a consumer is
+ * disconnected.
+ * <tr><td> Check that an immediate message results in no consumers code, in a transaction, when a consumer is
+ * disconnected.
+ * <tr><td> Check that an immediate message results in no route code, not using transactions, when no outgoing route is
* connected.
- * <tr><td> Check that an immediate message results in no consumers code, upon transaction commit, when a consumer is
+ * <tr><td> Check that an immediate message results in no route code, upon transaction commit, when no outgoing route is
* connected.
+ * <tr><td> Check that an immediate message is sent succesfully not using transactions when a consumer is connected.
+ * <tr><td> Check that an immediate message is committed succesfully in a transaction when a consumer is connected.
* <tr><td> Check that an immediate message results in no consumers code, not using transactions, when a consumer is
* disconnected.
- * <tr><dt> Check that an immediate message results in no consumers code, in a transaction, when a consumer is
+ * <tr><td> Check that an immediate message results in no consumers code, in a transaction, when a consumer is
* disconnected.
+ * <tr><td> Check that an immediate message results in no route code, not using transactions, when no outgoing route is
+ * connected.
+ * <tr><td> Check that an immediate message results in no route code, upon transaction commit, when no outgoing route is
+ * connected.
* </table>
*
- * @todo Write a test decorator, the sole function of which is to populate test context properties, from sys properties,
- * from trailing prop=value pairs on the command line, from test properties files or other sources. This should
- * run through stanard JUnit without the JUnit toolkit extensions, and through Maven surefire, and also through
- * the JUnit toolkit extended test runners.
- *
- * @todo Veto test topologies using bounce back. Or else the bounce back client will act as an immediate consumer.
+ * @todo All of these test cases will be generated by a test generator that thoroughly tests all combinations of test
+ * circuits.
*/
-public class ImmediateMessageTest extends TestCase
+public class ImmediateMessageTest extends FrameworkBaseCase
{
- /** Used for debugging. */
- private static final Logger log = LoggerFactory.getLogger(ImmediateMessageTest.class);
-
/** Used to read the tests configurable properties through. */
ParsedProperties testProps;
- /** Used to create unique destination names for each test.
- * @todo Move into the test framework.
+ /**
+ * Creates a new test case with the specified name.
+ *
+ * @param name The test case name.
*/
- private static AtomicLong uniqueDestsId = new AtomicLong();
+ public ImmediateMessageTest(String name)
+ {
+ super(name);
+ }
/** Check that an immediate message is sent succesfully not using transactions when a consumer is connected. */
- public void test_QPID_517_ImmediateOkNoTxP2P() throws Exception
+ public void test_QPID_517_ImmediateOkNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ // Run the default test sequence over the test circuit checking for no errors.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/** Check that an immediate message is committed succesfully in a transaction when a consumer is connected. */
- public void test_QPID_517_ImmediateOkTxP2P() throws Exception
+ public void test_QPID_517_ImmediateOkTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
-
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/** Check that an immediate message results in no consumers code, not using transactions, when a consumer is disconnected. */
@@ -121,13 +110,14 @@ public class ImmediateMessageTest extends TestCase testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoConsumersException.class);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noConsumersAssertion()), testProps);
}
/** Check that an immediate message results in no consumers code, in a transaction, when a consumer is disconnected. */
@@ -137,73 +127,74 @@ public class ImmediateMessageTest extends TestCase testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoConsumersException.class);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noConsumersAssertion()), testProps);
}
- /** Check that an immediate message results in no consumers code, not using transactions, when no consumer is connected. */
- public void test_QPID_517_ImmediateFailsNoRouteNoTxP2P() throws Exception
+ /** Check that an immediate message results in no route code, not using transactions, when no outgoing route is connected. */
+ public void test_QPID_517_ImmediateFailsNoRouteNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- // Set up the messaging topology so that only the publishers producer is bound (do not set up the receiver to
+ // Set up the messaging topology so that only the publishers producer is bound (do not set up the receivers to
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ // Send one message and get a linked no route exception.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
}
- /** Check that an immediate message results in no consumers code, upon transaction commit, when a consumer is connected. */
- public void test_QPID_517_ImmediateFailsNoRouteTxP2P() throws Exception
+ /** Check that an immediate message results in no route code, upon transaction commit, when no outgoing route is connected. */
+ public void test_QPID_517_ImmediateFailsNoRouteTxP2P()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- // Set up the messaging topology so that only the publishers producer is bound (do not set up the receiver to
+ // Set up the messaging topology so that only the publishers producer is bound (do not set up the receivers to
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ // Send one message and get a linked no route exception.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
}
/** Check that an immediate message is sent succesfully not using transactions when a consumer is connected. */
- public void test_QPID_517_ImmediateOkNoTxPubSub() throws Exception
+ public void test_QPID_517_ImmediateOkNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, true);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
-
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/** Check that an immediate message is committed succesfully in a transaction when a consumer is connected. */
- public void test_QPID_517_ImmediateOkTxPubSub() throws Exception
+ public void test_QPID_517_ImmediateOkTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, true);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
-
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/** Check that an immediate message results in no consumers code, not using transactions, when a consumer is disconnected. */
@@ -216,13 +207,14 @@ public class ImmediateMessageTest extends TestCase // Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoConsumersException.class);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noConsumersAssertion()), testProps);
}
/** Check that an immediate message results in no consumers code, in a transaction, when a consumer is disconnected. */
@@ -235,696 +227,61 @@ public class ImmediateMessageTest extends TestCase // Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoConsumersException.class);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noConsumersAssertion()), testProps);
}
- /** Check that an immediate message results in no consumers code, not using transactions, when no consumer is connected. */
- public void test_QPID_517_ImmediateFailsNoRouteNoTxPubSub() throws Exception
+ /** Check that an immediate message results in no route code, not using transactions, when no outgoing route is connected. */
+ public void test_QPID_517_ImmediateFailsNoRouteNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, true);
- // Set up the messaging topology so that only the publishers producer is bound (do not set up the receiver to
+ // Set up the messaging topology so that only the publishers producer is bound (do not set up the receivers to
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ // Send one message and get a linked no route exception.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
}
- /** Check that an immediate message results in no consumers code, upon transaction commit, when a consumer is connected. */
- public void test_QPID_517_ImmediateFailsNoRouteTxPubSub() throws Exception
+ /** Check that an immediate message results in no route code, upon transaction commit, when no outgoing route is connected. */
+ public void test_QPID_517_ImmediateFailsNoRouteTxPubSub()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, true);
- // Set up the messaging topology so that only the publishers producer is bound (do not set up the receiver to
+ // Set up the messaging topology so that only the publishers producer is bound (do not set up the receivers to
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- PublisherReceiver testClients = PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ // Send one message and get a linked no route exception.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
}
protected void setUp() throws Exception
{
- NDC.push(getName());
+ super.setUp();
testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
/** All these tests should have the immediate flag on. */
testProps.setProperty(IMMEDIATE_PROPNAME, true);
+ testProps.setProperty(MANDATORY_PROPNAME, false);
/** Bind the receivers consumer by default. */
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, true);
-
- // Ensure that the in-vm broker is created.
- TransportConnection.createVMBroker(1);
- }
-
- protected void tearDown() throws Exception
- {
- try
- {
- // Ensure that the in-vm broker is cleaned up so that the next test starts afresh.
- TransportConnection.killVMBroker(1);
- ApplicationRegistry.remove(1);
- }
- finally
- {
- NDC.pop();
- }
- }
-
- /*
- * Stuff below:
- *
- * This will get tidied into some sort on JMS convenience framework, through which practically any usefull test
- * topology can be created. This will become a replacement for PingPongProducer.
- *
- * Base everything on standard connection properties defined in PingPongProducer. Split JMS and AMQP-only properties.
- *
- * Integrate with ConversationFactory, so that it will work with prod/con pairs.
- *
- * Support pub/rec pairs.
- * Support m*n pub/rec setups. All pubs/recs on one machine.
- *
- * Support bounce back clients, with configurable bounce back behavior. All, one in X, round robin one in m, etc.
- *
- * Support pairing of m*n pub/rec setups with bounce back clients. JVM running a test, can simulate m publishers,
- * will receive (a known subset of) all messages sent, bounced back to n receivers. Co-location of pub/rec will be
- * the normal model to allow accurate timings to be taken.
- *
- * Support creation of pub or rec only.
- * Support clock synching of pub/rec on different JVMs, by calculating clock offsets. Must also provide an accuracy
- * estimate to +- the results.
- *
- * Augment the interop Coordinator, to become a full distributed test coordinator. Capable of querying available
- * tests machines, looking at test parameters and farming out tests onto the test machines, passing all test
- * parameters, standard naming of pub/rec config parameters used to set up m*n test topologies, run test cases,
- * report results, tear down m*n topologies. Need to split the re-usable general purpose distributed test coordinator
- * from the Qpid specific test framework for creating test-topoloigies and passing Qpid specific parameters.
- *
- * Write all tests against pub/rec pairs, without coding to the fact that the topology may be anything from 1:1 in
- * JVM to m*n with bounce back clients accross many machines. That is, make the test topology orthogonal to the test
- * case.
- */
-
- private static class ExceptionMonitor implements ExceptionListener
- {
- List<JMSException> exceptions = new ArrayList<JMSException>();
-
- public void onException(JMSException e)
- {
- log.debug("ExceptionMonitor got JMSException: ", e);
-
- exceptions.add(e);
- }
-
- public boolean assertNoExceptions()
- {
- return exceptions.isEmpty();
- }
-
- public boolean assertOneJMSException()
- {
- return exceptions.size() == 1;
- }
-
- public boolean assertOneJMSExceptionWithLinkedCause(Class aClass)
- {
- if (exceptions.size() == 1)
- {
- JMSException e = exceptions.get(0);
-
- Exception linkedCause = e.getLinkedException();
-
- if ((linkedCause != null) && aClass.isInstance(linkedCause))
- {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Reports the number of exceptions held by this monitor.
- *
- * @return The number of exceptions held by this monitor.
- */
- public int size()
- {
- return exceptions.size();
- }
-
- public void reset()
- {
- exceptions = new ArrayList();
- }
-
- /**
- * Provides a dump of the stack traces of all exceptions that this exception monitor was notified of. Mainly
- * use for debugging/test failure reporting purposes.
- *
- * @return A string containing a dump of the stack traces of all exceptions.
- */
- public String toString()
- {
- String result = "ExceptionMonitor: holds " + exceptions.size() + " exceptions.\n\n";
-
- for (JMSException ex : exceptions)
- {
- result += getStackTrace(ex) + "\n";
- }
-
- return result;
- }
-
- /**
- * Prints an exception stack trace into a string.
- *
- * @param t The throwable to get the stack trace from.
- *
- * @return A string containing the throwables stack trace.
- */
- public static String getStackTrace(Throwable t)
- {
- StringWriter sw = new StringWriter();
- PrintWriter pw = new PrintWriter(sw, true);
- t.printStackTrace(pw);
- pw.flush();
- sw.flush();
-
- return sw.toString();
- }
- }
-
- public static class MessageMonitor implements MessageListener
- {
- public void onMessage(Message message)
- {
- log.debug("public void onMessage(Message message): called");
- }
- }
-
- /**
- * Establishes a JMS connection using a properties file and qpids built in JNDI implementation. This is a simple
- * convenience method for code that does anticipate handling connection failures. All exceptions that indicate
- * that the connection has failed, are wrapped as rutime exceptions, preumably handled by a top level failure
- * handler.
- *
- * @param messagingProps Any additional connection properties.
- *
- * @return A JMS conneciton.
- *
- * @todo Move this to a Utils library class or base test class. Also move the copy in interop.TestClient too.
- *
- * @todo Make in VM broker creation step optional on whether one is to be used or not.
- */
- public static Connection createConnection(ParsedProperties messagingProps)
- {
- log.debug("public static Connection createConnection(Properties messagingProps = " + messagingProps + "): called");
-
- try
- {
- // Extract the configured connection properties from the test configuration.
- String conUsername = messagingProps.getProperty(USERNAME_PROPNAME);
- String conPassword = messagingProps.getProperty(PASSWORD_PROPNAME);
- String virtualHost = messagingProps.getProperty(VIRTUAL_HOST_PROPNAME);
- String brokerUrl = messagingProps.getProperty(BROKER_PROPNAME);
-
- // Set up the broker connection url.
- String connectionString =
- "amqp://" + conUsername + ":" + conPassword + "/" + ((virtualHost != null) ? virtualHost : "")
- + "?brokerlist='" + brokerUrl + "'";
-
- // messagingProps.setProperty(CONNECTION_PROPNAME, connectionString);
-
- Context ctx = new InitialContext(messagingProps);
-
- ConnectionFactory cf = (ConnectionFactory) ctx.lookup(CONNECTION_NAME);
- Connection connection = cf.createConnection();
-
- return connection;
- }
- catch (NamingException e)
- {
- log.debug("Got NamingException: ", e);
- throw new RuntimeException("Got JNDI NamingException whilst looking up the connection factory.", e);
- }
- catch (JMSException e)
- {
- log.debug("Got JMSException: ", e);
- throw new RuntimeException("Could not establish connection due to JMSException.", e);
- }
- }
-
- /**
- * Creates a publisher and a receiver on the same connection, configured according the to specified standard
- * properties.
- *
- * @param messagingProps The connection properties.
- *
- * @return A publisher/receiver client pair.
- */
- public static PublisherReceiver createPublisherReceiverPairSharedConnection(ParsedProperties messagingProps)
- {
- try
- {
- // Get a unique offset to append to destination names to make them unique to the connection.
- long uniqueId = uniqueDestsId.incrementAndGet();
-
- // Extract the standard test configuration parameters relevant to the connection.
- String destinationSendRoot = messagingProps.getProperty(SEND_DESTINATION_NAME_ROOT_PROPNAME) + "_" + uniqueId;
- String destinationReceiveRoot =
- messagingProps.getProperty(RECEIVE_DESTINATION_NAME_ROOT_PROPNAME) + "_" + uniqueId;
- boolean createPublisherProducer = messagingProps.getPropertyAsBoolean(PUBLISHER_PRODUCER_BIND_PROPNAME);
- boolean createPublisherConsumer = messagingProps.getPropertyAsBoolean(PUBLISHER_CONSUMER_BIND_PROPNAME);
- boolean createReceiverProducer = messagingProps.getPropertyAsBoolean(RECEIVER_PRODUCER_BIND_PROPNAME);
- boolean createReceiverConsumer = messagingProps.getPropertyAsBoolean(RECEIVER_CONSUMER_BIND_PROPNAME);
-
- // Check which JMS flags and options are to be set.
- int ackMode = messagingProps.getPropertyAsInteger(ACK_MODE_PROPNAME);
- boolean useTopics = messagingProps.getPropertyAsBoolean(PUBSUB_PROPNAME);
- boolean transactional = messagingProps.getPropertyAsBoolean(TRANSACTED_PROPNAME);
- boolean durableSubscription = messagingProps.getPropertyAsBoolean(DURABLE_SUBSCRIPTION_PROPNAME);
-
- // Check if any Qpid/AMQP specific flags or options need to be set.
- boolean immediate = messagingProps.getPropertyAsBoolean(IMMEDIATE_PROPNAME);
- boolean mandatory = messagingProps.getPropertyAsBoolean(MANDATORY_PROPNAME);
- boolean needsQpidOptions = immediate | mandatory;
-
- /*log.debug("ackMode = " + ackMode);
- log.debug("useTopics = " + useTopics);
- log.debug("destinationSendRoot = " + destinationSendRoot);
- log.debug("destinationReceiveRoot = " + destinationReceiveRoot);
- log.debug("createPublisherProducer = " + createPublisherProducer);
- log.debug("createPublisherConsumer = " + createPublisherConsumer);
- log.debug("createReceiverProducer = " + createReceiverProducer);
- log.debug("createReceiverConsumer = " + createReceiverConsumer);
- log.debug("transactional = " + transactional);
- log.debug("immediate = " + immediate);
- log.debug("mandatory = " + mandatory);
- log.debug("needsQpidOptions = " + needsQpidOptions);*/
-
- // Create connection, sessions and producer/consumer pairs on each session.
- Connection connection = createConnection(messagingProps);
-
- // Add the connection exception listener to assert on exception conditions with.
- ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
- connection.setExceptionListener(exceptionMonitor);
-
- Session publisherSession = connection.createSession(transactional, ackMode);
- Session receiverSession = connection.createSession(transactional, ackMode);
-
- Destination publisherProducerDestination =
- useTopics ? (Destination) publisherSession.createTopic(destinationSendRoot)
- : publisherSession.createQueue(destinationSendRoot);
-
- MessageProducer publisherProducer =
- createPublisherProducer
- ? (needsQpidOptions
- ? ((AMQSession) publisherSession).createProducer(publisherProducerDestination, mandatory, immediate)
- : publisherSession.createProducer(publisherProducerDestination)) : null;
-
- MessageConsumer publisherConsumer =
- createPublisherConsumer
- ? publisherSession.createConsumer(publisherSession.createQueue(destinationReceiveRoot)) : null;
-
- if (publisherConsumer != null)
- {
- publisherConsumer.setMessageListener(new MessageMonitor());
- }
-
- MessageProducer receiverProducer =
- createReceiverProducer ? receiverSession.createProducer(receiverSession.createQueue(destinationReceiveRoot))
- : null;
-
- Destination receiverConsumerDestination =
- useTopics ? (Destination) receiverSession.createTopic(destinationSendRoot)
- : receiverSession.createQueue(destinationSendRoot);
-
- MessageConsumer receiverConsumer =
- createReceiverConsumer
- ? ((durableSubscription && useTopics)
- ? receiverSession.createDurableSubscriber((Topic) receiverConsumerDestination, "testsub")
- : receiverSession.createConsumer(receiverConsumerDestination)) : null;
-
- if (receiverConsumer != null)
- {
- receiverConsumer.setMessageListener(new MessageMonitor());
- }
-
- // Start listening for incoming messages.
- connection.start();
-
- // Package everything up.
- ProducerConsumerPair publisher =
- new ProducerConsumerPairImpl(publisherProducer, publisherConsumer, publisherSession);
- ProducerConsumerPair receiver =
- new ProducerConsumerPairImpl(receiverProducer, receiverConsumer, receiverSession);
-
- PublisherReceiver result = new PublisherReceiverImpl(publisher, receiver, connection, exceptionMonitor);
-
- return result;
- }
- catch (JMSException e)
- {
- log.debug("Got JMSException: ", e);
- throw new RuntimeException("Could not create publisher/receiver pair due to a JMSException.", e);
- }
- }
-
- public static Message createTestMessage(ProducerConsumerPair client, ParsedProperties testProps) throws JMSException
- {
- return client.getSession().createTextMessage("Hello");
- // return client.getSession().createMessage();
- }
-
- /**
- * A ProducerConsumerPair is a pair consisting of one message producer and one message consumer. It is a standard
- * unit of connectivity allowing a full-duplex conversation to be held, provided both the consumer and producer
- * are instantiated and configured.
- *
- * In some situations a test, or piece of application code will be written with differing numbers of publishers
- * and receivers in different roles, where one role produces only and one consumes only. This messaging topology
- * can still make use of producer/consumer pairs as standard building blocks, combined into publisher/receiver
- * units to fulfill the different messaging roles, with the publishers consumer uninstantiated and the receivers
- * producer uninstantiated. Use a {@link PublisherReceiver} for this.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities
- * <tr><td> Provide a message producer for sending messages.
- * <tr><td> Provide a message consumer for receiving messages.
- * </table>
- *
- * @todo Update the {@link org.apache.qpid.util.ConversationFactory} so that it accepts these as the basic
- * conversation connection units.
- */
- public static interface ProducerConsumerPair
- {
- public MessageProducer getProducer();
-
- public MessageConsumer getConsumer();
-
- public void send(Message message) throws JMSException;
-
- public Session getSession();
-
- public void close() throws JMSException;
- }
-
- /**
- * A single producer and consumer.
- */
- public static class ProducerConsumerPairImpl implements ProducerConsumerPair
- {
- MessageProducer producer;
-
- MessageConsumer consumer;
-
- Session session;
-
- public ProducerConsumerPairImpl(MessageProducer producer, MessageConsumer consumer, Session session)
- {
- this.producer = producer;
- this.consumer = consumer;
- this.session = session;
- }
-
- public MessageProducer getProducer()
- {
- return producer;
- }
-
- public MessageConsumer getConsumer()
- {
- return consumer;
- }
-
- public void send(Message message) throws JMSException
- {
- producer.send(message);
- }
-
- public Session getSession()
- {
- return session;
- }
-
- public void close() throws JMSException
- {
- if (producer != null)
- {
- producer.close();
- }
-
- if (consumer != null)
- {
- consumer.close();
- }
- }
- }
-
- /**
- * Multiple producers and consumers made to look like a single producer and consumer. All methods repeated accross
- * all producers and consumers.
- */
- public static class MultiProducerConsumerPairImpl implements ProducerConsumerPair
- {
- public MessageProducer getProducer()
- {
- throw new RuntimeException("Not implemented.");
- }
-
- public MessageConsumer getConsumer()
- {
- throw new RuntimeException("Not implemented.");
- }
-
- public void send(Message message) throws JMSException
- {
- throw new RuntimeException("Not implemented.");
- }
-
- public Session getSession()
- {
- throw new RuntimeException("Not implemented.");
- }
-
- public void close()
- {
- throw new RuntimeException("Not implemented.");
- }
- }
-
- /**
- * A PublisherReceiver consists of two sets of producer/consumer pairs, one for an 'instigating' publisher
- * role, and one for a more 'passive' receiver role.
- *
- * <p/>A set of publishers and receivers forms a typical test configuration where both roles are to be controlled
- * from within a single JVM. This is not a particularly usefull arrangement for applications which want to place
- * these roles on physically seperate machines and pass messages between them. It is a faily normal arrangement for
- * test code though, either to publish and receive messages through an in-VM message broker in order to test its
- * expected behaviour, or to publish and receive (possibly bounced back) messages through a seperate broker instance
- * in order to take performance timings. In the case of performance timings, the co-location of the publisher and
- * receiver means that the timings are taken on the same machine for accurate timing without the need for clock
- * synchronization.
- *
- * <p/><table id="crc"><caption>CRC Card</caption>
- * <tr><th> Responsibilities
- * <tr><td> Manage an m*n array of publisher and recievers.
- * </table>
- */
- public static interface PublisherReceiver
- {
- public ProducerConsumerPair getPublisher();
-
- public ProducerConsumerPair getReceiver();
-
- public void start();
-
- public void send(ParsedProperties testProps, int numMessages);
-
- public ExceptionMonitor getConnectionExceptionMonitor();
-
- public ExceptionMonitor getExceptionMonitor();
-
- public void testWithAssertions(ParsedProperties testProps, Class aClass /*, assertions */);
-
- public void testNoExceptions(ParsedProperties testProps);
-
- public void close();
- }
-
- public static class PublisherReceiverImpl implements PublisherReceiver
- {
- private ProducerConsumerPair publisher;
- private ProducerConsumerPair receiver;
- private Connection connection;
- private ExceptionMonitor connectionExceptionMonitor;
- private ExceptionMonitor exceptionMonitor;
-
- public PublisherReceiverImpl(ProducerConsumerPair publisher, ProducerConsumerPair receiver, Connection connection,
- ExceptionMonitor connectionExceptionMonitor)
- {
- this.publisher = publisher;
- this.receiver = receiver;
- this.connection = connection;
- this.connectionExceptionMonitor = connectionExceptionMonitor;
- this.exceptionMonitor = new ExceptionMonitor();
- }
-
- public ProducerConsumerPair getPublisher()
- {
- return publisher;
- }
-
- public ProducerConsumerPair getReceiver()
- {
- return receiver;
- }
-
- public void start()
- { }
-
- public void close()
- {
- try
- {
- publisher.close();
- receiver.close();
- connection.close();
- }
- catch (JMSException e)
- {
- throw new RuntimeException("Got JMSException during close.", e);
- }
- }
-
- public ExceptionMonitor getConnectionExceptionMonitor()
- {
- return connectionExceptionMonitor;
- }
-
- public ExceptionMonitor getExceptionMonitor()
- {
- return exceptionMonitor;
- }
-
- public void send(ParsedProperties testProps, int numMessages)
- {
- boolean transactional = testProps.getPropertyAsBoolean(TRANSACTED_PROPNAME);
-
- // Send an immediate message through the publisher and ensure that it results in a JMSException.
- try
- {
- getPublisher().send(createTestMessage(getPublisher(), testProps));
-
- if (transactional)
- {
- getPublisher().getSession().commit();
- }
- }
- catch (JMSException e)
- {
- log.debug("Got JMSException: ", e);
- exceptionMonitor.onException(e);
- }
- }
-
- public void testWithAssertions(ParsedProperties testProps, Class aClass /*, assertions */)
- {
- start();
- send(testProps, 1);
- pause(1000L);
-
- String errors = "";
-
- ExceptionMonitor connectionExceptionMonitor = getConnectionExceptionMonitor();
- if (!connectionExceptionMonitor.assertOneJMSExceptionWithLinkedCause(aClass))
- {
- errors += "Was expecting linked exception type " + aClass.getName() + " on the connection.\n";
- errors +=
- (connectionExceptionMonitor.size() > 0)
- ? ("Actually got the following exceptions on the connection, " + connectionExceptionMonitor)
- : "Got no exceptions on the connection.";
- }
-
- // Clean up the publisher/receiver client pair.
- close();
-
- assertEquals(errors, "", errors);
- }
-
- /**
- */
- public void testNoExceptions(ParsedProperties testProps)
- {
- start();
- send(testProps, 1);
- pause(1000L);
-
- String errors = "";
-
- if (!getConnectionExceptionMonitor().assertNoExceptions())
- {
- errors += "Was expecting no exceptions.\n";
- errors += "Got the following exceptions on the connection, " + getConnectionExceptionMonitor();
- }
-
- if (!getExceptionMonitor().assertNoExceptions())
- {
- errors += "Was expecting no exceptions.\n";
- errors += "Got the following exceptions on the producer, " + getExceptionMonitor();
- }
-
- // Clean up the publisher/receiver client pair.
- close();
-
- assertEquals(errors, "", errors);
- }
-
- public static PublisherReceiver connectClients(ParsedProperties testProps)
- {
- // Create a standard publisher/receiver test client pair on a shared connection, individual sessions.
- return createPublisherReceiverPairSharedConnection(testProps);
- }
- }
-
- /**
- * Pauses for the specified length of time. In the event of failing to pause for at least that length of time
- * due to interuption of the thread, a RutimeException is raised to indicate the failure. The interupted status
- * of the thread is restores in that case. This method should only be used when it is expected that the pause
- * will be succesfull, for example in test code that relies on inejecting a pause.
- *
- * @param t The minimum time to pause for in milliseconds.
- */
- public static void pause(long t)
- {
- try
- {
- Thread.sleep(t);
- }
- catch (InterruptedException e)
- {
- // Restore the interrupted status
- Thread.currentThread().interrupt();
-
- throw new RuntimeException("Failed to generate the requested pause length.", e);
- }
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java index 09a32aa3eb..94a33806d0 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java +++ b/java/systests/src/main/java/org/apache/qpid/server/exchange/MandatoryMessageTest.java @@ -20,17 +20,11 @@ */
package org.apache.qpid.server.exchange;
-import junit.framework.TestCase;
-
-import org.apache.log4j.NDC;
-
-import org.apache.qpid.client.AMQNoRouteException;
-import org.apache.qpid.client.transport.TransportConnection;
-import static org.apache.qpid.server.exchange.MessagingTestConfigProperties.*;
-import org.apache.qpid.server.registry.ApplicationRegistry;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.qpid.test.framework.sequencers.TestCaseSequencer;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
+import org.apache.qpid.test.framework.MessagingTestConfigProperties;
+import static org.apache.qpid.test.framework.MessagingTestConfigProperties.*;
import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
@@ -43,52 +37,70 @@ import uk.co.thebadgerset.junit.extensions.util.TestContextProperties; *
* <p><table id="crc"><caption>CRC Card</caption>
* <tr><th> Responsibilities <th> Collaborations
- * <tr><td> Check that a mandatory message is sent succesfully not using transactions when a consumer is connected.
- * <tr><td> Check that a mandatory message is committed succesfully in a transaction when a consumer is connected.
- * <tr><td> Check that a mandatory message results in no route code, not using transactions, when no consumer is
+ * <tr><td> Check that an mandatory message is sent succesfully not using transactions when a consumer is connected.
+ * <tr><td> Check that an mandatory message is committed succesfully in a transaction when a consumer is connected.
+ * <tr><td> Check that a mandatory message is sent succesfully, not using transactions, when a consumer is disconnected
+ * but the route exists.
+ * <tr><td> Check that a mandatory message is sent succesfully, in a transaction, when a consumer is disconnected but
+ * the route exists.
+ * <tr><td> Check that an mandatory message results in no route code, not using transactions, when no consumer is
+ * connected.
+ * <tr><td> Check that an mandatory message results in no route code, upon transaction commit, when a consumer is
* connected.
- * <tr><td> Check that a mandatory message results in no route code, upon transaction commit, when a consumer is
+ * <tr><td> Check that an mandatory message is sent succesfully not using transactions when a consumer is connected.
+ * <tr><td> Check that an mandatory message is committed succesfully in a transaction when a consumer is connected.
+ * <tr><td> Check that a mandatory message is sent succesfully, not using transactions, when a consumer is disconnected
+ * but the route exists.
+ * <tr><td> Check that a mandatory message is sent succesfully, in a transaction, when a consumer is disconnected but
+ * the route exists.
+ * <tr><td> Check that an mandatory message results in no route code, not using transactions, when no consumer is
+ * connected.
+ * <tr><td> Check that an mandatory message results in no route code, upon transaction commit, when a consumer is
* connected.
- * <tr><td> Check that a mandatory message is sent succesfully, not using transactions, when a consumer is
- * disconnected but the route exists.
- * <tr><dt> Check that a mandatory message is send successfully, in a transactions, when a consumer is
- * disconnected but when the route exists.
* </table>
+ *
+ * @todo All of these test cases will be generated by a test generator that thoroughly tests all combinations of test
+ * circuits.
*/
-public class MandatoryMessageTest extends TestCase
+public class MandatoryMessageTest extends FrameworkBaseCase
{
- /** Used for debugging. */
- private static final Logger log = LoggerFactory.getLogger(MandatoryMessageTest.class);
-
/** Used to read the tests configurable properties through. */
ParsedProperties testProps;
+ /**
+ * Creates a new test case with the specified name.
+ *
+ * @param name The test case name.
+ */
+ public MandatoryMessageTest(String name)
+ {
+ super(name);
+ }
+
/** Check that an mandatory message is sent succesfully not using transactions when a consumer is connected. */
- public void test_QPID_508_MandatoryOkNoTxP2P() throws Exception
+ public void test_QPID_508_MandatoryOkNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ // Run the default test sequence over the test circuit checking for no errors.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/** Check that an mandatory message is committed succesfully in a transaction when a consumer is connected. */
- public void test_QPID_508_MandatoryOkTxP2P() throws Exception
+ public void test_QPID_508_MandatoryOkTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ // Run the default test sequence over the test circuit checking for no errors.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/**
@@ -101,14 +113,14 @@ public class MandatoryMessageTest extends TestCase testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/**
@@ -121,78 +133,74 @@ public class MandatoryMessageTest extends TestCase testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/** Check that an mandatory message results in no route code, not using transactions, when no consumer is connected. */
- public void test_QPID_508_MandatoryFailsNoRouteNoTxP2P() throws Exception
+ public void test_QPID_508_MandatoryFailsNoRouteNoTxP2P()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, false);
- // Set up the messaging topology so that only the publishers producer is bound (do not set up the receiver to
+ // Set up the messaging topology so that only the publishers producer is bound (do not set up the receivers to
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ // Send one message and get a linked no route exception.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
}
/** Check that an mandatory message results in no route code, upon transaction commit, when a consumer is connected. */
- public void test_QPID_508_MandatoryFailsNoRouteTxP2P() throws Exception
+ public void test_QPID_508_MandatoryFailsNoRouteTxP2P()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, false);
- // Set up the messaging topology so that only the publishers producer is bound (do not set up the receiver to
+ // Set up the messaging topology so that only the publishers producer is bound (do not set up the receivers to
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ // Send one message and get a linked no route exception.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
}
/** Check that an mandatory message is sent succesfully not using transactions when a consumer is connected. */
- public void test_QPID_508_MandatoryOkNoTxPubSub() throws Exception
+ public void test_QPID_508_MandatoryOkNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, true);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ // Run the default test sequence over the test circuit checking for no errors.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/** Check that an mandatory message is committed succesfully in a transaction when a consumer is connected. */
- public void test_QPID_508_MandatoryOkTxPubSub() throws Exception
+ public void test_QPID_508_MandatoryOkTxPubSub()
{
- // Ensure transactional sessions are off.
+ // Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, true);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ // Run the default test sequence over the test circuit checking for no errors.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/**
@@ -208,14 +216,14 @@ public class MandatoryMessageTest extends TestCase // Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/**
@@ -231,79 +239,61 @@ public class MandatoryMessageTest extends TestCase // Use durable subscriptions, so that the route remains open with no subscribers.
testProps.setProperty(DURABLE_SUBSCRIPTION_PROPNAME, true);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
// Disconnect the consumer.
- testClients.getReceiver().getConsumer().close();
+ testCircuit.getReceiver().getConsumer().close();
// Send one message with no errors.
- testClients.testNoExceptions(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noExceptionsAssertion()), testProps);
}
/** Check that an mandatory message results in no route code, not using transactions, when no consumer is connected. */
- public void test_QPID_508_MandatoryFailsNoRouteNoTxPubSub() throws Exception
+ public void test_QPID_508_MandatoryFailsNoRouteNoTxPubSub()
{
// Ensure transactional sessions are off.
testProps.setProperty(TRANSACTED_PROPNAME, false);
testProps.setProperty(PUBSUB_PROPNAME, true);
- // Set up the messaging topology so that only the publishers producer is bound (do not set up the receiver to
+ // Set up the messaging topology so that only the publishers producer is bound (do not set up the receivers to
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ // Send one message and get a linked no route exception.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
}
/** Check that an mandatory message results in no route code, upon transaction commit, when a consumer is connected. */
- public void test_QPID_508_MandatoryFailsNoRouteTxPubSub() throws Exception
+ public void test_QPID_508_MandatoryFailsNoRouteTxPubSub()
{
// Ensure transactional sessions are on.
testProps.setProperty(TRANSACTED_PROPNAME, true);
testProps.setProperty(PUBSUB_PROPNAME, true);
- // Set up the messaging topology so that only the publishers producer is bound (do not set up the receiver to
+ // Set up the messaging topology so that only the publishers producer is bound (do not set up the receivers to
// collect its messages).
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, false);
- ImmediateMessageTest.PublisherReceiver testClients =
- ImmediateMessageTest.PublisherReceiverImpl.connectClients(testProps);
-
- // Send one message and get a linked no consumers exception.
- testClients.testWithAssertions(testProps, AMQNoRouteException.class);
+ // Send one message and get a linked no route exception.
+ TestCaseSequencer sequencer = getTestSequencer();
+ Circuit testCircuit = sequencer.createCircuit(testProps);
+ sequencer.sequenceTest(testCircuit, assertionList(testCircuit.getPublisher().noRouteAssertion()), testProps);
}
protected void setUp() throws Exception
{
- NDC.push(getName());
+ super.setUp();
testProps = TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
/** All these tests should have the mandatory flag on. */
+ testProps.setProperty(IMMEDIATE_PROPNAME, false);
testProps.setProperty(MANDATORY_PROPNAME, true);
/** Bind the receivers consumer by default. */
testProps.setProperty(RECEIVER_CONSUMER_BIND_PROPNAME, true);
-
- // Ensure that the in-vm broker is created.
- TransportConnection.createVMBroker(1);
- }
-
- protected void tearDown() throws Exception
- {
- try
- {
- // Ensure that the in-vm broker is cleaned up so that the next test starts afresh.
- TransportConnection.killVMBroker(1);
- ApplicationRegistry.remove(1);
- }
- finally
- {
- NDC.pop();
- }
}
}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java b/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java index a6a2bbb80f..191f38f1b2 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java +++ b/java/systests/src/main/java/org/apache/qpid/server/exchange/ReturnUnroutableMandatoryMessageTest.java @@ -126,8 +126,8 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex con.start();
TextMessage tm = (TextMessage) consumer.receive(1000L);
- assertTrue("No message routed to receiver", tm != null);
- assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg3".equals(tm.getText()));
+ assertTrue("No message routed to receivers", tm != null);
+ assertTrue("Wrong message routed to receivers: " + tm.getText(), "msg3".equals(tm.getText()));
try
{
@@ -193,8 +193,8 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex con.start();
TextMessage tm = (TextMessage) consumer.receive(1000L);
- assertTrue("No message routed to receiver", tm != null);
- assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg1".equals(tm.getText()));
+ assertTrue("No message routed to receivers", tm != null);
+ assertTrue("Wrong message routed to receivers: " + tm.getText(), "msg1".equals(tm.getText()));
try
{
@@ -259,8 +259,8 @@ public class ReturnUnroutableMandatoryMessageTest extends TestCase implements Ex con.start();
TextMessage tm = (TextMessage) consumer.receive(1000L);
- assertTrue("No message routed to receiver", tm != null);
- assertTrue("Wrong message routed to receiver: " + tm.getText(), "msg1".equals(tm.getText()));
+ assertTrue("No message routed to receivers", tm != null);
+ assertTrue("Wrong message routed to receivers: " + tm.getText(), "msg1".equals(tm.getText()));
try
{
diff --git a/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java b/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java index 6f14956cc4..14d45807dd 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java +++ b/java/systests/src/main/java/org/apache/qpid/server/protocol/AMQProtocolSessionMBeanTest.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ package org.apache.qpid.server.protocol; diff --git a/java/systests/src/main/java/org/apache/qpid/server/protocol/MaxChannelsTest.java b/java/systests/src/main/java/org/apache/qpid/server/protocol/MaxChannelsTest.java index dc1f592679..b507bee16e 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/protocol/MaxChannelsTest.java +++ b/java/systests/src/main/java/org/apache/qpid/server/protocol/MaxChannelsTest.java @@ -1,18 +1,21 @@ /* * - * Copyright (c) 2006 The Apache Software Foundation + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * */ package org.apache.qpid.server.protocol; diff --git a/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java b/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java index 5abbbd2aae..d01284cb8a 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java +++ b/java/systests/src/main/java/org/apache/qpid/server/queue/PersistentTestManual.java @@ -1,39 +1,41 @@ /* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. * - * */ package org.apache.qpid.server.queue; -import org.apache.qpid.client.AMQConnection; -import org.apache.qpid.client.AMQSession; -import org.apache.qpid.AMQException; +import org.apache.log4j.Logger; + import org.apache.qpid.AMQChannelClosedException; import org.apache.qpid.AMQConnectionClosedException; -import org.apache.qpid.util.CommandLineParser; +import org.apache.qpid.AMQException; +import org.apache.qpid.client.AMQConnection; +import org.apache.qpid.client.AMQSession; import org.apache.qpid.url.URLSyntaxException; -import org.apache.log4j.Logger; +import org.apache.qpid.util.CommandLineParser; -import javax.jms.Session; import javax.jms.JMSException; -import javax.jms.Queue; import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; import javax.jms.TextMessage; + import java.io.IOException; import java.util.Properties; @@ -41,7 +43,6 @@ public class PersistentTestManual { private static final Logger _logger = Logger.getLogger(PersistentTestManual.class); - private static final String QUEUE = "direct://amq.direct//PersistentTest-Queue2?durable='true',exclusive='true'"; protected AMQConnection _connection; @@ -89,7 +90,7 @@ public class PersistentTestManual public void test() throws AMQException, URLSyntaxException { - //Create the Durable Queue + // Create the Durable Queue try { _session.createConsumer(_session.createQueue(QUEUE)).close(); @@ -121,16 +122,17 @@ public class PersistentTestManual System.out.println("Continuing...."); } - //Test queue is still there. - AMQConnection connection = new AMQConnection(_brokerDetails, _username, _password, "DifferentClientID", _virtualpath); + // Test queue is still there. + AMQConnection connection = + new AMQConnection(_brokerDetails, _username, _password, "DifferentClientID", _virtualpath); AMQSession session = (AMQSession) connection.createSession(false, Session.AUTO_ACKNOWLEDGE); try { session.createConsumer(session.createQueue(QUEUE)); - _logger.error("Create consumer succeeded." + - " This shouldn't be allowed as this means the queue didn't exist when it should"); + _logger.error("Create consumer succeeded." + + " This shouldn't be allowed as this means the queue didn't exist when it should"); connection.close(); @@ -189,6 +191,7 @@ public class PersistentTestManual { // } + System.exit(0); } @@ -196,7 +199,7 @@ public class PersistentTestManual { String TEST_TEXT = "init"; - //Create a new session to send producer + // Create a new session to send producer Session session = _connection.createSession(false, Session.AUTO_ACKNOWLEDGE); Queue q = session.createQueue(QUEUE); @@ -204,10 +207,9 @@ public class PersistentTestManual producer.send(session.createTextMessage(TEST_TEXT)); - //create a new consumer on the original session + // create a new consumer on the original session TextMessage m = (TextMessage) _session.createConsumer(q).receive(); - if ((m != null) && m.getText().equals(TEST_TEXT)) { return true; @@ -216,6 +218,7 @@ public class PersistentTestManual { _logger.error("Incorrect values returned from Queue Test:" + m); System.exit(0); + return false; } } @@ -259,8 +262,8 @@ public class PersistentTestManual { PersistentTestManual test; - Properties options = CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][]{})); - + Properties options = + CommandLineParser.processCommandLine(args, new CommandLineParser(new String[][] {}), System.getProperties()); test = new PersistentTestManual(options); try diff --git a/java/systests/src/main/java/org/apache/qpid/test/VMTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/VMTestCase.java index 540c91ddaf..9629f87d46 100644 --- a/java/systests/src/main/java/org/apache/qpid/test/VMTestCase.java +++ b/java/systests/src/main/java/org/apache/qpid/test/VMTestCase.java @@ -1,4 +1,5 @@ /* + * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -20,29 +21,32 @@ package org.apache.qpid.test; import junit.extensions.TestSetup; + import junit.framework.Test; import junit.framework.TestCase; import org.apache.qpid.client.transport.TransportConnection; import org.apache.qpid.jndi.PropertiesFileInitialContextFactory; +import org.apache.qpid.server.registry.ApplicationRegistry; -import javax.naming.Context; -import javax.naming.spi.InitialContextFactory; -import javax.jms.Queue; -import javax.jms.ConnectionFactory; -import javax.jms.Session; import javax.jms.Connection; +import javax.jms.ConnectionFactory; import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.Session; +import javax.naming.Context; +import javax.naming.spi.InitialContextFactory; + +import java.util.HashMap; import java.util.Hashtable; -import java.util.List; import java.util.LinkedList; +import java.util.List; import java.util.Map; -import java.util.HashMap; public class VMTestCase extends TestCase { - protected long RECEIVE_TIMEOUT = 1000l; // 1 sec - protected long CLOSE_TIMEOUT = 10000l; // 10 secs + protected long RECEIVE_TIMEOUT = 1000L; // 1 sec + protected long CLOSE_TIMEOUT = 10000L; // 10 secs protected Context _context; protected String _clientID; @@ -84,8 +88,8 @@ public class VMTestCase extends TestCase _brokerlist = "vm://:1"; } - env.put("connectionfactory.connection", "amqp://guest:guest@" + - _clientID + _virtualhost + "?brokerlist='" + _brokerlist + "'"); + env.put("connectionfactory.connection", "amqp://guest:guest@" + _clientID + _virtualhost + "?brokerlist='" + + _brokerlist + "'"); for (Map.Entry<String, String> c : _connections.entrySet()) { @@ -112,6 +116,8 @@ public class VMTestCase extends TestCase protected void tearDown() throws Exception { TransportConnection.killVMBroker(1); + ApplicationRegistry.remove(1); + super.tearDown(); } diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/Assertion.java b/java/systests/src/main/java/org/apache/qpid/test/framework/Assertion.java new file mode 100644 index 0000000000..75c1c97999 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/Assertion.java @@ -0,0 +1,39 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+/**
+ * Assertion models an assertion on a test {@link Circuit}.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Indicate whether or not the assertion passes when applied.
+ * </table>
+ */
+public interface Assertion
+{
+ /**
+ * Applies the assertion.
+ *
+ * @return <tt>true</tt> if the assertion passes, <tt>false</tt> if it fails.
+ */
+ public boolean apply();
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/AssertionBase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/AssertionBase.java new file mode 100644 index 0000000000..3d83224513 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/AssertionBase.java @@ -0,0 +1,66 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * AssertionBase is a base class for implenmenting assertions. It provides a mechanism to store error messages, and
+ * report all error messages when its {@link #toString()} method is called.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Collect error messages.
+ * </table>
+ */
+public abstract class AssertionBase implements Assertion
+{
+ /** Holds the error messages. */
+ List<String> errors = new LinkedList<String>();
+
+ /**
+ * Adds an error message to the assertion.
+ *
+ * @param error An error message to add to the assertion.
+ */
+ public void addError(String error)
+ {
+ errors.add(error);
+ }
+
+ /**
+ * Prints all of the error messages in the assertion into a string.
+ *
+ * @return All of the error messages in the assertion as a string.
+ */
+ public String toString()
+ {
+ String result = "";
+
+ for (String error : errors)
+ {
+ result += error;
+ }
+
+ return result;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/Circuit.java b/java/systests/src/main/java/org/apache/qpid/test/framework/Circuit.java new file mode 100644 index 0000000000..d665acb62c --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/Circuit.java @@ -0,0 +1,109 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import java.util.List;
+
+/**
+ * A Circuit is the basic test unit against which test cases are to be written. A circuit consists of two 'ends', an
+ * instigating 'publisher' end and a more passive 'receivers' end.
+ *
+ * <p/>Once created, the life-cycle of a circuit may be controlled by {@link #start()}ing it, or {@link #close()}ing it.
+ * Once started, the circuit is ready to send messages over. Once closed the circuit can no longer be used.
+ *
+ * <p/>The state of the circuit may be taken with the {@link #check()} method, and asserted against by the
+ * {@link #applyAssertions(java.util.List)} method.
+ *
+ * <p/>There is a default test procedure which may be performed against the circuit. The outline of this procedure is:
+ *
+ * <p/><pre>
+ * Start the circuit.
+ * Send test messages.
+ * Request a status report.
+ * Assert conditions on the publishing end of the circuit.
+ * Assert conditions on the receiving end of the circuit.
+ * Close the circuit.
+ * Pass with no failed assertions or fail with a list of failed assertions.
+ * </pre>
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
+ * <tr><td> Start the circuit running.
+ * <tr><td> Close the circuit down.
+ * <tr><td> Take a reading of the circuits state.
+ * <tr><td> Apply assertions against the circuits state.
+ * <tr><td> Send test messages over the circuit.
+ * <tr><td> Perform the default test procedue on the circuit.
+ * </table>
+ */
+public interface Circuit
+{
+ /**
+ * Gets the interface on the publishing end of the circuit.
+ *
+ * @return The publishing end of the circuit.
+ */
+ public Publisher getPublisher();
+
+ /**
+ * Gets the interface on the receiving end of the circuit.
+ *
+ * @return The receiving end of the circuit.
+ */
+ public Receiver getReceiver();
+
+ /**
+ * Connects and starts the circuit. After this method is called the circuit is ready to send messages.
+ */
+ public void start();
+
+ /**
+ * Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
+ * into a report, against which assertions may be checked.
+ */
+ public void check();
+
+ /**
+ * Closes the circuit. All associated resources are closed.
+ */
+ public void close();
+
+ /**
+ * Applied a list of assertions against the test circuit. The {@link #check()} method should be called before doing
+ * this, to ensure that the circuit has gathered its state into a report to assert against.
+ *
+ * @param assertions The list of assertions to apply to the circuit.
+ *
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> applyAssertions(List<Assertion> assertions);
+
+ /**
+ * Runs the default test procedure against the circuit, and checks that all of the specified assertions hold.
+ *
+ * @param numMessages The number of messages to send using the default test procedure.
+ * @param assertions The list of assertions to apply.
+ *
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> test(int numMessages, List<Assertion> assertions);
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java new file mode 100644 index 0000000000..43c3fa4c66 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEnd.java @@ -0,0 +1,77 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import javax.jms.*;
+
+/**
+ * A CircuitEnd is a pair consisting of one message producer and one message consumer, that represents one end of a
+ * test circuit. It is a standard unit of connectivity allowing a full-duplex conversation to be held, provided both
+ * the consumer and producer are instantiated and configured.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Provide a message producer for sending messages.
+ * <tr><td> Provide a message consumer for receiving messages.
+ * </table>
+ *
+ * @todo Update the {@link org.apache.qpid.util.ConversationFactory} so that it accepts these as the basic conversation
+ * connection units.
+ */
+public interface CircuitEnd
+{
+ /**
+ * Gets the message producer at this circuit end point.
+ *
+ * @return The message producer at with this circuit end point.
+ */
+ public MessageProducer getProducer();
+
+ /**
+ * Gets the message consumer at this circuit end point.
+ *
+ * @return The message consumer at this circuit end point.
+ */
+ public MessageConsumer getConsumer();
+
+ /**
+ * Send the specified message over the producer at this end point.
+ *
+ * @param message The message to send.
+ *
+ * @throws JMSException Any JMS exception occuring during the send is allowed to fall through.
+ */
+ public void send(Message message) throws JMSException;
+
+ /**
+ * Gets the JMS Session associated with this circuit end point.
+ *
+ * @return The JMS Session associated with this circuit end point.
+ */
+ public Session getSession();
+
+ /**
+ * Closes the message producers and consumers and the sessions, associated with this circuit end point.
+ *
+ * @throws JMSException Any JMSExceptions occurring during the close are allowed to fall through.
+ */
+ public void close() throws JMSException;
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java new file mode 100644 index 0000000000..54a30d9c6e --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/CircuitEndBase.java @@ -0,0 +1,119 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import javax.jms.*;
+
+/**
+ * A CircuitEndBase is a pair consisting of one message producer and one message consumer, that represents one end of a
+ * test circuit. It is a standard unit of connectivity allowing a full-duplex conversation to be held, provided both
+ * the consumer and producer are instantiated and configured.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Provide a message producer for sending messages.
+ * <tr><td> Provide a message consumer for receiving messages.
+ * </table>
+ */
+public class CircuitEndBase implements CircuitEnd
+{
+ /** Holds the single message producer. */
+ MessageProducer producer;
+
+ /** Holds the single message consumer. */
+ MessageConsumer consumer;
+
+ /** Holds the session for the circuit end. */
+ Session session;
+
+ /**
+ * Creates a circuit end point on the specified producer, consumer and session.
+ *
+ * @param producer The message producer for the circuit end point.
+ * @param consumer The message consumer for the circuit end point.
+ * @param session The session for the circuit end point.
+ */
+ public CircuitEndBase(MessageProducer producer, MessageConsumer consumer, Session session)
+ {
+ this.producer = producer;
+ this.consumer = consumer;
+ this.session = session;
+ }
+
+ /**
+ * Gets the message producer at this circuit end point.
+ *
+ * @return The message producer at with this circuit end point.
+ */
+ public MessageProducer getProducer()
+ {
+ return producer;
+ }
+
+ /**
+ * Gets the message consumer at this circuit end point.
+ *
+ * @return The message consumer at this circuit end point.
+ */
+ public MessageConsumer getConsumer()
+ {
+ return consumer;
+ }
+
+ /**
+ * Send the specified message over the producer at this end point.
+ *
+ * @param message The message to send.
+ * @throws javax.jms.JMSException Any JMS exception occuring during the send is allowed to fall through.
+ */
+ public void send(Message message) throws JMSException
+ {
+ producer.send(message);
+ }
+
+ /**
+ * Gets the JMS Session associated with this circuit end point.
+ *
+ * @return The JMS Session associated with this circuit end point.
+ */
+ public Session getSession()
+ {
+ return session;
+ }
+
+ /**
+ * Closes the message producers and consumers and the sessions, associated with this circuit end point.
+ *
+ * @throws javax.jms.JMSException Any JMSExceptions occurring during the close are allowed to fall through.
+ */
+ public void close() throws JMSException
+ {
+ if (producer != null)
+ {
+ producer.close();
+ }
+
+ if (consumer != null)
+ {
+ consumer.close();
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/DropInTest.java b/java/systests/src/main/java/org/apache/qpid/test/framework/DropInTest.java new file mode 100644 index 0000000000..12cf0d79d5 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/DropInTest.java @@ -0,0 +1,51 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+/**
+ * A DropIn test is a test case that can accept late joining test clients into a running test. This can be usefull,
+ * for interactive experimentation.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Accept late joining test clients.
+ * </table>
+ */
+public interface DropInTest
+{
+ /**
+ * Should accept a late joining client into a running test case. The client will be enlisted with a control message
+ * with the 'CONTROL_TYPE' field set to the value 'LATEJOIN'. It should also provide values for the fields:
+ *
+ * <p/><table>
+ * <tr><td> CLIENT_NAME <td> A unique name for the new client.
+ * <tr><td> CLIENT_PRIVATE_CONTROL_KEY <td> The key for the route on which the client receives its control messages.
+ * </table>
+ *
+ * @param message The late joiners join message.
+ *
+ * @throws JMSException Any JMS Exception are allowed to fall through, indicating that the join failed.
+ */
+ public void lateJoin(Message message) throws JMSException;
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java b/java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java new file mode 100644 index 0000000000..606f2eabda --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/ExceptionMonitor.java @@ -0,0 +1,151 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import javax.jms.ExceptionListener;
+import javax.jms.JMSException;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * An exception monitor, listens for JMS exception on a connection or consumer. It record all exceptions that it receives
+ * and provides methods to test the number and type of exceptions received.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Record all exceptions received. <td> {@link ExceptionListener}
+ * </table>
+ */
+public class ExceptionMonitor implements ExceptionListener
+{
+ /** Holds the received exceptions. */
+ List<JMSException> exceptions = new ArrayList<JMSException>();
+
+ /**
+ * Receives incoming exceptions.
+ *
+ * @param e The exception to record.
+ */
+ public void onException(JMSException e)
+ {
+ exceptions.add(e);
+ }
+
+ /**
+ * Checks that no exceptions have been received.
+ *
+ * @return <tt>true</tt> if no exceptions have been received, <tt>false</tt> otherwise.
+ */
+ public boolean assertNoExceptions()
+ {
+ return exceptions.isEmpty();
+ }
+
+ /**
+ * Checks that exactly one exception has been received.
+ *
+ * @return <tt>true</tt> if exactly one exception been received, <tt>false</tt> otherwise.
+ */
+ public boolean assertOneJMSException()
+ {
+ return exceptions.size() == 1;
+ }
+
+ /**
+ * Checks that exactly one exception, with a linked cause of the specified type, has been received.
+ *
+ * @return <tt>true</tt> if exactly one exception, with a linked cause of the specified type, been received,
+ * <tt>false</tt> otherwise.
+ */
+ public boolean assertOneJMSExceptionWithLinkedCause(Class aClass)
+ {
+ if (exceptions.size() == 1)
+ {
+ JMSException e = exceptions.get(0);
+
+ Exception linkedCause = e.getLinkedException();
+
+ if ((linkedCause != null) && aClass.isInstance(linkedCause))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Reports the number of exceptions held by this monitor.
+ *
+ * @return The number of exceptions held by this monitor.
+ */
+ public int size()
+ {
+ return exceptions.size();
+ }
+
+ /**
+ * Clears the record of received exceptions.
+ */
+ public void reset()
+ {
+ exceptions = new ArrayList();
+ }
+
+ /**
+ * Provides a dump of the stack traces of all exceptions that this exception monitor was notified of. Mainly
+ * use for debugging/test failure reporting purposes.
+ *
+ * @return A string containing a dump of the stack traces of all exceptions.
+ */
+ public String toString()
+ {
+ String result = "ExceptionMonitor: holds " + exceptions.size() + " exceptions.\n\n";
+
+ for (JMSException ex : exceptions)
+ {
+ result += getStackTrace(ex) + "\n";
+ }
+
+ return result;
+ }
+
+ /**
+ * Prints an exception stack trace into a string.
+ *
+ * @param t The throwable to get the stack trace from.
+ *
+ * @return A string containing the throwables stack trace.
+ */
+ public static String getStackTrace(Throwable t)
+ {
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw, true);
+ t.printStackTrace(pw);
+ pw.flush();
+ sw.flush();
+
+ return sw.toString();
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java new file mode 100644 index 0000000000..d6cb0cad13 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/FrameworkBaseCase.java @@ -0,0 +1,207 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import junit.framework.TestCase;
+
+import org.apache.log4j.NDC;
+
+import org.apache.qpid.client.transport.TransportConnection;
+import org.apache.qpid.test.framework.sequencers.TestCaseSequencer;
+import org.apache.qpid.server.registry.ApplicationRegistry;
+import org.apache.qpid.test.framework.localcircuit.CircuitImpl;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * FrameworkBaseCase provides a starting point for writing test cases against the test framework. Its main purpose is
+ * to provide some convenience methods for testing.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Create and clean up in-vm brokers on every test case.
+ * <tr><td> Produce lists of assertions from assertion creation calls.
+ * <tr><td> Produce JUnit failures from assertion failures.
+ * <tr><td> Convert failed assertions to error messages.
+ * </table>
+ */
+public class FrameworkBaseCase extends TestCase
+{
+ /** Holds the test sequencer to create and run test circuits with. */
+ protected TestCaseSequencer testSequencer = new DefaultTestSequencer();
+
+ /**
+ * Creates a new test case with the specified name.
+ *
+ * @param name The test case name.
+ */
+ public FrameworkBaseCase(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Returns the test case sequencer that provides test circuit, and test sequence implementations. The sequencer
+ * that this base case returns by default is suitable for running a test circuit with both circuit ends colocated
+ * on the same JVM.
+ *
+ * @return The test case sequencer.
+ */
+ protected TestCaseSequencer getTestSequencer()
+ {
+ return testSequencer;
+ }
+
+ /**
+ * Overrides the default test sequencer. Test decorators can use this to supply distributed test sequencers or other
+ * test sequencer specializations.
+ *
+ * @param sequencer The new test sequencer.
+ */
+ public void setTestSequencer(TestCaseSequencer sequencer)
+ {
+ this.testSequencer = sequencer;
+ }
+
+ /**
+ * Creates a list of assertions.
+ *
+ * @param asserts The assertions to compile in a list.
+ *
+ * @return A list of assertions.
+ */
+ protected List<Assertion> assertionList(Assertion... asserts)
+ {
+ List<Assertion> result = new ArrayList<Assertion>();
+
+ for (Assertion assertion : asserts)
+ {
+ result.add(assertion);
+ }
+
+ return result;
+ }
+
+ /**
+ * Generates a JUnit assertion exception (failure) if any assertions are passed into this method, also concatenating
+ * all of the error messages in the assertions together to form an error message to diagnose the test failure with.
+ *
+ * @param asserts The list of failed assertions.
+ */
+ protected void assertNoFailures(List<Assertion> asserts)
+ {
+ // Check if there are no assertion failures, and return without doing anything if so.
+ if ((asserts == null) || asserts.isEmpty())
+ {
+ return;
+ }
+
+ // Compile all of the assertion failure messages together.
+ String errorMessage = assertionsToString(asserts);
+
+ // Fail with the error message from all of the assertions.
+ fail(errorMessage);
+ }
+
+ /**
+ * Converts a list of failed assertions into an error message.
+ *
+ * @param asserts The failed assertions.
+ *
+ * @return The error message.
+ */
+ protected String assertionsToString(List<Assertion> asserts)
+ {
+ String errorMessage = "";
+
+ for (Assertion assertion : asserts)
+ {
+ errorMessage += assertion.toString() + "\n";
+ }
+
+ return errorMessage;
+ }
+
+ /**
+ * Ensures that the in-vm broker is created and initialized.
+ *
+ * @throws Exception Any exceptions allowed to fall through and fail the test.
+ */
+ protected void setUp() throws Exception
+ {
+ NDC.push(getName());
+
+ // Ensure that the in-vm broker is created.
+ TransportConnection.createVMBroker(1);
+ }
+
+ /**
+ * Ensures that the in-vm broker is cleaned up after each test run.
+ */
+ protected void tearDown()
+ {
+ try
+ {
+ // Ensure that the in-vm broker is cleaned up so that the next test starts afresh.
+ TransportConnection.killVMBroker(1);
+ ApplicationRegistry.remove(1);
+ }
+ finally
+ {
+ NDC.pop();
+ }
+ }
+
+ /**
+ * DefaultTestSequencer is a test sequencer that creates test circuits with publishing and receiving ends rooted
+ * on the same JVM.
+ */
+ public class DefaultTestSequencer implements TestCaseSequencer
+ {
+ /**
+ * Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
+ * begining the test and gathering the test reports from the participants.
+ *
+ * @param testCircuit The test circuit.
+ * @param assertions The list of assertions to apply to the test circuit.
+ * @param testProperties The test case definition.
+ */
+ public void sequenceTest(Circuit testCircuit, List<Assertion> assertions, Properties testProperties)
+ {
+ assertNoFailures(testCircuit.test(1, assertions));
+ }
+
+ /**
+ * Creates a test circuit for the test, configered by the test parameters specified.
+ *
+ * @param testProperties The test parameters.
+ * @return A test circuit.
+ */
+ public Circuit createCircuit(ParsedProperties testProperties)
+ {
+ return CircuitImpl.createCircuit(testProperties);
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java b/java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java new file mode 100644 index 0000000000..873f876012 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/MessageMonitor.java @@ -0,0 +1,46 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+/**
+ * MessageMonitor is used to record information about messages received. This will provide methods to check various
+ * properties, such as the type, number and content of messages received in order to verify the correct behaviour of
+ * tests.
+ *
+ * <p/>At the moment this monitor does not do anything.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * </table>
+ */
+public class MessageMonitor implements MessageListener
+{
+ /**
+ * Handles received messages. Does Nothing.
+ *
+ * @param message The message. Ignored.
+ */
+ public void onMessage(Message message)
+ { }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/server/exchange/MessagingTestConfigProperties.java b/java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java index b584c8c80b..3cc4a92886 100644 --- a/java/systests/src/main/java/org/apache/qpid/server/exchange/MessagingTestConfigProperties.java +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/MessagingTestConfigProperties.java @@ -18,7 +18,7 @@ * under the License.
*
*/
-package org.apache.qpid.server.exchange;
+package org.apache.qpid.test.framework;
import org.apache.qpid.jms.Session;
@@ -48,7 +48,7 @@ import uk.co.thebadgerset.junit.extensions.util.ParsedProperties; * <tr><td> destinationCount <td> 1 <td> The number of receivers listening to the pings.
* <tr><td> timeout <td> 30000 <td> In milliseconds. The timeout to stop waiting for replies.
* <tr><td> commitBatchSize <td> 1 <td> The number of messages per transaction in transactional mode.
- * <tr><td> uniqueDests <td> true <td> Whether each receiver only listens to one ping destination or all.
+ * <tr><td> uniqueDests <td> true <td> Whether each receivers only listens to one ping destination or all.
* <tr><td> durableDests <td> false <td> Whether or not durable destinations are used.
* <tr><td> ackMode <td> AUTO_ACK <td> The message acknowledgement mode. Possible values are:
* 0 - SESSION_TRANSACTED
@@ -81,12 +81,6 @@ public class MessagingTestConfigProperties /** Defines the class to use as the initial context factory by default. */
public static final String INITIAL_CONTEXT_FACTORY_DEFAULT = "org.apache.qpid.jndi.PropertiesFileInitialContextFactory";
- /** Holds the name of the default connection factory configuration property. */
- public static final String CONNECTION_PROPNAME = "connectionfactory.broker";
-
- /** Defeins the default connection configuration. */
- public static final String CONNECTION_DEFAULT = "amqp://guest:guest@clientid/?brokerlist='vm://:1'";
-
/** Holds the name of the property to get the test broker url from. */
public static final String BROKER_PROPNAME = "qpid.test.broker";
@@ -125,16 +119,16 @@ public class MessagingTestConfigProperties /** Holds the default value of the publisher consumer flag. */
public static final boolean PUBLISHER_CONSUMER_BIND_DEFAULT = false;
- /** Holds the name of the property to get the bind receiver procuder flag from. */
+ /** Holds the name of the property to get the bind receivers procuder flag from. */
public static final String RECEIVER_PRODUCER_BIND_PROPNAME = "receiverProducerBind";
- /** Holds the default value of the receiver producer flag. */
+ /** Holds the default value of the receivers producer flag. */
public static final boolean RECEIVER_PRODUCER_BIND_DEFAULT = false;
- /** Holds the name of the property to get the bind receiver procuder flag from. */
+ /** Holds the name of the property to get the bind receivers procuder flag from. */
public static final String RECEIVER_CONSUMER_BIND_PROPNAME = "receiverConsumerBind";
- /** Holds the default value of the receiver consumer flag. */
+ /** Holds the default value of the receivers consumer flag. */
public static final boolean RECEIVER_CONSUMER_BIND_DEFAULT = true;
/** Holds the name of the property to get the destination name root from. */
@@ -275,7 +269,7 @@ public class MessagingTestConfigProperties static
{
defaults.setPropertyIfNull(INITIAL_CONTEXT_FACTORY_PROPNAME, INITIAL_CONTEXT_FACTORY_DEFAULT);
- defaults.setPropertyIfNull(CONNECTION_PROPNAME, CONNECTION_DEFAULT);
+ // defaults.setPropertyIfNull(CONNECTION_PROPNAME, CONNECTION_DEFAULT);
defaults.setPropertyIfNull(MESSAGE_SIZE_PROPNAME, MESSAGE_SIZE_DEAFULT);
defaults.setPropertyIfNull(PUBLISHER_PRODUCER_BIND_PROPNAME, PUBLISHER_PRODUCER_BIND_DEFAULT);
defaults.setPropertyIfNull(PUBLISHER_CONSUMER_BIND_PROPNAME, PUBLISHER_CONSUMER_BIND_DEFAULT);
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java b/java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java new file mode 100644 index 0000000000..59aa9065dd --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/Publisher.java @@ -0,0 +1,56 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+/**
+ * A Publisher is a {@link CircuitEnd} that represents one end of a test circuit. Its main purpose is to
+ * provide assertions that can be applied to test the behaviour of the publisher.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Provide assertion that the publisher received no exceptions.
+ * <tr><td> Provide assertion that the publisher received a no consumers error code.
+ * <tr><td> Provide assertion that the publisher received a no route error code.
+ * </table>
+ */
+public interface Publisher extends CircuitEnd
+{
+ /**
+ * Provides an assertion that the publisher encountered no exceptions.
+ *
+ * @return An assertion that the publisher encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion();
+
+ /**
+ * Provides an assertion that the publisher got a no consumers exception on every message.
+ *
+ * @return An assertion that the publisher got a no consumers exception on every message.
+ */
+ public Assertion noConsumersAssertion();
+
+ /**
+ * Provides an assertion that the publisher got a no rout exception on every message.
+ *
+ * @return An assertion that the publisher got a no rout exception on every message.
+ */
+ public Assertion noRouteAssertion();
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java b/java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java new file mode 100644 index 0000000000..6e01a7ea4f --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/Receiver.java @@ -0,0 +1,48 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+/**
+ * A Receiver is a {@link CircuitEnd} that represents one end of a test circuit. Its main purpose is to
+ * provide assertions that can be applied to test the behaviour of the receivers.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Provide assertion that the receivers received no exceptions.
+ * <tr><td> Provide assertion that the receivers received all test messages sent to it.
+ * </table>
+ */
+public interface Receiver extends CircuitEnd
+{
+ /**
+ * Provides an assertion that the receivers encountered no exceptions.
+ *
+ * @return An assertion that the receivers encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion();
+
+ /**
+ * Provides an assertion that the receivers got all messages that were sent to it.
+ *
+ * @return An assertion that the receivers got all messages that were sent to it.
+ */
+ public Assertion allMessagesAssertion();
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/TestClientDetails.java b/java/systests/src/main/java/org/apache/qpid/test/framework/TestClientDetails.java new file mode 100644 index 0000000000..1e5807cba8 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/TestClientDetails.java @@ -0,0 +1,86 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+/**
+ * TestClientDetails is used to encapsulate information about an interop test client. It pairs together the unique
+ * name of the client, and the route on which it listens to its control messages.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Record test clients control addresses together with their names.
+ * </table>
+ */
+public class TestClientDetails
+{
+ /** The test clients name. */
+ public String clientName;
+
+ /* The test clients unique sequence number. Not currently used. */
+
+ /** The routing key of the test clients control topic. */
+ public String privateControlKey;
+
+ /**
+ * Two TestClientDetails are considered to be equal, iff they have the same client name.
+ *
+ * @param o The object to compare to.
+ *
+ * @return <tt>If the object to compare to is a TestClientDetails equal to this one, <tt>false</tt> otherwise.
+ */
+ public boolean equals(Object o)
+ {
+ if (this == o)
+ {
+ return true;
+ }
+
+ if (!(o instanceof TestClientDetails))
+ {
+ return false;
+ }
+
+ final TestClientDetails testClientDetails = (TestClientDetails) o;
+
+ return !((clientName != null) ? (!clientName.equals(testClientDetails.clientName))
+ : (testClientDetails.clientName != null));
+ }
+
+ /**
+ * Computes a hash code compatible with the equals method; based on the client name alone.
+ *
+ * @return A hash code for this.
+ */
+ public int hashCode()
+ {
+ return ((clientName != null) ? clientName.hashCode() : 0);
+ }
+
+ /**
+ * Outputs the client name and address details. Mostly used for debugging purposes.
+ *
+ * @return The client name and address.
+ */
+ public String toString()
+ {
+ return "TestClientDetails: [ clientName = " + clientName + ", privateControlKey = " + privateControlKey + " ]";
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/TestUtils.java b/java/systests/src/main/java/org/apache/qpid/test/framework/TestUtils.java new file mode 100644 index 0000000000..8b3e72ef08 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/TestUtils.java @@ -0,0 +1,156 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework;
+
+import org.apache.log4j.Logger;
+
+import static org.apache.qpid.test.framework.MessagingTestConfigProperties.*;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+
+import java.util.Properties;
+import java.util.Map;
+
+/**
+ * TestUtils provides static helper methods that are usefull for writing tests against QPid.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Create connections from test properties. <td> {@link MessagingTestConfigProperties}
+ * <tr><td> Inject a short pause in a test.
+ * </table>
+ */
+public class TestUtils
+{
+ /** Used for debugging. */
+ private static Logger log = Logger.getLogger(TestUtils.class);
+
+ /**
+ * Establishes a JMS connection using a set of properties and qpids built in JNDI implementation. This is a simple
+ * convenience method for code that does not anticipate handling connection failures. All exceptions that indicate
+ * that the connection has failed, are wrapped as rutime exceptions, presumably handled by a top level failure
+ * handler.
+ *
+ * <p/>This utility makes use of the following test parameters from {@link MessagingTestConfigProperties} to control
+ * the connection creation:
+ *
+ * <p/><table>
+ * <tr><td> {@link MessagingTestConfigProperties#USERNAME_PROPNAME} <td> The username.
+ * <tr><td> {@link MessagingTestConfigProperties#PASSWORD_PROPNAME} <td> The password.
+ * <tr><td> {@link MessagingTestConfigProperties#VIRTUAL_HOST_PROPNAME} <td> The virtual host name.
+ * <tr><td> {@link MessagingTestConfigProperties#BROKER_PROPNAME} <td> The broker URL.
+ * <tr><td> {@link MessagingTestConfigProperties#CONNECTION_NAME} <td> The broker name in the initial context.
+ *
+ * @param messagingProps Connection properties as defined in {@link MessagingTestConfigProperties}.
+ *
+ * @return A JMS conneciton.
+ */
+ public static Connection createConnection(ParsedProperties messagingProps)
+ {
+ log.debug("public static Connection createConnection(ParsedProperties messagingProps = " + messagingProps
+ + "): called");
+
+ try
+ {
+ // Extract the configured connection properties from the test configuration.
+ String conUsername = messagingProps.getProperty(USERNAME_PROPNAME);
+ String conPassword = messagingProps.getProperty(PASSWORD_PROPNAME);
+ String virtualHost = messagingProps.getProperty(VIRTUAL_HOST_PROPNAME);
+ String brokerUrl = messagingProps.getProperty(BROKER_PROPNAME);
+
+ // Create the broker connection url.
+ String connectionString =
+ "amqp://" + conUsername + ":" + conPassword + "@clientid/" + ((virtualHost != null) ? virtualHost : "")
+ + "?brokerlist='" + brokerUrl + "'";
+
+ // Create properties to create the initial context from, and inject the connection factory configuration
+ // for the defined connection name into it.
+ messagingProps.setProperty("connectionfactory." + CONNECTION_NAME, connectionString);
+
+ Context ctx = new InitialContext(messagingProps);
+
+ ConnectionFactory cf = (ConnectionFactory) ctx.lookup(CONNECTION_NAME);
+ Connection connection = cf.createConnection();
+
+ return connection;
+ }
+ catch (NamingException e)
+ {
+ throw new RuntimeException("Got JNDI NamingException whilst looking up the connection factory.", e);
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Could not establish connection due to JMSException.", e);
+ }
+ }
+
+ /**
+ * Pauses for the specified length of time. In the event of failing to pause for at least that length of time
+ * due to interuption of the thread, a RutimeException is raised to indicate the failure. The interupted status
+ * of the thread is restores in that case. This method should only be used when it is expected that the pause
+ * will be succesfull, for example in test code that relies on inejecting a pause.
+ *
+ * @param t The minimum time to pause for in milliseconds.
+ */
+ public static void pause(long t)
+ {
+ try
+ {
+ Thread.sleep(t);
+ }
+ catch (InterruptedException e)
+ {
+ // Restore the interrupted status
+ Thread.currentThread().interrupt();
+
+ throw new RuntimeException("Failed to generate the requested pause length.", e);
+ }
+ }
+
+ /**
+ * Sets properties of different types on a JMS Message.
+ *
+ * @param message The message to set properties on.
+ * @param properties The property name/value pairs to set.
+ *
+ * @throws javax.jms.JMSException All underlying JMSExceptions are allowed to fall through.
+ *
+ * @todo Move this helper method somewhere else. For example, TestUtils.
+ */
+ public static void setPropertiesOnMessage(Message message, Map<Object, Object> properties) throws JMSException
+ {
+ for (Map.Entry<Object, Object> entry : properties.entrySet())
+ {
+ String name = entry.getKey().toString();
+ Object value = entry.getValue();
+
+ message.setObjectProperty(name, value);
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedCircuitImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedCircuitImpl.java new file mode 100644 index 0000000000..aadd378aed --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedcircuit/DistributedCircuitImpl.java @@ -0,0 +1,116 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.distributedcircuit;
+
+import org.apache.qpid.test.framework.Assertion;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.Publisher;
+import org.apache.qpid.test.framework.Receiver;
+
+import java.util.List;
+
+/**
+ * DistributedCircuitImpl is a distributed implementation of the test {@link Circuit}. Many publishers and receivers
+ * accross multiple machines may be combined to form a single test circuit. The test circuit extracts reports from
+ * all of its publishers and receivers, and applies its assertions to these reports.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
+ * <tr><td> Start the circuit running.
+ * <tr><td> Close the circuit down.
+ * <tr><td> Take a reading of the circuits state.
+ * <tr><td> Apply assertions against the circuits state.
+ * <tr><td> Send test messages over the circuit.
+ * <tr><td> Perform the default test procedue on the circuit.
+ * </table>
+ */
+public class DistributedCircuitImpl implements Circuit
+{
+ /**
+ * Gets the interface on the publishing end of the circuit.
+ *
+ * @return The publishing end of the circuit.
+ */
+ public Publisher getPublisher()
+ {
+ throw new RuntimeException("Not Implemented.");
+ }
+
+ /**
+ * Gets the interface on the receiving end of the circuit.
+ *
+ * @return The receiving end of the circuit.
+ */
+ public Receiver getReceiver()
+ {
+ throw new RuntimeException("Not Implemented.");
+ }
+
+ /**
+ * Connects and starts the circuit. After this method is called the circuit is ready to send messages.
+ */
+ public void start()
+ {
+ throw new RuntimeException("Not Implemented.");
+ }
+
+ /**
+ * Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
+ * into a report, against which assertions may be checked.
+ */
+ public void check()
+ {
+ throw new RuntimeException("Not Implemented.");
+ }
+
+ /**
+ * Closes the circuit. All associated resources are closed.
+ */
+ public void close()
+ {
+ throw new RuntimeException("Not Implemented.");
+ }
+
+ /**
+ * Applied a list of assertions against the test circuit. The {@link #check()} method should be called before doing
+ * this, to ensure that the circuit has gathered its state into a report to assert against.
+ *
+ * @param assertions The list of assertions to apply.
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> applyAssertions(List<Assertion> assertions)
+ {
+ throw new RuntimeException("Not Implemented.");
+ }
+
+ /**
+ * Runs the default test procedure against the circuit, and checks that all of the specified assertions hold.
+ *
+ * @param numMessages The number of messages to send using the default test procedure.
+ * @param assertions The list of assertions to apply.
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> test(int numMessages, List<Assertion> assertions)
+ {
+ throw new RuntimeException("Not Implemented.");
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/Coordinator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/Coordinator.java new file mode 100644 index 0000000000..7d28aee432 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/Coordinator.java @@ -0,0 +1,498 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.distributedtesting;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.MessagingTestConfigProperties;
+import org.apache.qpid.test.framework.TestUtils;
+import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.test.framework.listeners.XMLTestListener;
+import org.apache.qpid.util.ConversationFactory;
+import org.apache.qpid.util.PrettyPrintingUtils;
+
+import uk.co.thebadgerset.junit.extensions.TKTestResult;
+import uk.co.thebadgerset.junit.extensions.TKTestRunner;
+import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
+import uk.co.thebadgerset.junit.extensions.util.CommandLineParser;
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+import uk.co.thebadgerset.junit.extensions.util.TestContextProperties;
+
+import javax.jms.*;
+
+import java.io.*;
+import java.util.*;
+import java.util.concurrent.LinkedBlockingQueue;
+
+/**
+ * <p/>Implements the coordinator client described in the interop testing specification
+ * (http://cwiki.apache.org/confluence/display/qpid/Interop+Testing+Specification). This coordinator is built on
+ * top of the JUnit testing framework.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Find out what test clients are available. <td> {@link ConversationFactory}
+ * <tr><td> Decorate available tests to run all available clients. <td> {@link DistributedTestDecorator}
+ * <tr><td> Attach XML test result logger.
+ * <tr><td> Terminate the interop testing framework.
+ * </table>
+ *
+ * @todo Should accumulate failures over all tests, and return with success or fail code based on all results. May need
+ * to write a special TestResult to do this properly. At the moment only the last one used will be tested for
+ * errors, as the start method creates a fresh one for each test case run.
+ *
+ * @todo Remove hard coding of test cases and put on command line instead.
+ */
+public class Coordinator extends TKTestRunner
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(Coordinator.class);
+
+ /** Used for reporting to the console. */
+ private static final Logger console = Logger.getLogger("CONSOLE");
+
+ /** Defines the possible distributed test engines available to run coordinated test cases with. */
+ public enum TestEngine
+ {
+ /** Specifies the interop test engine. This tests all available clients in pairs. */
+ INTEROP,
+
+ /** Specifies the fanout test engine. This sets up one publisher role, and many reciever roles. */
+ FANOUT
+ }
+
+ /**
+ * Holds the test context properties that provides the default test parameters, plus command line overrides.
+ * This is initialized with the default test parameters, to which command line overrides may be applied.
+ */
+ protected static ParsedProperties testContextProperties =
+ TestContextProperties.getInstance(MessagingTestConfigProperties.defaults);
+
+ /** Holds the URL of the broker to coordinate the tests on. */
+ protected String brokerUrl;
+
+ /** Holds the virtual host to coordinate the tests on. If <tt>null</tt>, then the default virtual host is used. */
+ protected String virtualHost;
+
+ /** Holds the list of all clients that enlisted, when the compulsory invite was issued. */
+ protected Set<TestClientDetails> enlistedClients = new HashSet<TestClientDetails>();
+
+ /** Holds the conversation helper for the control conversation. */
+ protected ConversationFactory conversationFactory;
+
+ /** Holds the connection that the coordinating messages are sent over. */
+ protected Connection connection;
+
+ /**
+ * Holds the name of the class of the test currently being run. Ideally passed into the {@link #createTestResult}
+ * method, but as the signature is already fixed for this, the current value gets pushed here as a member variable.
+ */
+ protected String currentTestClassName;
+
+ /** Holds the path of the directory to output test results too, if one is defined. */
+ protected String reportDir;
+
+ /** Holds the coordinating test engine type to run the tests through. */
+ protected TestEngine engine;
+
+ /** Flag that indicates that all test clients should be terminated upon completion of the test cases. */
+ protected boolean terminate;
+
+ /**
+ * Creates an interop test coordinator on the specified broker and virtual host.
+ *
+ * @param brokerUrl The URL of the broker to connect to.
+ * @param virtualHost The virtual host to run all tests on. Optional, may be <tt>null</tt>.
+ * @param reportDir The directory to write out test results to.
+ * @param engine The distributed test engine type to run the tests with.
+ */
+ public Coordinator(String brokerUrl, String virtualHost, String reportDir, TestEngine engine, boolean terminate)
+ {
+ log.debug("Coordinator(String brokerUrl = " + brokerUrl + ", String virtualHost = " + virtualHost + "): called");
+
+ // Retain the connection parameters.
+ this.brokerUrl = brokerUrl;
+ this.virtualHost = virtualHost;
+ this.reportDir = reportDir;
+ this.engine = engine;
+ this.terminate = terminate;
+ }
+
+ /**
+ * The entry point for the interop test coordinator. This client accepts the following command line arguments:
+ *
+ * <p/><table>
+ * <tr><td> -b <td> The broker URL. <td> Mandatory.
+ * <tr><td> -h <td> The virtual host. <td> Optional.
+ * <tr><td> -o <td> The directory to output test results to. <td> Optional.
+ * <tr><td> -e <td> The type of test distribution engine to use. <td> Optional. One of: interop, fanout.
+ * <tr><td> ... <td> Free arguments. The distributed test cases to run.
+ * <td> Mandatory. At least one must be defined.
+ * <tr><td> name=value <td> Trailing argument define name/value pairs. Added to the test contenxt properties.
+ * <td> Optional.
+ * </table>
+ *
+ * @param args The command line arguments.
+ */
+ public static void main(String[] args)
+ {
+ console.info("Qpid Distributed Test Coordinator.");
+
+ // Override the default broker url to be localhost:5672.
+ testContextProperties.setProperty(MessagingTestConfigProperties.BROKER_PROPNAME, "tcp://localhost:5672");
+
+ try
+ {
+ // Use the command line parser to evaluate the command line with standard handling behaviour (print errors
+ // and usage then exist if there are errors).
+ // Any options and trailing name=value pairs are also injected into the test context properties object,
+ // to override any defaults that may have been set up.
+ ParsedProperties options =
+ new ParsedProperties(CommandLineParser.processCommandLine(args,
+ new CommandLineParser(
+ new String[][]
+ {
+ { "b", "The broker URL.", "broker", "false" },
+ { "h", "The virtual host to use.", "virtual host", "false" },
+ { "o", "The name of the directory to output test timings to.", "dir", "false" },
+ {
+ "e", "The test execution engine to use. Default is interop.", "engine", "interop",
+ "^interop$|^fanout$", "true"
+ },
+ { "t", "Terminate test clients on completion of tests.", "flag", "false" }
+ }), testContextProperties));
+
+ // Extract the command line options.
+ String brokerUrl = options.getProperty("b");
+ String virtualHost = options.getProperty("h");
+ String reportDir = options.getProperty("o");
+ reportDir = (reportDir == null) ? "." : reportDir;
+ String testEngine = options.getProperty("e");
+ TestEngine engine = "fanout".equals(testEngine) ? TestEngine.FANOUT : TestEngine.INTEROP;
+ boolean terminate = options.getPropertyAsBoolean("t");
+
+ // If broker or virtual host settings were specified as command line options, override the defaults in the
+ // test context properties with them.
+
+ // Collection all of the test cases to be run.
+ Collection<Class<? extends DistributedTestCase>> testCaseClasses =
+ new ArrayList<Class<? extends DistributedTestCase>>();
+
+ // Scan for available test cases using a classpath scanner.
+ // ClasspathScanner.getMatches(InteropTestCase.class, "^Test.*", true);
+
+ // Hard code the test classes till the classpath scanner is fixed.
+ // Collections.addAll(testCaseClasses, InteropTestCase1DummyRun.class, InteropTestCase2BasicP2P.class,
+ // InteropTestCase3BasicPubSub.class);
+
+ // Parse all of the free arguments as test cases to run.
+ for (int i = 1; true; i++)
+ {
+ String nextFreeArg = options.getProperty(Integer.toString(i));
+
+ // Terminate the loop once all free arguments have been consumed.
+ if (nextFreeArg == null)
+ {
+ break;
+ }
+
+ try
+ {
+ Class nextClass = Class.forName(nextFreeArg);
+
+ if (DistributedTestCase.class.isAssignableFrom(nextClass))
+ {
+ testCaseClasses.add(nextClass);
+ console.info("Found distributed test case: " + nextFreeArg);
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ console.info("Unable to instantiate the test case: " + nextFreeArg + ".");
+ }
+ }
+
+ // Check that some test classes were actually found.
+ if (testCaseClasses.isEmpty())
+ {
+ throw new RuntimeException("No test cases implementing InteropTestCase were specified on the command line.");
+ }
+
+ // Extract the names of all the test classes, to pass to the start method.
+ int i = 0;
+ String[] testClassNames = new String[testCaseClasses.size()];
+
+ for (Class testClass : testCaseClasses)
+ {
+ testClassNames[i++] = testClass.getName();
+ }
+
+ // Create a coordinator and begin its test procedure.
+ Coordinator coordinator = new Coordinator(brokerUrl, virtualHost, reportDir, engine, terminate);
+
+ TestResult testResult = coordinator.start(testClassNames);
+
+ // Return different error codes, depending on whether or not there were test failures.
+ if (testResult.failureCount() > 0)
+ {
+ System.exit(FAILURE_EXIT);
+ }
+ else
+ {
+ System.exit(SUCCESS_EXIT);
+ }
+ }
+ catch (Exception e)
+ {
+ log.debug("Top level handler caught execption.", e);
+ console.info(e.getMessage());
+ System.exit(EXCEPTION_EXIT);
+ }
+ }
+
+ /**
+ * Starts all of the test classes to be run by this coordinator.
+ *
+ * @param testClassNames An array of all the coordinating test case implementations.
+ *
+ * @return A JUnit TestResult to run the tests with.
+ *
+ * @throws Exception Any underlying exceptions are allowed to fall through, and fail the test process.
+ */
+ public TestResult start(String[] testClassNames) throws Exception
+ {
+ log.debug("public TestResult start(String[] testClassNames = " + PrettyPrintingUtils.printArray(testClassNames)
+ + ": called");
+
+ // Connect to the broker.
+ connection = TestUtils.createConnection(TestContextProperties.getInstance());
+ Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ Destination controlTopic = session.createTopic("iop.control");
+ Destination responseQueue = session.createQueue("coordinator");
+
+ conversationFactory = new ConversationFactory(connection, responseQueue, LinkedBlockingQueue.class);
+ ConversationFactory.Conversation conversation = conversationFactory.startConversation();
+
+ connection.start();
+
+ // Broadcast the compulsory invitation to find out what clients are available to test.
+ Message invite = session.createMessage();
+ invite.setStringProperty("CONTROL_TYPE", "INVITE");
+ invite.setJMSReplyTo(responseQueue);
+
+ conversation.send(controlTopic, invite);
+
+ // Wait for a short time, to give test clients an opportunity to reply to the invitation.
+ Collection<Message> enlists = conversation.receiveAll(0, 3000);
+
+ enlistedClients = extractEnlists(enlists);
+
+ // Run the test in the suite using JUnit.
+ TestResult result = null;
+
+ for (String testClassName : testClassNames)
+ {
+ // Record the current test class, so that the test results can be output to a file incorporating this name.
+ this.currentTestClassName = testClassName;
+
+ result = super.start(new String[] { testClassName });
+ }
+
+ // At this point in time, all tests have completed. Broadcast the shutdown message, if the termination option
+ // was set on the command line.
+ if (terminate)
+ {
+ Message terminate = session.createMessage();
+ terminate.setStringProperty("CONTROL_TYPE", "TERMINATE");
+
+ conversation.send(controlTopic, terminate);
+ }
+
+ return result;
+ }
+
+ /**
+ * For a collection of enlist messages, this method pulls out of the client details for the enlisting clients.
+ *
+ * @param enlists The enlist messages.
+ *
+ * @return A set of enlisting clients, extracted from the enlist messages.
+ *
+ * @throws JMSException Any underlying JMSException is allowed to fall through.
+ */
+ public static Set<TestClientDetails> extractEnlists(Collection<Message> enlists) throws JMSException
+ {
+ log.debug("public static Set<TestClientDetails> extractEnlists(Collection<Message> enlists = " + enlists
+ + "): called");
+
+ Set<TestClientDetails> enlistedClients = new HashSet<TestClientDetails>();
+
+ // Retain the list of all available clients.
+ for (Message enlist : enlists)
+ {
+ TestClientDetails clientDetails = new TestClientDetails();
+ clientDetails.clientName = enlist.getStringProperty("CLIENT_NAME");
+ clientDetails.privateControlKey = enlist.getStringProperty("CLIENT_PRIVATE_CONTROL_KEY");
+
+ enlistedClients.add(clientDetails);
+ }
+
+ return enlistedClients;
+ }
+
+ /**
+ * Runs a test or suite of tests, using the super class implemenation. This method wraps the test to be run
+ * in any test decorators needed to add in the coordinators ability to invite test clients to participate in
+ * tests.
+ *
+ * @param test The test to run.
+ * @param wait Undocumented. Nothing in the JUnit javadocs to say what this is for.
+ *
+ * @return The results of the test run.
+ */
+ public TestResult doRun(Test test, boolean wait)
+ {
+ log.debug("public TestResult doRun(Test \"" + test + "\", boolean " + wait + "): called");
+
+ // Wrap all tests in the test suite with WrappedSuiteTestDecorators. This is quite ugly and a bit baffling,
+ // but the reason it is done is because the JUnit implementation of TestDecorator has some bugs in it.
+ WrappedSuiteTestDecorator targetTest = null;
+
+ if (test instanceof TestSuite)
+ {
+ log.debug("targetTest is a TestSuite");
+
+ TestSuite suite = (TestSuite) test;
+
+ int numTests = suite.countTestCases();
+ log.debug("There are " + numTests + " in the suite.");
+
+ for (int i = 0; i < numTests; i++)
+ {
+ Test nextTest = suite.testAt(i);
+ log.debug("suite.testAt(" + i + ") = " + nextTest);
+
+ if (nextTest instanceof DistributedTestCase)
+ {
+ log.debug("nextTest is a DistributedTestCase");
+ }
+ }
+
+ targetTest = new WrappedSuiteTestDecorator(suite);
+ log.debug("Wrapped with a WrappedSuiteTestDecorator.");
+ }
+
+ // Wrap the tests in a suitable distributed test decorator, to perform the invite/test cycle.
+ targetTest = newTestDecorator(targetTest, enlistedClients, conversationFactory, connection);
+
+ TestSuite suite = new TestSuite();
+ suite.addTest(targetTest);
+
+ // Wrap the tests in a scaled test decorator to them them as a 'batch' in one thread.
+ // targetTest = new ScaledTestDecorator(targetTest, new int[] { 1 });
+
+ return super.doRun(suite, wait);
+ }
+
+ /**
+ * Creates a wrapped test decorator, that is capable of inviting enlisted clients to participate in a specified
+ * test. This is the test engine that sets up the roles and sequences a distributed test case.
+ *
+ * @param targetTest The test decorator to wrap.
+ * @param enlistedClients The enlisted clients available to run the test.
+ * @param conversationFactory The conversation factory used to build conversation helper over the specified connection.
+ * @param connection The connection to talk to the enlisted clients over.
+ *
+ * @return An invititing test decorator, that invites all the enlisted clients to participate in tests, in pairs.
+ */
+ protected DistributedTestDecorator newTestDecorator(WrappedSuiteTestDecorator targetTest,
+ Set<TestClientDetails> enlistedClients, ConversationFactory conversationFactory, Connection connection)
+ {
+ switch (engine)
+ {
+ case FANOUT:
+ return new FanOutTestDecorator(targetTest, enlistedClients, conversationFactory, connection);
+ case INTEROP:
+ default:
+ return new InteropTestDecorator(targetTest, enlistedClients, conversationFactory, connection);
+ }
+ }
+
+ /**
+ * Creates the TestResult object to be used for test runs.
+ *
+ * @return An instance of the test result object.
+ */
+ protected TestResult createTestResult()
+ {
+ log.debug("protected TestResult createTestResult(): called");
+
+ TKTestResult result = new TKTestResult(fPrinter.getWriter(), delay, verbose, testCaseName);
+
+ // Check if a directory to output reports to has been specified and attach test listeners if so.
+ if (reportDir != null)
+ {
+ // Create the report directory if it does not already exist.
+ File reportDirFile = new File(reportDir);
+
+ if (!reportDirFile.exists())
+ {
+ reportDirFile.mkdir();
+ }
+
+ // Create the results file (make the name of this configurable as a command line parameter).
+ Writer timingsWriter;
+
+ try
+ {
+ File timingsFile = new File(reportDirFile, "TEST." + currentTestClassName + ".xml");
+ timingsWriter = new BufferedWriter(new FileWriter(timingsFile), 20000);
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Unable to create the log file to write test results to: " + e, e);
+ }
+
+ // Set up an XML results listener to output the timings to the results file.
+ XMLTestListener listener = new XMLTestListener(timingsWriter, currentTestClassName);
+ result.addListener(listener);
+ result.addTKTestListener(listener);
+
+ // Register the results listeners shutdown hook to flush its data if the test framework is shutdown
+ // prematurely.
+ // registerShutdownHook(listener);
+
+ // Record the start time of the batch.
+ // result.notifyStartBatch();
+
+ // At this point in time the test class has been instantiated, giving it an opportunity to read its parameters.
+ // Inform any test listers of the test properties.
+ result.notifyTestProperties(TestContextProperties.getAccessedProps());
+ }
+
+ return result;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestCase.java new file mode 100644 index 0000000000..c47650ba1c --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestCase.java @@ -0,0 +1,81 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.distributedtesting;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
+import org.apache.qpid.test.framework.FrameworkBaseCase;
+
+/**
+ * DistributedTestCase provides a base class implementation of the {@link org.apache.qpid.test.framework.sequencers.DistributedTestSequencer}, taking care of its
+ * more mundane aspects, such as recording the test pariticipants.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Accept notification of test case participants.
+ * <td> {@link DistributedTestDecorator}
+ * <tr><td> Accept JMS Connection to carry out the coordination over.
+ * </table>
+ */
+public abstract class DistributedTestCase extends FrameworkBaseCase
+{
+ /** Used for debugging. */
+ private final Logger log = Logger.getLogger(DistributedTestCase.class);
+
+ /**
+ * Creates a new test case with the specified name.
+ *
+ * @param name The test case name.
+ */
+ public DistributedTestCase(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * Gets the test sequencer for this distributed test, cast as a {@link DistributedTestSequencer}, provided that it
+ * is one. If the test sequencer is not distributed, this returns null.
+ */
+ public DistributedTestSequencer getDistributedTestSequencer()
+ {
+ try
+ {
+ return (DistributedTestSequencer) testSequencer;
+ }
+ catch (ClassCastException e)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Should provide a translation from the junit method name of a test to its test case name as known to the test
+ * clients that will run the test. The purpose of this is to convert the JUnit method name into the correct test
+ * case name to place into the test invite. For example the method "testP2P" might map onto the interop test case
+ * name "TC2_BasicP2P".
+ *
+ * @param methodName The name of the JUnit test method.
+ *
+ * @return The name of the corresponding interop test case.
+ */
+ public abstract String getTestCaseNameForTestMethod(String methodName);
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestDecorator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestDecorator.java new file mode 100644 index 0000000000..bcc409dff9 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/DistributedTestDecorator.java @@ -0,0 +1,166 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.distributedtesting;
+
+import junit.framework.TestResult;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
+import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.util.ConversationFactory;
+
+import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
+
+import javax.jms.Connection;
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+import java.util.*;
+
+/**
+ * DistributedTestDecorator is a base class for writing test decorators that invite test clients to participate in
+ * distributed test cases. It provides a helper method, {@link #signupClients}, that broadcasts an invitation and
+ * returns the set of test clients that are available to particiapte in the test.
+ *
+ * <p/>When used to wrap a {@link org.apache.qpid.test.framework.FrameworkBaseCase} test, it replaces the default
+ * {@link org.apache.qpid.test.framework.sequencers.TestCaseSequencer} implementations with a suitable
+ * {@link org.apache.qpid.test.framework.sequencers.DistributedTestSequencer}. Concrete implementations
+ * can use this to configure the sending and receiving roles on the test.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Broadcast test invitations and collect enlists. <td> {@link ConversationFactory}.
+ * </table>
+ */
+public abstract class DistributedTestDecorator extends WrappedSuiteTestDecorator
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(DistributedTestDecorator.class);
+
+ /** Holds the contact information for all test clients that are available and that may take part in the test. */
+ Set<TestClientDetails> allClients;
+
+ /** Holds the conversation helper for the control level conversation for coordinating the test through. */
+ ConversationFactory conversationFactory;
+
+ /** Holds the connection that the control conversation is held over. */
+ Connection connection;
+
+ /** Holds the underlying {@link DistributedTestCase}s that this decorator wraps. */
+ WrappedSuiteTestDecorator testSuite;
+
+ /** Holds the control topic, on which test invitations are broadcast. */
+ protected Destination controlTopic;
+
+ /**
+ * Creates a wrapped suite test decorator from another one.
+ *
+ * @param suite The test suite.
+ * @param availableClients The list of all clients that responded to the compulsory invite.
+ * @param controlConversation The conversation helper for the control level, test coordination conversation.
+ * @param controlConnection The connection that the coordination messages are sent over.
+ */
+ public DistributedTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> availableClients,
+ ConversationFactory controlConversation, Connection controlConnection)
+ {
+ super(suite);
+
+ log.debug("public DistributedTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> allClients = "
+ + availableClients + ", ConversationHelper controlConversation = " + controlConversation + "): called");
+
+ testSuite = suite;
+ allClients = availableClients;
+ conversationFactory = controlConversation;
+ connection = controlConnection;
+
+ // Set up the test control topic.
+ try
+ {
+ controlTopic = conversationFactory.getSession().createTopic("iop.control");
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Unable to create the coordinating control topic to broadcast test invites on.", e);
+ }
+ }
+
+ /**
+ * Should run all of the tests in the wrapped test suite.
+ *
+ * @param testResult The the results object to monitor the test results with.
+ */
+ public abstract void run(TestResult testResult);
+
+ /**
+ * Should provide the distributed test sequencer to pass to {@link org.apache.qpid.test.framework.FrameworkBaseCase}
+ * tests.
+ *
+ * @return A distributed test sequencer.
+ */
+ public abstract DistributedTestSequencer getDistributedTestSequencer();
+
+ /**
+ * Broadcasts an invitation to participate in a coordinating test case to find out what clients are available to
+ * run the test case.
+ *
+ * @param coordTest The coordinating test case to broadcast an inviate for.
+ *
+ * @return A set of test clients that accepted the invitation.
+ */
+ protected Set<TestClientDetails> signupClients(DistributedTestCase coordTest)
+ {
+ // Broadcast the invitation to find out what clients are available to test.
+ Set<TestClientDetails> enlists;
+ try
+ {
+ Message invite = conversationFactory.getSession().createMessage();
+
+ ConversationFactory.Conversation conversation = conversationFactory.startConversation();
+
+ invite.setStringProperty("CONTROL_TYPE", "INVITE");
+ invite.setStringProperty("TEST_NAME", coordTest.getTestCaseNameForTestMethod(coordTest.getName()));
+
+ conversation.send(controlTopic, invite);
+
+ // Wait for a short time, to give test clients an opportunity to reply to the invitation.
+ Collection<Message> replies = conversation.receiveAll(allClients.size(), 3000);
+ enlists = Coordinator.extractEnlists(replies);
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("There was a JMSException during the invite/enlist conversation.", e);
+ }
+
+ return enlists;
+ }
+
+ /**
+ * Prints a string summarizing this test decorator, mainly for debugging purposes.
+ *
+ * @return String representation for debugging purposes.
+ */
+ public String toString()
+ {
+ return "DistributedTestDecorator: [ testSuite = " + testSuite + " ]";
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/FanOutTestDecorator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/FanOutTestDecorator.java new file mode 100644 index 0000000000..83d6602e57 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/FanOutTestDecorator.java @@ -0,0 +1,201 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.distributedtesting;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
+import org.apache.qpid.test.framework.sequencers.FanOutTestSequencer;
+import org.apache.qpid.test.framework.DropInTest;
+import org.apache.qpid.util.ConversationFactory;
+import org.apache.qpid.test.framework.TestClientDetails;
+
+import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
+
+import javax.jms.Connection;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.Set;
+
+/**
+ * FanOutTestDecorator is an {@link DistributedTestDecorator} that runs one test client in the sender role, and the remainder
+ * in the receivers role. It also has the capability to listen for new test cases joining the test beyond the initial start
+ * point. This feature can be usefull when experimenting with adding more load, in the form of more test clients, to assess
+ * its impact on a running test.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Execute coordinated test cases. <td> {@link DistributedTestCase}
+ * <tr><td> Accept test clients joining a running test.
+ * </table>
+ */
+public class FanOutTestDecorator extends DistributedTestDecorator implements MessageListener
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(FanOutTestDecorator.class);
+
+ /** Holds the currently running test case. */
+ DistributedTestCase currentTest = null;
+
+ /**
+ * Creates a wrapped suite test decorator from another one.
+ *
+ * @param suite The test suite.
+ * @param availableClients The list of all clients that responded to the compulsory invite.
+ * @param controlConversation The conversation helper for the control level, test coordination conversation.
+ * @param controlConnection The connection that the coordination messages are sent over.
+ */
+ public FanOutTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> availableClients,
+ ConversationFactory controlConversation, Connection controlConnection)
+ {
+ super(suite, availableClients, controlConversation, controlConnection);
+
+ log.debug("public DistributedTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> allClients = "
+ + availableClients + ", ConversationHelper controlConversation = " + controlConversation + "): called");
+
+ testSuite = suite;
+ allClients = availableClients;
+ conversationFactory = controlConversation;
+ connection = controlConnection;
+ }
+
+ /**
+ * Broadcasts a test invitation and accepts enlists from participating clients. The wrapped test cases are run
+ * with one test client in the sender role, and the remaining test clients in the receiving role.
+ *
+ * <p/>Any JMSExceptions during the invite/enlist conversation will be allowed to fall through as runtime
+ * exceptions, resulting in the non-completion of the test run.
+ *
+ * @param testResult The the results object to monitor the test results with.
+ *
+ * @todo Better error recovery for failure of the invite/enlist conversation could be added.
+ */
+ public void run(TestResult testResult)
+ {
+ log.debug("public void run(TestResult testResult): called");
+
+ Collection<Test> tests = testSuite.getAllUnderlyingTests();
+
+ // Listen for late joiners on the control topic.
+ try
+ {
+ conversationFactory.getSession().createConsumer(controlTopic).setMessageListener(this);
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Unable to set up the message listener on the control topic.", e);
+ }
+
+ // Run all of the test cases in the test suite.
+ for (Test test : tests)
+ {
+ DistributedTestCase coordTest = (DistributedTestCase) test;
+
+ // Get all of the clients able to participate in the test.
+ Set<TestClientDetails> enlists = signupClients(coordTest);
+
+ // Check that there were some clients available.
+ if (enlists.size() == 0)
+ {
+ throw new RuntimeException("No clients to test with");
+ }
+
+ // Create a distributed test sequencer for the test.
+ DistributedTestSequencer sequencer = getDistributedTestSequencer();
+
+ // Set up the first client in the sender role, and the remainder in the receivers role.
+ Iterator<TestClientDetails> clients = enlists.iterator();
+ sequencer.setSender(clients.next());
+
+ while (clients.hasNext())
+ {
+ // Set the sending and receiving client details on the test case.
+ sequencer.setReceiver(clients.next());
+ }
+
+ // Pass down the connection to hold the coordinating conversation over.
+ sequencer.setConversationFactory(conversationFactory);
+
+ // If the current test case is a drop-in test, set it up as the currently running test for late joiners to
+ // add in to. Otherwise the current test field is set to null, to indicate that late joiners are not allowed.
+ currentTest = (coordTest instanceof DropInTest) ? coordTest : null;
+
+ // Execute the test case.
+ coordTest.setTestSequencer(sequencer);
+ coordTest.run(testResult);
+
+ currentTest = null;
+ }
+ }
+
+ /**
+ * Should provide the distributed test sequencer to pass to {@link org.apache.qpid.test.framework.FrameworkBaseCase}
+ * tests.
+ *
+ * @return A distributed test sequencer.
+ */
+ public DistributedTestSequencer getDistributedTestSequencer()
+ {
+ return new FanOutTestSequencer();
+ }
+
+ /**
+ * Listens to incoming messages on the control topic. If the messages are 'join' messages, signalling a new
+ * test client wishing to join the current test, then the new client will be added to the current test in the
+ * receivers role.
+ *
+ * @param message The incoming control message.
+ */
+ public void onMessage(Message message)
+ {
+ try
+ {
+ // Check if the message is from a test client attempting to join a running test, and join it to the current
+ // test case if so.
+ if (message.getStringProperty("CONTROL_TYPE").equals("JOIN") && (currentTest != null))
+ {
+ ((DropInTest) currentTest).lateJoin(message);
+ }
+ }
+ // There is not a lot can be done with this error, so it is deliberately ignored.
+ catch (JMSException e)
+ {
+ log.debug("Unable to process message:" + message);
+ }
+ }
+
+ /**
+ * Prints a string summarizing this test decorator, mainly for debugging purposes.
+ *
+ * @return String representation for debugging purposes.
+ */
+ public String toString()
+ {
+ return "FanOutTestDecorator: [ testSuite = " + testSuite + " ]";
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropTestDecorator.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropTestDecorator.java new file mode 100644 index 0000000000..7743d2bba3 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/InteropTestDecorator.java @@ -0,0 +1,207 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.distributedtesting;
+
+import junit.framework.Test;
+import junit.framework.TestResult;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
+import org.apache.qpid.test.framework.sequencers.InteropTestSequencer;
+import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.util.ConversationFactory;
+
+import uk.co.thebadgerset.junit.extensions.WrappedSuiteTestDecorator;
+
+import javax.jms.Connection;
+
+import java.util.*;
+
+/**
+ * DistributedTestDecorator is a test decorator, written to implement the interop test specification. Given a list
+ * of enlisted test clients, that are available to run interop tests, this decorator invites them to participate
+ * in each test in the wrapped test suite. Amongst all the clients that respond to the invite, all pairs are formed,
+ * and each pairing (in both directions, but excluding the reflexive pairings) is split into a sender and receivers
+ * role and a test case run between them. Any enlisted combinations that do not accept a test invite are automatically
+ * failed.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Broadcast test invitations and collect enlists. <td> {@link org.apache.qpid.util.ConversationFactory}.
+ * <tr><td> Output test failures for clients unwilling to run the test case. <td> {@link Coordinator}
+ * <tr><td> Execute distributed test cases. <td> {@link DistributedTestCase}
+ * <tr><td> Fail non participating pairings. <td> {@link OptOutTestCase}
+ * </table>
+ */
+public class InteropTestDecorator extends DistributedTestDecorator
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(InteropTestDecorator.class);
+
+ /**
+ * Creates a wrapped suite test decorator from another one.
+ *
+ * @param suite The test suite.
+ * @param availableClients The list of all clients that responded to the compulsory invite.
+ * @param controlConversation The conversation helper for the control level, test coordination conversation.
+ * @param controlConnection The connection that the coordination messages are sent over.
+ */
+ public InteropTestDecorator(WrappedSuiteTestDecorator suite, Set<TestClientDetails> availableClients,
+ ConversationFactory controlConversation, Connection controlConnection)
+ {
+ super(suite, availableClients, controlConversation, controlConnection);
+ }
+
+ /**
+ * Broadcasts a test invitation and accetps enlisting from participating clients. The wrapped test case is
+ * then repeated for every combination of test clients (provided the wrapped test case extends
+ * {@link DistributedTestCase}.
+ *
+ * <p/>Any JMSExceptions during the invite/enlist conversation will be allowed to fall through as runtime exceptions,
+ * resulting in the non-completion of the test run.
+ *
+ * @todo Better error recovery for failure of the invite/enlist conversation could be added.
+ *
+ * @param testResult The the results object to monitor the test results with.
+ */
+ public void run(TestResult testResult)
+ {
+ log.debug("public void run(TestResult testResult): called");
+
+ Collection<Test> tests = testSuite.getAllUnderlyingTests();
+
+ for (Test test : tests)
+ {
+ DistributedTestCase coordTest = (DistributedTestCase) test;
+
+ // Broadcast the invitation to find out what clients are available to test.
+ Set<TestClientDetails> enlists = signupClients(coordTest);
+
+ // Compare the list of willing clients to the list of all available.
+ Set<TestClientDetails> optOuts = new HashSet<TestClientDetails>(allClients);
+ optOuts.removeAll(enlists);
+
+ // Output test failures for clients that will not particpate in the test.
+ Set<List<TestClientDetails>> failPairs = allPairs(optOuts, allClients);
+
+ for (List<TestClientDetails> failPair : failPairs)
+ {
+ // Create a distributed test sequencer for the test.
+ DistributedTestSequencer sequencer = getDistributedTestSequencer();
+
+ // Create an automatic failure test for the opted out test pair.
+ DistributedTestCase failTest = new OptOutTestCase("testOptOut");
+ sequencer.setSender(failPair.get(0));
+ sequencer.setReceiver(failPair.get(1));
+ failTest.setTestSequencer(sequencer);
+
+ failTest.run(testResult);
+ }
+
+ // Loop over all combinations of clients, willing to run the test.
+ Set<List<TestClientDetails>> enlistedPairs = allPairs(enlists, enlists);
+
+ for (List<TestClientDetails> enlistedPair : enlistedPairs)
+ {
+ // Create a distributed test sequencer for the test.
+ DistributedTestSequencer sequencer = getDistributedTestSequencer();
+
+ // Set the sending and receiving client details on the test sequencer.
+ sequencer.setSender(enlistedPair.get(0));
+ sequencer.setReceiver(enlistedPair.get(1));
+
+ // Pass down the connection to hold the coordination conversation over.
+ sequencer.setConversationFactory(conversationFactory);
+
+ // Execute the test case.
+ coordTest.setTestSequencer(sequencer);
+ coordTest.run(testResult);
+ }
+ }
+ }
+
+ /**
+ * Should provide the distributed test sequencer to pass to {@link org.apache.qpid.test.framework.FrameworkBaseCase}
+ * tests.
+ *
+ * @return A distributed test sequencer.
+ */
+ public DistributedTestSequencer getDistributedTestSequencer()
+ {
+ return new InteropTestSequencer();
+ }
+
+ /**
+ * Produces all pairs of combinations of elements from two sets. The ordering of the elements in the pair is
+ * important, that is the pair <l, r> is distinct from <r, l>; both pairs are generated. For any element, i, in
+ * both the left and right sets, the reflexive pair <i, i> is not generated.
+ *
+ * @param left The left set.
+ * @param right The right set.
+ * @param <E> The type of the content of the pairs.
+ *
+ * @return All pairs formed from the permutations of all elements of the left and right sets.
+ */
+ private <E> Set<List<E>> allPairs(Set<E> left, Set<E> right)
+ {
+ log.debug("private <E> Set<List<E>> allPairs(Set<E> left = " + left + ", Set<E> right = " + right + "): called");
+
+ Set<List<E>> results = new HashSet<List<E>>();
+
+ // Form all pairs from left to right.
+ // Form all pairs from right to left.
+ for (E le : left)
+ {
+ for (E re : right)
+ {
+ if (!le.equals(re))
+ {
+ results.add(new Pair<E>(le, re));
+ results.add(new Pair<E>(re, le));
+ }
+ }
+ }
+
+ log.debug("results = " + results);
+
+ return results;
+ }
+
+ /**
+ * A simple implementation of a pair, using a list.
+ */
+ private class Pair<T> extends ArrayList<T>
+ {
+ /**
+ * Creates a new pair of elements.
+ *
+ * @param first The first element.
+ * @param second The second element.
+ */
+ public Pair(T first, T second)
+ {
+ super();
+ super.add(first);
+ super.add(second);
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/OptOutTestCase.java b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/OptOutTestCase.java new file mode 100644 index 0000000000..83ec12ad56 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/distributedtesting/OptOutTestCase.java @@ -0,0 +1,68 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.distributedtesting;
+
+import org.apache.qpid.test.framework.sequencers.DistributedTestSequencer;
+
+/**
+ * An OptOutTestCase is a test case that automatically fails. It is used when a list of test clients has been generated
+ * from a compulsory invite, but only some of those clients have responded to a specific test case invite. The clients
+ * that did not respond, may automatically be given a fail for some tests.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Fail the test with a suitable reason.
+ * </table>
+ */
+public class OptOutTestCase extends DistributedTestCase
+{
+ /**
+ * Creates a new coordinating test case with the specified name.
+ *
+ * @param name The test case name.
+ */
+ public OptOutTestCase(String name)
+ {
+ super(name);
+ }
+
+ /** Generates an appropriate test failure assertion. */
+ public void testOptOut()
+ {
+ DistributedTestSequencer sequencer = getDistributedTestSequencer();
+
+ fail("One of " + sequencer.getSender() + " and " + getDistributedTestSequencer().getReceivers()
+ + " opted out of the test.");
+ }
+
+ /**
+ * Should provide a translation from the junit method name of a test to its test case name as defined in the
+ * interop testing specification. For example the method "testP2P" might map onto the interop test case name
+ * "TC2_BasicP2P".
+ *
+ * @param methodName The name of the JUnit test method.
+ * @return The name of the corresponding interop test case.
+ */
+ public String getTestCaseNameForTestMethod(String methodName)
+ {
+ return "OptOutTest";
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/listeners/XMLTestListener.java b/java/systests/src/main/java/org/apache/qpid/test/framework/listeners/XMLTestListener.java new file mode 100644 index 0000000000..ee274a1e01 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/listeners/XMLTestListener.java @@ -0,0 +1,382 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.listeners;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+
+import org.apache.log4j.Logger;
+
+import uk.co.thebadgerset.junit.extensions.listeners.TKTestListener;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+import java.util.*;
+
+/**
+ * Listens for test results for a named test and outputs these in the standard JUnit XML format to the specified
+ * writer.
+ *
+ * <p/>The API for this listener accepts notifications about different aspects of a tests results through different
+ * methods, so some assumption needs to be made as to which test result a notification refers to. For example
+ * {@link #startTest} will be called, then possibly {@link #timing} will be called, even though the test instance is
+ * passed in both cases, it is not enough to distinguish a particular run of the test, as the test case instance may
+ * be being shared between multiple threads, or being run a repeated number of times, and can therfore be re-used
+ * between calls. The listeners make the assumption that, for every test, a unique thread will call {@link #startTest}
+ * and {@link #endTest} to delimit each test. All calls to set test parameters, timings, state and so on, will occur
+ * between the start and end and will be given with the same thread id as the start and end, so the thread id provides
+ * a unqiue value to identify a particular test run against.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Listen to test lifecycle notifications.
+ * <tr><td> Listen to test errors and failures.
+ * <tr><td> Listen to test timings.
+ * <tr><td> Listen to test memory usages.
+ * <tr><td> Listen to parameterized test parameters.
+ * <tr><th> Responsibilities
+ * </table>
+ *
+ * @todo Merge this class with CSV test listener, making the collection of results common to both, and only factoring
+ * out the results printing code into sub-classes. Provide a simple XML results formatter with the same format as
+ * the ant XML formatter, and a more structured one for outputing results with timings and summaries from
+ * performance tests.
+ */
+public class XMLTestListener implements TKTestListener
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(XMLTestListener.class);
+
+ /** The results file writer. */
+ protected Writer writer;
+
+ /** Holds the results for individual tests. */
+ // protected Map<Result, Result> results = new LinkedHashMap<Result, Result>();
+ // protected List<Result> results = new ArrayList<Result>();
+
+ /**
+ * Map for holding results on a per thread basis as they come in. A ThreadLocal is not used as sometimes an
+ * explicit thread id must be used, where notifications come from different threads than the ones that called
+ * the test method.
+ */
+ Map<Long, Result> threadLocalResults = Collections.synchronizedMap(new LinkedHashMap<Long, Result>());
+
+ /**
+ * Holds results for tests that have ended. Transferring these results here from the per-thread results map, means
+ * that the thread id is freed for the thread to generate more results.
+ */
+ List<Result> results = new ArrayList<Result>();
+
+ /** Holds the overall error count. */
+ protected int errors = 0;
+
+ /** Holds the overall failure count. */
+ protected int failures = 0;
+
+ /** Holds the overall tests run count. */
+ protected int runs = 0;
+
+ /** Holds the name of the class that tests are being run for. */
+ String testClassName;
+
+ /**
+ * Creates a new XML results output listener that writes to the specified location.
+ *
+ * @param writer The location to write results to.
+ * @param testClassName The name of the test class to include in the test results.
+ */
+ public XMLTestListener(Writer writer, String testClassName)
+ {
+ log.debug("public XMLTestListener(Writer writer, String testClassName = " + testClassName + "): called");
+
+ this.writer = writer;
+ this.testClassName = testClassName;
+ }
+
+ /**
+ * Resets the test results to the default state of time zero, memory usage zero, parameter zero, test passed.
+ *
+ * @param test The test to resest any results for.
+ * @param threadId Optional thread id if not calling from thread that started the test method. May be null.
+ */
+ public void reset(Test test, Long threadId)
+ {
+ log.debug("public void reset(Test test = " + test + ", Long threadId = " + threadId + "): called");
+
+ XMLTestListener.Result r =
+ (threadId == null) ? threadLocalResults.get(Thread.currentThread().getId()) : threadLocalResults.get(threadId);
+
+ r.error = null;
+ r.failure = null;
+
+ }
+
+ /**
+ * Notification that a test started.
+ *
+ * @param test The test that started.
+ */
+ public void startTest(Test test)
+ {
+ log.debug("public void startTest(Test test = " + test + "): called");
+
+ Result newResult = new Result(test.getClass().getName(), ((TestCase) test).getName());
+
+ // Initialize the thread local test results.
+ threadLocalResults.put(Thread.currentThread().getId(), newResult);
+ runs++;
+ }
+
+ /**
+ * Should be called every time a test completes with the run time of that test.
+ *
+ * @param test The name of the test.
+ * @param nanos The run time of the test in nanoseconds.
+ * @param threadId Optional thread id if not calling from thread that started the test method. May be null.
+ */
+ public void timing(Test test, long nanos, Long threadId)
+ { }
+
+ /**
+ * Should be called every time a test completed with the amount of memory used before and after the test was run.
+ *
+ * @param test The test which memory was measured for.
+ * @param memStart The total JVM memory used before the test was run.
+ * @param memEnd The total JVM memory used after the test was run.
+ * @param threadId Optional thread id if not calling from thread that started the test method. May be null.
+ */
+ public void memoryUsed(Test test, long memStart, long memEnd, Long threadId)
+ { }
+
+ /**
+ * Should be called every time a parameterized test completed with the int value of its test parameter.
+ *
+ * @param test The test which memory was measured for.
+ * @param parameter The int parameter value.
+ * @param threadId Optional thread id if not calling from thread that started the test method. May be null.
+ */
+ public void parameterValue(Test test, int parameter, Long threadId)
+ { }
+
+ /**
+ * Should be called every time a test completes with the current number of test threads running.
+ *
+ * @param test The test for which the measurement is being generated.
+ * @param threads The number of tests being run concurrently.
+ * @param threadId Optional thread id if not calling from thread that started the test method. May be null.
+ */
+ public void concurrencyLevel(Test test, int threads, Long threadId)
+ { }
+
+ /**
+ * Notifies listeners of the tests read/set properties.
+ *
+ * @param properties The tests read/set properties.
+ */
+ public void properties(Properties properties)
+ { }
+
+ /**
+ * Notification that a test ended.
+ *
+ * @param test The test that ended.
+ */
+ public void endTest(Test test)
+ {
+ log.debug("public void endTest(Test test = " + test + "): called");
+
+ // Move complete test results into the completed tests list.
+ Result r = threadLocalResults.get(Thread.currentThread().getId());
+ results.add(r);
+
+ // Clear all the test results for the thread.
+ threadLocalResults.remove(Thread.currentThread().getId());
+ }
+
+ /**
+ * Called when a test completes. Success, failure and errors. This method should be used when registering an
+ * end test from a different thread than the one that started the test.
+ *
+ * @param test The test which completed.
+ * @param threadId Optional thread id if not calling from thread that started the test method. May be null.
+ */
+ public void endTest(Test test, Long threadId)
+ {
+ log.debug("public void endTest(Test test = " + test + ", Long threadId = " + threadId + "): called");
+
+ // Move complete test results into the completed tests list.
+ Result r =
+ (threadId == null) ? threadLocalResults.get(Thread.currentThread().getId()) : threadLocalResults.get(threadId);
+ results.add(r);
+
+ // Clear all the test results for the thread.
+ threadLocalResults.remove(Thread.currentThread().getId());
+ }
+
+ /**
+ * An error occurred.
+ *
+ * @param test The test in which the error occurred.
+ * @param t The throwable that resulted from the error.
+ */
+ public void addError(Test test, Throwable t)
+ {
+ log.debug("public void addError(Test test = " + test + ", Throwable t = " + t + "): called");
+
+ Result r = threadLocalResults.get(Thread.currentThread().getId());
+ r.error = t;
+ errors++;
+ }
+
+ /**
+ * A failure occurred.
+ *
+ * @param test The test in which the failure occurred.
+ * @param t The JUnit assertions that led to the failure.
+ */
+ public void addFailure(Test test, AssertionFailedError t)
+ {
+ log.debug("public void addFailure(Test test = " + test + ", AssertionFailedError t = " + t + "): called");
+
+ Result r = threadLocalResults.get(Thread.currentThread().getId());
+ r.failure = t;
+ failures++;
+ }
+
+ /**
+ * Called when a test completes to mark it as a test fail. This method should be used when registering a
+ * failure from a different thread than the one that started the test.
+ *
+ * @param test The test which failed.
+ * @param e The assertion that failed the test.
+ * @param threadId Optional thread id if not calling from thread that started the test method. May be null.
+ */
+ public void addFailure(Test test, AssertionFailedError e, Long threadId)
+ {
+ log.debug("public void addFailure(Test test, AssertionFailedError e, Long threadId): called");
+
+ Result r =
+ (threadId == null) ? threadLocalResults.get(Thread.currentThread().getId()) : threadLocalResults.get(threadId);
+ r.failure = e;
+ failures++;
+ }
+
+ /**
+ * Notifies listeners of the start of a complete run of tests.
+ */
+ public void startBatch()
+ {
+ log.debug("public void startBatch(): called");
+
+ // Reset all results counts.
+ threadLocalResults = Collections.synchronizedMap(new HashMap<Long, Result>());
+ errors = 0;
+ failures = 0;
+ runs = 0;
+
+ // Write out the file header.
+ try
+ {
+ writer.write("<?xml version=\"1.0\" ?>\n");
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Unable to write the test results.", e);
+ }
+ }
+
+ /**
+ * Notifies listeners of the end of a complete run of tests.
+ *
+ * @param parameters The optional test parameters to log out with the batch results.
+ */
+ public void endBatch(Properties parameters)
+ {
+ log.debug("public void endBatch(Properties parameters = " + parameters + "): called");
+
+ // Write out the results.
+ try
+ {
+ // writer.write("<?xml version=\"1.0\" ?>\n");
+ writer.write("<testsuite errors=\"" + errors + "\" failures=\"" + failures + "\" tests=\"" + runs + "\" name=\""
+ + testClassName + "\">\n");
+
+ for (Result result : results)
+ {
+ writer.write(" <testcase classname=\"" + result.testClass + "\" name=\"" + result.testName + "\">\n");
+
+ if (result.error != null)
+ {
+ writer.write(" <error type=\"" + result.error.getClass() + "\">");
+ result.error.printStackTrace(new PrintWriter(writer));
+ writer.write(" </error>");
+ }
+ else if (result.failure != null)
+ {
+ writer.write(" <failure type=\"" + result.failure.getClass() + "\">");
+ result.failure.printStackTrace(new PrintWriter(writer));
+ writer.write(" </failure>");
+ }
+
+ writer.write(" </testcase>\n");
+ }
+
+ writer.write("</testsuite>\n");
+ writer.flush();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Unable to write the test results.", e);
+ }
+ }
+
+ /**
+ * Used to capture the results of a particular test run.
+ */
+ protected static class Result
+ {
+ /** Holds the name of the test class. */
+ public String testClass;
+
+ /** Holds the name of the test method. */
+ public String testName;
+
+ /** Holds the exception that caused error in this test. */
+ public Throwable error;
+
+ /** Holds the assertion exception that caused failure in this test. */
+ public AssertionFailedError failure;
+
+ /**
+ * Creates a placeholder for the results of a test.
+ *
+ * @param testClass The test class.
+ * @param testName The name of the test that was run.
+ */
+ public Result(String testClass, String testName)
+ {
+ this.testClass = testClass;
+ this.testName = testName;
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/CircuitImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/CircuitImpl.java new file mode 100644 index 0000000000..3c678eef7d --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/CircuitImpl.java @@ -0,0 +1,394 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.localcircuit;
+
+import org.apache.qpid.client.AMQSession;
+import org.apache.qpid.test.framework.*;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import javax.jms.*;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * CircuitImpl provides an implementation of the test circuit. This is a first prototype implementation and only supports
+ * a single producer/consumer on each end of the circuit, with both ends of the circuit on the same JVM.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Supply the publishing and receiving ends of a test messaging circuit.
+ * <td> {@link PublisherImpl}, {@link ReceiverImpl}
+ * <tr><td> Start the circuit running.
+ * <tr><td> Close the circuit down.
+ * <tr><td> Take a reading of the circuits state.
+ * <tr><td> Apply assertions against the circuits state. <td> {@link org.apache.qpid.test.framework.Assertion}
+ * <tr><td> Send test messages over the circuit.
+ * <tr><td> Perform the default test procedure on the circuit.
+ * <tr><td> Provide access to connection and session exception monitors <td> {@link org.apache.qpid.test.framework.ExceptionMonitor}
+ * </table>
+ *
+ * @todo Add ability to create routes with no consumers active on them. Immediate/Mandatory tests are closing consumers
+ * themsleves to create this scenario. Should make it part of the test configuration.
+ */
+public class CircuitImpl implements Circuit
+{
+ /** Used to create unique destination names for each test. */
+ private static AtomicLong uniqueDestsId = new AtomicLong();
+
+ /** Holds the test configuration for the circuit. */
+ private ParsedProperties testProps;
+
+ /** Holds the publishing end of the circuit. */
+ private PublisherImpl publisher;
+
+ /** Holds the receiving end of the circuit. */
+ private ReceiverImpl receiver;
+
+ /** Holds the connection for the publishing end of the circuit. */
+ private Connection connection;
+
+ /** Holds the exception listener for the connection on the publishing end of the circuit. */
+ private ExceptionMonitor connectionExceptionMonitor;
+
+ /** Holds the exception listener for the session on the publishing end of the circuit. */
+ private ExceptionMonitor exceptionMonitor;
+
+ /**
+ * Creates a test circuit using the specified test parameters. The publisher, receivers, connection and
+ * connection monitor must already have been created, to assemble the circuit.
+ *
+ * @param testProps The test parameters.
+ * @param publisher The test publisher.
+ * @param receiver The test receivers.
+ * @param connection The connection.
+ * @param connectionExceptionMonitor The connection exception monitor.
+ */
+ protected CircuitImpl(ParsedProperties testProps, PublisherImpl publisher, ReceiverImpl receiver, Connection connection,
+ ExceptionMonitor connectionExceptionMonitor)
+ {
+ this.testProps = testProps;
+ this.publisher = publisher;
+ this.receiver = receiver;
+ this.connection = connection;
+ this.connectionExceptionMonitor = connectionExceptionMonitor;
+ this.exceptionMonitor = new ExceptionMonitor();
+
+ // Set this as the parent circuit on the publisher and receivers.
+ publisher.setCircuit(this);
+ receiver.setCircuit(this);
+ }
+
+ /**
+ * Creates a test circuit from the specified test parameters.
+ *
+ * @param testProps The test parameters.
+ *
+ * @return A connected and ready to start, test circuit.
+ */
+ public static Circuit createCircuit(ParsedProperties testProps)
+ {
+ // Create a standard publisher/receivers test client pair on a shared connection, individual sessions.
+ try
+ {
+ // ParsedProperties testProps = new ParsedProperties(testProps);
+
+ // Get a unique offset to append to destination names to make them unique to the connection.
+ long uniqueId = uniqueDestsId.incrementAndGet();
+
+ // Extract the standard test configuration parameters relevant to the connection.
+ String destinationSendRoot =
+ testProps.getProperty(MessagingTestConfigProperties.SEND_DESTINATION_NAME_ROOT_PROPNAME) + "_" + uniqueId;
+ String destinationReceiveRoot =
+ testProps.getProperty(MessagingTestConfigProperties.RECEIVE_DESTINATION_NAME_ROOT_PROPNAME) + "_" + uniqueId;
+ boolean createPublisherProducer =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.PUBLISHER_PRODUCER_BIND_PROPNAME);
+ boolean createPublisherConsumer =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.PUBLISHER_CONSUMER_BIND_PROPNAME);
+ boolean createReceiverProducer =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.RECEIVER_PRODUCER_BIND_PROPNAME);
+ boolean createReceiverConsumer =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.RECEIVER_CONSUMER_BIND_PROPNAME);
+
+ // Check which JMS flags and options are to be set.
+ int ackMode = testProps.getPropertyAsInteger(MessagingTestConfigProperties.ACK_MODE_PROPNAME);
+ boolean useTopics = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.PUBSUB_PROPNAME);
+ boolean transactional = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.TRANSACTED_PROPNAME);
+ boolean durableSubscription =
+ testProps.getPropertyAsBoolean(MessagingTestConfigProperties.DURABLE_SUBSCRIPTION_PROPNAME);
+
+ // Check if any Qpid/AMQP specific flags or options need to be set.
+ boolean immediate = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.IMMEDIATE_PROPNAME);
+ boolean mandatory = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.MANDATORY_PROPNAME);
+ boolean needsQpidOptions = immediate | mandatory;
+
+ /*log.debug("ackMode = " + ackMode);
+ log.debug("useTopics = " + useTopics);
+ log.debug("destinationSendRoot = " + destinationSendRoot);
+ log.debug("destinationReceiveRoot = " + destinationReceiveRoot);
+ log.debug("createPublisherProducer = " + createPublisherProducer);
+ log.debug("createPublisherConsumer = " + createPublisherConsumer);
+ log.debug("createReceiverProducer = " + createReceiverProducer);
+ log.debug("createReceiverConsumer = " + createReceiverConsumer);
+ log.debug("transactional = " + transactional);
+ log.debug("immediate = " + immediate);
+ log.debug("mandatory = " + mandatory);
+ log.debug("needsQpidOptions = " + needsQpidOptions);*/
+
+ // Create connection, sessions and producer/consumer pairs on each session.
+ Connection connection = TestUtils.createConnection(testProps);
+
+ // Add the connection exception listener to assert on exception conditions with.
+ ExceptionMonitor exceptionMonitor = new ExceptionMonitor();
+ connection.setExceptionListener(exceptionMonitor);
+
+ Session publisherSession = connection.createSession(transactional, ackMode);
+ Session receiverSession = connection.createSession(transactional, ackMode);
+
+ Destination publisherProducerDestination =
+ useTopics ? publisherSession.createTopic(destinationSendRoot)
+ : publisherSession.createQueue(destinationSendRoot);
+
+ MessageProducer publisherProducer =
+ createPublisherProducer
+ ? (needsQpidOptions
+ ? ((AMQSession) publisherSession).createProducer(publisherProducerDestination, mandatory, immediate)
+ : publisherSession.createProducer(publisherProducerDestination)) : null;
+
+ MessageConsumer publisherConsumer =
+ createPublisherConsumer
+ ? publisherSession.createConsumer(publisherSession.createQueue(destinationReceiveRoot)) : null;
+
+ if (publisherConsumer != null)
+ {
+ publisherConsumer.setMessageListener(new MessageMonitor());
+ }
+
+ MessageProducer receiverProducer =
+ createReceiverProducer ? receiverSession.createProducer(receiverSession.createQueue(destinationReceiveRoot))
+ : null;
+
+ Destination receiverConsumerDestination =
+ useTopics ? receiverSession.createTopic(destinationSendRoot)
+ : receiverSession.createQueue(destinationSendRoot);
+
+ MessageConsumer receiverConsumer =
+ createReceiverConsumer
+ ? ((durableSubscription && useTopics)
+ ? receiverSession.createDurableSubscriber((Topic) receiverConsumerDestination, "testsub")
+ : receiverSession.createConsumer(receiverConsumerDestination)) : null;
+
+ if (receiverConsumer != null)
+ {
+ receiverConsumer.setMessageListener(new MessageMonitor());
+ }
+
+ // Start listening for incoming messages.
+ connection.start();
+
+ // Package everything up.
+ PublisherImpl publisher = new PublisherImpl(publisherProducer, publisherConsumer, publisherSession);
+ ReceiverImpl receiver = new ReceiverImpl(receiverProducer, receiverConsumer, receiverSession);
+
+ return new CircuitImpl(testProps, publisher, receiver, connection, exceptionMonitor);
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Could not create publisher/receivers pair due to a JMSException.", e);
+ }
+ }
+
+ /**
+ * Gets the interface on the publishing end of the circuit.
+ *
+ * @return The publishing end of the circuit.
+ */
+ public Publisher getPublisher()
+ {
+ return publisher;
+ }
+
+ /**
+ * Gets the interface on the receiving end of the circuit.
+ *
+ * @return The receiving end of the circuit.
+ */
+ public Receiver getReceiver()
+ {
+ return receiver;
+ }
+
+ /**
+ * Checks the test circuit. The effect of this is to gather the circuits state, for both ends of the circuit,
+ * into a report, against which assertions may be checked.
+ */
+ public void check()
+ { }
+
+ /**
+ * Applied a list of assertions against the test circuit. The {@link #check()} method should be called before doing
+ * this, to ensure that the circuit has gathered its state into a report to assert against.
+ *
+ * @param assertions The list of assertions to apply.
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> applyAssertions(List<Assertion> assertions)
+ {
+ List<Assertion> failures = new LinkedList<Assertion>();
+
+ for (Assertion assertion : assertions)
+ {
+ if (!assertion.apply())
+ {
+ failures.add(assertion);
+ }
+ }
+
+ return failures;
+ }
+
+ /**
+ * Connects and starts the circuit. After this method is called the circuit is ready to send messages.
+ */
+ public void start()
+ { }
+
+ /**
+ * Closes the circuit. All associated resources are closed.
+ */
+ public void close()
+ {
+ try
+ {
+ publisher.close();
+ receiver.close();
+ connection.close();
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Got JMSException during close.", e);
+ }
+ }
+
+ /**
+ * Sends a message on the test circuit. The exact nature of the message sent is controlled by the test parameters.
+ */
+ public void send()
+ {
+ boolean transactional = testProps.getPropertyAsBoolean(MessagingTestConfigProperties.TRANSACTED_PROPNAME);
+
+ // Send an immediate message through the publisher and ensure that it results in a JMSException.
+ try
+ {
+ getPublisher().send(createTestMessage(getPublisher()));
+
+ if (transactional)
+ {
+ getPublisher().getSession().commit();
+ }
+ }
+ catch (JMSException e)
+ {
+ exceptionMonitor.onException(e);
+ }
+ }
+
+ /**
+ * Runs the default test procedure against the circuit, and checks that all of the specified assertions hold. The
+ * outline of the default test procedure is:
+ *
+ * <p/><pre>
+ * Start the circuit.
+ * Send test messages.
+ * Request a status report.
+ * Assert conditions on the publishing end of the circuit.
+ * Assert conditions on the receiving end of the circuit.
+ * Close the circuit.
+ * Pass with no failed assertions or fail with a list of failed assertions.
+ * </pre>
+ *
+ * @param numMessages The number of messages to send using the default test procedure.
+ * @param assertions The list of assertions to apply.
+ * @return Any assertions that failed.
+ */
+ public List<Assertion> test(int numMessages, List<Assertion> assertions)
+ {
+ // Start the test circuit.
+ start();
+
+ // Send the requested number of test messages.
+ for (int i = 0; i < numMessages; i++)
+ {
+ send();
+ }
+
+ // Inject a short pause to allow time for exceptions to come back asynchronously.
+ TestUtils.pause(100L);
+
+ // Request a status report.
+ check();
+
+ // Apply all of the requested assertions, keeping record of any that fail.
+ List<Assertion> failures = applyAssertions(assertions);
+
+ // Clean up the publisher/receivers/session/connections.
+ close();
+
+ // Return any failed assertions to the caller.
+ return failures;
+ }
+
+ /**
+ * Creates a message with the properties defined as per the test parameters.
+ *
+ * @param client The circuit end to create the message on.
+ *
+ * @return The test message.
+ *
+ * @throws JMSException Any JMSException occurring during creation of the message is allowed to fall through.
+ */
+ private Message createTestMessage(CircuitEnd client) throws JMSException
+ {
+ return client.getSession().createTextMessage("Hello");
+ }
+
+ /**
+ * Gets the exception monitor for the publishing ends connection.
+ *
+ * @return The exception monitor for the publishing ends connection.
+ */
+ public ExceptionMonitor getConnectionExceptionMonitor()
+ {
+ return connectionExceptionMonitor;
+ }
+
+ /**
+ * Gets the exception monitor for the publishing ends session.
+ *
+ * @return The exception monitor for the publishing ends session.
+ */
+ public ExceptionMonitor getExceptionMonitor()
+ {
+ return exceptionMonitor;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/PublisherImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/PublisherImpl.java new file mode 100644 index 0000000000..5b63607867 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/PublisherImpl.java @@ -0,0 +1,162 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.localcircuit;
+
+import org.apache.qpid.client.AMQNoConsumersException;
+import org.apache.qpid.client.AMQNoRouteException;
+import org.apache.qpid.test.framework.localcircuit.CircuitImpl;
+import org.apache.qpid.test.framework.*;
+
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+/**
+ * Provides an implementation of the {@link org.apache.qpid.test.framework.Publisher} interface that wraps a single message producer and consumer on
+ * a single session.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Provide a message producer for sending messages.
+ * <tr><td> Provide a message consumer for receiving messages.
+ * <tr><td> Provide assertion that the publisher received no exceptions.
+ * <tr><td> Provide assertion that the publisher received a no consumers error code.
+ * <tr><td> Provide assertion that the publisher received a no route error code.
+ * </table>
+ */
+public class PublisherImpl extends CircuitEndBase implements Publisher
+{
+ /** Holds a reference to the containing circuit. */
+ private CircuitImpl circuit;
+
+ /**
+ * Creates a circuit end point on the specified producer, consumer and session.
+ *
+ * @param producer The message producer for the circuit end point.
+ * @param consumer The message consumer for the circuit end point.
+ * @param session The session for the circuit end point.
+ */
+ public PublisherImpl(MessageProducer producer, MessageConsumer consumer, Session session)
+ {
+ super(producer, consumer, session);
+ }
+
+ /**
+ * Provides an assertion that the publisher encountered no exceptions.
+ *
+ * @return An assertion that the publisher encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion()
+ {
+ return new AssertionBase()
+ {
+ public boolean apply()
+ {
+ boolean passed = true;
+ ExceptionMonitor sessionExceptionMonitor = circuit.getExceptionMonitor();
+ ExceptionMonitor connectionExceptionMonitor = circuit.getConnectionExceptionMonitor();
+
+ if (!connectionExceptionMonitor.assertNoExceptions())
+ {
+ passed = false;
+ addError("Was expecting no exceptions.\n");
+ addError("Got the following exceptions on the connection, "
+ + circuit.getConnectionExceptionMonitor());
+ }
+
+ if (!sessionExceptionMonitor.assertNoExceptions())
+ {
+ passed = false;
+ addError("Was expecting no exceptions.\n");
+ addError("Got the following exceptions on the producer, " + circuit.getExceptionMonitor());
+ }
+
+ return passed;
+ }
+ };
+ }
+
+ /**
+ * Provides an assertion that the publisher got a no consumers exception on every message.
+ *
+ * @return An assertion that the publisher got a no consumers exception on every message.
+ */
+ public Assertion noConsumersAssertion()
+ {
+ return new AssertionBase()
+ {
+ public boolean apply()
+ {
+ boolean passed = true;
+ ExceptionMonitor connectionExceptionMonitor = circuit.getConnectionExceptionMonitor();
+
+ if (!connectionExceptionMonitor.assertOneJMSExceptionWithLinkedCause(AMQNoConsumersException.class))
+ {
+ addError("Was expecting linked exception type " + AMQNoConsumersException.class.getName()
+ + " on the connection.\n");
+ addError((connectionExceptionMonitor.size() > 0)
+ ? ("Actually got the following exceptions on the connection, " + connectionExceptionMonitor)
+ : "Got no exceptions on the connection.");
+ }
+
+ return passed;
+ }
+ };
+ }
+
+ /**
+ * Provides an assertion that the publisher got a no rout exception on every message.
+ *
+ * @return An assertion that the publisher got a no rout exception on every message.
+ */
+ public Assertion noRouteAssertion()
+ {
+ return new AssertionBase()
+ {
+ public boolean apply()
+ {
+ boolean passed = true;
+ ExceptionMonitor connectionExceptionMonitor = circuit.getConnectionExceptionMonitor();
+
+ if (!connectionExceptionMonitor.assertOneJMSExceptionWithLinkedCause(AMQNoRouteException.class))
+ {
+ addError("Was expecting linked exception type " + AMQNoRouteException.class.getName()
+ + " on the connection.\n");
+ addError((connectionExceptionMonitor.size() > 0)
+ ? ("Actually got the following exceptions on the connection, " + connectionExceptionMonitor)
+ : "Got no exceptions on the connection.");
+ }
+
+ return passed;
+ }
+ };
+ }
+
+ /**
+ * Sets the contianing circuit.
+ *
+ * @param circuit The containing circuit.
+ */
+ public void setCircuit(CircuitImpl circuit)
+ {
+ this.circuit = circuit;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/ReceiverImpl.java b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/ReceiverImpl.java new file mode 100644 index 0000000000..6dd7056806 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/localcircuit/ReceiverImpl.java @@ -0,0 +1,90 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.localcircuit;
+
+import org.apache.qpid.test.framework.localcircuit.CircuitImpl;
+import org.apache.qpid.test.framework.CircuitEndBase;
+import org.apache.qpid.test.framework.Receiver;
+import org.apache.qpid.test.framework.Assertion;
+
+import javax.jms.MessageConsumer;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+
+/**
+ * Provides an implementation of the {@link org.apache.qpid.test.framework.Receiver} interface that wraps a single message producer and consumer on
+ * a single session.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Provide a message producer for sending messages.
+ * <tr><td> Provide a message consumer for receiving messages.
+ * <tr><td> Provide assertion that the receivers received no exceptions.
+ * <tr><td> Provide assertion that the receivers received all test messages sent to it.
+ * </table>
+ */
+public class ReceiverImpl extends CircuitEndBase implements Receiver
+{
+ /** Holds a reference to the containing circuit. */
+ private CircuitImpl circuit;
+
+ /**
+ * Creates a circuit end point on the specified producer, consumer and session.
+ *
+ * @param producer The message producer for the circuit end point.
+ * @param consumer The message consumer for the circuit end point.
+ * @param session The session for the circuit end point.
+ */
+ public ReceiverImpl(MessageProducer producer, MessageConsumer consumer, Session session)
+ {
+ super(producer, consumer, session);
+ }
+
+ /**
+ * Provides an assertion that the receivers encountered no exceptions.
+ *
+ * @return An assertion that the receivers encountered no exceptions.
+ */
+ public Assertion noExceptionsAssertion()
+ {
+ return null;
+ }
+
+ /**
+ * Provides an assertion that the receivers got all messages that were sent to it.
+ *
+ * @return An assertion that the receivers got all messages that were sent to it.
+ */
+ public Assertion allMessagesAssertion()
+ {
+ return null;
+ }
+
+ /**
+ * Sets the contianing circuit.
+ *
+ * @param circuit The containing circuit.
+ */
+ public void setCircuit(CircuitImpl circuit)
+ {
+ this.circuit = circuit;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/package.html b/java/systests/src/main/java/org/apache/qpid/test/framework/package.html new file mode 100644 index 0000000000..f07a5118e7 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/package.html @@ -0,0 +1,22 @@ +<html>
+<body>
+<p/>A framework for testing Qpid, built around a standard 'test circuit' design. The idea behind this framework is the
+use of a test circuit which is configured by a set of test parameters, that may be projected onto a topology of
+test nodes, with tests scripted to run over test circuits, making as few assumptions as possible about the underlying
+topology. The standardization of the design, whilst limiting in some respectes, allows a large variety of test
+scenarios to be written with minimal amounts of coding.
+
+<p/>The standard consruction block for a test, is a test circuit. This consists of a publisher, and a receiver. The
+publisher and receiver may reside on the same machine, or may be distributed. Will use a standard set of properties to
+define the desired circuit topology.
+
+<p/>Tests are always to be controlled from the publishing side only. The receiving end of the circuit is to be exposed
+to the test code through an interface, that abstracts as much as possible the receiving end of the test. The interface
+exposes a set of 'assertions' that may be applied to the receiving end of the test circuit.
+
+<p/>In the case where the receiving end of the circuit resides on the same JVM, the assertions will call the receivers
+code locally. Where the receiving end is distributed accross one or more machines, the assertions will be applied to a
+test report gethered from all of the receivers. Test code will be written to the assertions making as few assumptions
+as possible about the exact test topology.
+</body>
+</html>
\ No newline at end of file diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseDistributedTestSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseDistributedTestSequencer.java new file mode 100644 index 0000000000..a0e3d3b4a6 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/BaseDistributedTestSequencer.java @@ -0,0 +1,129 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.sequencers;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.distributedtesting.DistributedTestCase;
+import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.util.ConversationFactory;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public abstract class BaseDistributedTestSequencer implements DistributedTestSequencer
+{
+ /** Used for debugging. */
+ private final Logger log = Logger.getLogger(DistributedTestCase.class);
+
+ /** Holds the contact details for the sending test client. */
+ protected TestClientDetails sender;
+
+ /** Holds the contact details for the receving test client. */
+ protected List<TestClientDetails> receivers = new LinkedList<TestClientDetails>();
+
+ /** Holds the conversation factory over which to coordinate the test. */
+ protected ConversationFactory conversationFactory;
+
+ /**
+ * Creates a test circuit for the test, configered by the test parameters specified.
+ *
+ * @param testProperties The test parameters.
+ * @return A test circuit.
+ */
+ public Circuit createCircuit(Properties testProperties)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Sets the sender test client to coordinate the test with.
+ *
+ * @param sender The contact details of the sending client in the test.
+ */
+ public void setSender(TestClientDetails sender)
+ {
+ log.debug("public void setSender(TestClientDetails sender = " + sender + "): called");
+
+ this.sender = sender;
+ }
+
+ /**
+ * Sets the receiving test client to coordinate the test with.
+ *
+ * @param receiver The contact details of the sending client in the test.
+ */
+ public void setReceiver(TestClientDetails receiver)
+ {
+ log.debug("public void setReceiver(TestClientDetails receivers = " + receiver + "): called");
+
+ this.receivers.add(receiver);
+ }
+
+ /**
+ * Supplies the sending test client.
+ *
+ * @return The sending test client.
+ */
+ public TestClientDetails getSender()
+ {
+ return sender;
+ }
+
+ /**
+ * Supplies the receiving test client.
+ *
+ * @return The receiving test client.
+ */
+ public List<TestClientDetails> getReceivers()
+ {
+ return receivers;
+ }
+
+ /**
+ * Accepts the conversation factory over which to hold the test coordinating conversation.
+ *
+ * @param conversationFactory The conversation factory to coordinate the test over.
+ */
+ public void setConversationFactory(ConversationFactory conversationFactory)
+ {
+ this.conversationFactory = conversationFactory;
+ }
+
+ /**
+ * Provides the conversation factory for providing the distributed test sequencing conversations over the test
+ * connection.
+ *
+ * @return The conversation factory to create test sequencing conversations with.
+ */
+ public ConversationFactory getConversationFactory()
+ {
+ return conversationFactory;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/DistributedTestSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/DistributedTestSequencer.java new file mode 100644 index 0000000000..73e61ec921 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/DistributedTestSequencer.java @@ -0,0 +1,75 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.sequencers;
+
+import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.util.ConversationFactory;
+
+import java.util.List;
+
+/**
+ * A DistributedTestSequencer is a test sequencer that coordinates activity amongst many
+ * {@link org.apache.qpid.test.framework.distributedtesting.TestClient}s.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Accept notification of test case participants.
+ * <tr><td> Accept JMS Connection to carry out the coordination over.
+ * <tr><td> Coordinate a test sequence amongst participants. <td> {@link ConversationFactory}
+ * </table>
+ */
+public interface DistributedTestSequencer extends TestCaseSequencer
+{
+ /**
+ * Sets the sender test client to coordinate the test with.
+ *
+ * @param sender The contact details of the sending client in the test.
+ */
+ public void setSender(TestClientDetails sender);
+
+ /**
+ * Sets the receiving test client to coordinate the test with.
+ *
+ * @param receiver The contact details of the sending client in the test.
+ */
+ public void setReceiver(TestClientDetails receiver);
+
+ /**
+ * Supplies the sending test client.
+ *
+ * @return The sending test client.
+ */
+ public TestClientDetails getSender();
+
+ /**
+ * Supplies the receiving test client.
+ *
+ * @return The receiving test client.
+ */
+ public List<TestClientDetails> getReceivers();
+
+ /**
+ * Accepts the conversation factory over which to hold the test coordinating conversation.
+ *
+ * @param conversationFactory The conversation factory to coordinate the test over.
+ */
+ public void setConversationFactory(ConversationFactory conversationFactory);
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutTestSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutTestSequencer.java new file mode 100644 index 0000000000..a116b23065 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/FanOutTestSequencer.java @@ -0,0 +1,171 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.sequencers;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.test.framework.Assertion;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.TestUtils;
+import org.apache.qpid.util.ConversationFactory;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class FanOutTestSequencer extends BaseDistributedTestSequencer
+{
+ /** Used for debugging. */
+ Logger log = Logger.getLogger(FanOutTestSequencer.class);
+
+ /**
+ * Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
+ * begining the test, gathering the test reports from the participants, and checking for assertion failures against
+ * the test reports.
+ *
+ * @param testCircuit The test circuit.
+ * @param assertions The list of assertions to apply to the test circuit.
+ * @param testProperties The test case definition.
+ */
+ public void sequenceTest(Circuit testCircuit, List<Assertion> assertions, Properties testProperties)
+ {
+ log.debug("protected Message[] sequenceTest(Object... testProperties = " + testProperties + "): called");
+
+ TestClientDetails sender = getSender();
+ List<TestClientDetails> receivers = getReceivers();
+ ConversationFactory conversationFactory = getConversationFactory();
+
+ try
+ {
+ // Create a conversation on the sender clients private control rouete.
+ Session session = conversationFactory.getSession();
+ Destination senderControlTopic = session.createTopic(sender.privateControlKey);
+ ConversationFactory.Conversation senderConversation = conversationFactory.startConversation();
+
+ // Assign the sender role to the sending test client.
+ Message assignSender = conversationFactory.getSession().createMessage();
+ TestUtils.setPropertiesOnMessage(assignSender, testProperties);
+ assignSender.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
+ assignSender.setStringProperty("ROLE", "SENDER");
+ assignSender.setStringProperty("CLIENT_NAME", "Sustained_SENDER");
+
+ senderConversation.send(senderControlTopic, assignSender);
+
+ // Wait for the sender to confirm its role.
+ senderConversation.receive();
+
+ // Assign the receivers roles.
+ for (TestClientDetails receiver : receivers)
+ {
+ assignReceiverRole(receiver, testProperties, true);
+ }
+
+ // Start the test on the sender.
+ Message start = session.createMessage();
+ start.setStringProperty("CONTROL_TYPE", "START");
+
+ senderConversation.send(senderControlTopic, start);
+
+ // Wait for the test sender to return its report.
+ Message senderReport = senderConversation.receive();
+ TestUtils.pause(500);
+
+ // Ask the receivers for their reports.
+ Message statusRequest = session.createMessage();
+ statusRequest.setStringProperty("CONTROL_TYPE", "STATUS_REQUEST");
+
+ // Gather the reports from all of the receiving clients.
+
+ // Return all of the test reports, the senders report first.
+ // return new Message[] { senderReport };
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("Unhandled JMSException.");
+ }
+ }
+
+ /**
+ * Creates a test circuit for the test, configered by the test parameters specified.
+ *
+ * @param testProperties The test parameters.
+ * @return A test circuit.
+ */
+ public Circuit createCircuit(ParsedProperties testProperties)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+
+ /**
+ * Assigns the receivers role to the specified test client that is to act as a receivers during the test. This method
+ * does not always wait for the receiving clients to confirm their role assignments. This is because this method
+ * may be called from an 'onMessage' method, when a client is joining the test at a later point in time, and it
+ * is not possible to do a synchronous receive during an 'onMessage' method. There is a flag to indicate whether
+ * or not to wait for role confirmations.
+ *
+ * @param receiver The test client to assign the receivers role to.
+ * @param testProperties The test parameters.
+ * @param confirm Indicates whether role confirmation should be waited for.
+ *
+ * @throws JMSException Any JMSExceptions occurring during the conversation are allowed to fall through.
+ */
+ protected void assignReceiverRole(TestClientDetails receiver, Properties testProperties, boolean confirm)
+ throws JMSException
+ {
+ log.info("assignReceiverRole(TestClientDetails receivers = " + receiver + ", Map<String, Object> testProperties = "
+ + testProperties + "): called");
+
+ ConversationFactory conversationFactory = getConversationFactory();
+
+ // Create a conversation with the receiving test client.
+ Session session = conversationFactory.getSession();
+ Destination receiverControlTopic = session.createTopic(receiver.privateControlKey);
+ ConversationFactory.Conversation receiverConversation = conversationFactory.startConversation();
+
+ // Assign the receivers role to the receiving client.
+ Message assignReceiver = session.createMessage();
+ TestUtils.setPropertiesOnMessage(assignReceiver, testProperties);
+ assignReceiver.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
+ assignReceiver.setStringProperty("ROLE", "RECEIVER");
+ assignReceiver.setStringProperty("CLIENT_NAME", receiver.clientName);
+
+ receiverConversation.send(receiverControlTopic, assignReceiver);
+
+ // Wait for the role confirmation to come back.
+ if (confirm)
+ {
+ receiverConversation.receive();
+ }
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropTestSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropTestSequencer.java new file mode 100644 index 0000000000..f2253d416b --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/InteropTestSequencer.java @@ -0,0 +1,137 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.sequencers;
+
+import org.apache.log4j.Logger;
+
+import org.apache.qpid.test.framework.TestClientDetails;
+import org.apache.qpid.test.framework.Assertion;
+import org.apache.qpid.test.framework.Circuit;
+import org.apache.qpid.test.framework.TestUtils;
+import org.apache.qpid.util.ConversationFactory;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import javax.jms.Destination;
+import javax.jms.JMSException;
+import javax.jms.Message;
+import javax.jms.Session;
+
+import java.util.List;
+import java.util.Properties;
+
+/**
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td>
+ * </table>
+ */
+public class InteropTestSequencer extends BaseDistributedTestSequencer
+{
+ /** Used for debugging. */
+ Logger log = Logger.getLogger(InteropTestSequencer.class);
+
+ /**
+ * Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
+ * begining the test, gathering the test reports from the participants, and checking for assertion failures against
+ * the test reports.
+ *
+ * @param testCircuit The test circuit.
+ * @param assertions The list of assertions to apply to the test circuit.
+ * @param testProperties The test case definition.
+ */
+ public void sequenceTest(Circuit testCircuit, List<Assertion> assertions, Properties testProperties)
+ {
+ log.debug("protected Message[] sequenceTest(Object... testProperties = " + testProperties + "): called");
+
+ TestClientDetails sender = getSender();
+ List<TestClientDetails> receivers = getReceivers();
+ ConversationFactory conversationFactory = getConversationFactory();
+
+ try
+ {
+ Session session = conversationFactory.getSession();
+ Destination senderControlTopic = session.createTopic(sender.privateControlKey);
+ Destination receiverControlTopic = session.createTopic(receivers.get(0).privateControlKey);
+
+ ConversationFactory.Conversation senderConversation = conversationFactory.startConversation();
+ ConversationFactory.Conversation receiverConversation = conversationFactory.startConversation();
+
+ // Assign the sender role to the sending test client.
+ Message assignSender = conversationFactory.getSession().createMessage();
+ TestUtils.setPropertiesOnMessage(assignSender, testProperties);
+ assignSender.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
+ assignSender.setStringProperty("ROLE", "SENDER");
+
+ senderConversation.send(senderControlTopic, assignSender);
+
+ // Assign the receivers role the receiving client.
+ Message assignReceiver = session.createMessage();
+ TestUtils.setPropertiesOnMessage(assignReceiver, testProperties);
+ assignReceiver.setStringProperty("CONTROL_TYPE", "ASSIGN_ROLE");
+ assignReceiver.setStringProperty("ROLE", "RECEIVER");
+
+ receiverConversation.send(receiverControlTopic, assignReceiver);
+
+ // Wait for the senders and receivers to confirm their roles.
+ senderConversation.receive();
+ receiverConversation.receive();
+
+ // Start the test.
+ Message start = session.createMessage();
+ start.setStringProperty("CONTROL_TYPE", "START");
+
+ senderConversation.send(senderControlTopic, start);
+
+ // Wait for the test sender to return its report.
+ Message senderReport = senderConversation.receive();
+ TestUtils.pause(500);
+
+ // Ask the receivers for its report.
+ Message statusRequest = session.createMessage();
+ statusRequest.setStringProperty("CONTROL_TYPE", "STATUS_REQUEST");
+
+ receiverConversation.send(receiverControlTopic, statusRequest);
+
+ // Wait for the receivers to send its report.
+ Message receiverReport = receiverConversation.receive();
+
+ // return new Message[] { senderReport, receiverReport };
+
+ // Apply assertions.
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException("JMSException not handled.");
+ }
+ }
+
+ /**
+ * Creates a test circuit for the test, configered by the test parameters specified.
+ *
+ * @param testProperties The test parameters.
+ * @return A test circuit.
+ */
+ public Circuit createCircuit(ParsedProperties testProperties)
+ {
+ throw new RuntimeException("Not implemented.");
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/TestCaseSequencer.java b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/TestCaseSequencer.java new file mode 100644 index 0000000000..4f09642467 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/test/framework/sequencers/TestCaseSequencer.java @@ -0,0 +1,66 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.test.framework.sequencers;
+
+import org.apache.qpid.test.framework.Assertion;
+import org.apache.qpid.test.framework.Circuit;
+
+import uk.co.thebadgerset.junit.extensions.util.ParsedProperties;
+
+import javax.jms.JMSException;
+import javax.jms.Message;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * A TestCaseSequence is responsibile for creating test circuits appropriate to the context that a test case is
+ * running in, and providing an implementation of a standard test procedure over a test circuit.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities
+ * <tr><td> Provide a standard test procedure over a test circuit.
+ * <tr><td> Construct test circuits appropriate to a tests context.
+ * </table>
+ */
+public interface TestCaseSequencer
+{
+ /**
+ * Holds a test coordinating conversation with the test clients. This should consist of assigning the test roles,
+ * begining the test, gathering the test reports from the participants, and checking for assertion failures against
+ * the test reports.
+ *
+ * @param testCircuit The test circuit.
+ * @param assertions The list of assertions to apply to the test circuit.
+ * @param testProperties The test case definition.
+ */
+ public void sequenceTest(Circuit testCircuit, List<Assertion> assertions, Properties testProperties);
+
+ /**
+ * Creates a test circuit for the test, configered by the test parameters specified.
+ *
+ * @param testProperties The test parameters.
+ *
+ * @return A test circuit.
+ */
+ public Circuit createCircuit(ParsedProperties testProperties);
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/util/ClasspathScanner.java b/java/systests/src/main/java/org/apache/qpid/util/ClasspathScanner.java new file mode 100644 index 0000000000..bad49060ca --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/util/ClasspathScanner.java @@ -0,0 +1,234 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import java.io.File;
+import java.util.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+/**
+ * An ClasspathScanner scans the classpath for classes that implement an interface or extend a base class and have names
+ * that match a regular expression.
+ *
+ * <p/>In order to test whether a class implements an interface or extends a class, the class must be loaded (unless
+ * the class files were to be scanned directly). Using this collector can cause problems when it scans the classpath,
+ * because loading classes will initialize their statics, which in turn may cause undesired side effects. For this
+ * reason, the collector should always be used with a regular expression, through which the class file names are
+ * filtered, and only those that pass this filter will be tested. For example, if you define tests in classes that
+ * end with the keyword "Test" then use the regular expression "Test$" to match this.
+ *
+ * <p><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><td> Find all classes matching type and name pattern on the classpath.
+ * </table>
+ *
+ * @todo Add logic to scan jars as well as directories.
+ */
+public class ClasspathScanner
+{
+ private static final Logger log = Logger.getLogger(ClasspathScanner.class);
+
+ /**
+ * Scans the classpath and returns all classes that extend a specified class and match a specified name.
+ * There is an flag that can be used to indicate that only Java Beans will be matched (that is, only those classes
+ * that have a default constructor).
+ *
+ * @param matchingClass The class or interface to match.
+ * @param matchingRegexp The regular expression to match against the class name.
+ * @param beanOnly Flag to indicate that onyl classes with default constructors should be matched.
+ *
+ * @return All the classes that match this collector.
+ */
+ public static <T> Collection<Class<? extends T>> getMatches(Class<T> matchingClass, String matchingRegexp,
+ boolean beanOnly)
+ {
+ log.debug("public static <T> Collection<Class<? extends T>> getMatches(Class<T> matchingClass = " + matchingClass
+ + ", String matchingRegexp = " + matchingRegexp + ", boolean beanOnly = " + beanOnly + "): called");
+
+ // Build a compiled regular expression from the pattern to match.
+ Pattern matchPattern = Pattern.compile(matchingRegexp);
+
+ String classPath = System.getProperty("java.class.path");
+ Map<String, Class<? extends T>> result = new HashMap<String, Class<? extends T>>();
+
+ log.debug("classPath = " + classPath);
+
+ // Find matching classes starting from all roots in the classpath.
+ for (String path : splitClassPath(classPath))
+ {
+ gatherFiles(new File(path), "", result, matchPattern, matchingClass);
+ }
+
+ return result.values();
+ }
+
+ /**
+ * Finds all matching classes rooted at a given location in the file system. If location is a directory it
+ * is recursively examined.
+ *
+ * @param classRoot The root of the current point in the file system being examined.
+ * @param classFileName The name of the current file or directory to examine.
+ * @param result The accumulated mapping from class names to classes that match the scan.
+ *
+ * @todo Recursion ok as file system depth is not likely to exhaust the stack. Might be better to replace with
+ * iteration.
+ */
+ private static <T> void gatherFiles(File classRoot, String classFileName, Map<String, Class<? extends T>> result,
+ Pattern matchPattern, Class<? extends T> matchClass)
+ {
+ log.debug("private static <T> void gatherFiles(File classRoot = " + classRoot + ", String classFileName = "
+ + classFileName + ", Map<String, Class<? extends T>> result, Pattern matchPattern = " + matchPattern
+ + ", Class<? extends T> matchClass = " + matchClass + "): called");
+
+ File thisRoot = new File(classRoot, classFileName);
+
+ // If the current location is a file, check if it is a matching class.
+ if (thisRoot.isFile())
+ {
+ // Check that the file has a matching name.
+ if (matchesName(thisRoot.getName(), matchPattern))
+ {
+ String className = classNameFromFile(thisRoot.getName());
+
+ // Check that the class has matching type.
+ try
+ {
+ Class<?> candidateClass = Class.forName(className);
+
+ Class matchedClass = matchesClass(candidateClass, matchClass);
+
+ if (matchedClass != null)
+ {
+ result.put(className, matchedClass);
+ }
+ }
+ catch (ClassNotFoundException e)
+ {
+ // Ignore this. The matching class could not be loaded.
+ log.debug("Got ClassNotFoundException, ignoring.", e);
+ }
+ }
+
+ return;
+ }
+ // Otherwise the current location is a directory, so examine all of its contents.
+ else
+ {
+ String[] contents = thisRoot.list();
+
+ if (contents != null)
+ {
+ for (String content : contents)
+ {
+ gatherFiles(classRoot, classFileName + File.separatorChar + content, result, matchPattern, matchClass);
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if the specified class file name corresponds to a class with name matching the specified regular expression.
+ *
+ * @param classFileName The class file name.
+ * @param matchPattern The regular expression pattern to match.
+ *
+ * @return <tt>true</tt> if the class name matches, <tt>false</tt> otherwise.
+ */
+ private static boolean matchesName(String classFileName, Pattern matchPattern)
+ {
+ String className = classNameFromFile(classFileName);
+ Matcher matcher = matchPattern.matcher(className);
+
+ return matcher.matches();
+ }
+
+ /**
+ * Checks if the specified class to compare extends the base class being scanned for.
+ *
+ * @param matchingClass The base class to match against.
+ * @param toMatch The class to match against the base class.
+ *
+ * @return The class to check, cast as an instance of the class to match if the class extends the base class, or
+ * <tt>null</tt> otherwise.
+ */
+ private static <T> Class<? extends T> matchesClass(Class<?> matchingClass, Class<? extends T> toMatch)
+ {
+ try
+ {
+ return matchingClass.asSubclass(toMatch);
+ }
+ catch (ClassCastException e)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Takes a classpath (which is a series of paths) and splits it into its component paths.
+ *
+ * @param classPath The classpath to split.
+ *
+ * @return A list of the component paths that make up the class path.
+ */
+ private static List<String> splitClassPath(String classPath)
+ {
+ List<String> result = new LinkedList<String>();
+ String separator = System.getProperty("path.separator");
+ StringTokenizer tokenizer = new StringTokenizer(classPath, separator);
+
+ while (tokenizer.hasMoreTokens())
+ {
+ result.add(tokenizer.nextToken());
+ }
+
+ return result;
+ }
+
+ /**
+ * Translates from the filename of a class to its fully qualified classname. Files are named using forward slash
+ * seperators and end in ".class", whereas fully qualified class names use "." sperators and no ".class" ending.
+ *
+ * @param classFileName The filename of the class to translate to a class name.
+ *
+ * @return The fully qualified class name.
+ */
+ private static String classNameFromFile(String classFileName)
+ {
+ log.debug("private static String classNameFromFile(String classFileName = " + classFileName + "): called");
+
+ // Remove the .class ending.
+ String s = classFileName.substring(0, classFileName.length() - ".class".length());
+
+ // Turn / seperators in . seperators.
+ String s2 = s.replace(File.separatorChar, '.');
+
+ // Knock off any leading . caused by a leading /.
+ if (s2.startsWith("."))
+ {
+ return s2.substring(1);
+ }
+
+ return s2;
+ }
+}
diff --git a/java/systests/src/main/java/org/apache/qpid/util/ConversationFactory.java b/java/systests/src/main/java/org/apache/qpid/util/ConversationFactory.java new file mode 100644 index 0000000000..0090bec3d0 --- /dev/null +++ b/java/systests/src/main/java/org/apache/qpid/util/ConversationFactory.java @@ -0,0 +1,479 @@ +/*
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.qpid.util;
+
+import org.apache.log4j.Logger;
+
+import javax.jms.*;
+
+import java.util.*;
+import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+/**
+ * A conversation helper, uses a message correlation id pattern to match up sent and received messages as a conversation
+ * over JMS messaging. Incoming message traffic is divided up by correlation id. Each id has a queue (behaviour dependant
+ * on the queue implementation). Clients of this de-multiplexer can wait on messages, defined by message correlation ids.
+ *
+ * <p/>One use of this is as a conversation synchronizer where multiple threads are carrying out conversations over a
+ * multiplexed messaging route. This can be usefull, as JMS sessions are not multi-threaded. Setting up the conversation
+ * with synchronous queues will allow these threads to be written in a synchronous style, but with their execution order
+ * governed by the asynchronous message flow. For example, something like the following code could run a multi-threaded
+ * conversation (the conversation methods can be called many times in parallel):
+ *
+ * <p/><pre>
+ * class Initiator
+ * {
+ * ConversationHelper conversation = new ConversationHelper(connection, null,
+ * java.util.concurrent.LinkedBlockingQueue.class);
+ *
+ * initiateConversation()
+ * {
+ * try {
+ * // Exchange greetings.
+ * conversation.send(sendDestination, conversation.getSession().createTextMessage("Hello."));
+ * Message greeting = conversation.receive();
+ *
+ * // Exchange goodbyes.
+ * conversation.send(conversation.getSession().createTextMessage("Goodbye."));
+ * Message goodbye = conversation.receive();
+ * } finally {
+ * conversation.end();
+ * }
+ * }
+ * }
+ *
+ * class Responder
+ * {
+ * ConversationHelper conversation = new ConversationHelper(connection, receiveDestination,
+ * java.util.concurrent.LinkedBlockingQueue.class);
+ *
+ * respondToConversation()
+ * {
+ * try {
+ * // Exchange greetings.
+ * Message greeting = conversation.receive();
+ * conversation.send(conversation.getSession().createTextMessage("Hello."));
+ *
+ * // Exchange goodbyes.
+ * Message goodbye = conversation.receive();
+ * conversation.send(conversation.getSession().createTextMessage("Goodbye."));
+ * } finally {
+ * conversation.end();
+ * }
+ * }
+ * }
+ * </pre>
+ *
+ * <p/>Conversation correlation id's are generated on a per thread basis.
+ *
+ * <p/>The same session is shared amongst all conversations. Calls to send are therefore synchronized because JMS
+ * sessions are not multi-threaded.
+ *
+ * <p/><table id="crc"><caption>CRC Card</caption>
+ * <tr><th> Responsibilities <th> Collaborations
+ * <tr><th> Associate messages to an ongoing conversation using correlation ids.
+ * <tr><td> Auto manage sessions for conversations.
+ * <tr><td> Store messages not in a conversation in dead letter box.
+ * </table>
+ */
+public class ConversationFactory
+{
+ /** Used for debugging. */
+ private static final Logger log = Logger.getLogger(ConversationFactory.class);
+
+ /** Holds a map from correlation id's to queues. */
+ private Map<Long, BlockingQueue<Message>> idsToQueues = new HashMap<Long, BlockingQueue<Message>>();
+
+ /** Holds the connection over which the conversation is conducted. */
+ private Connection connection;
+
+ /** Holds the session over which the conversation is conduxted. */
+ private Session session;
+
+ /** The message consumer for incoming messages. */
+ MessageConsumer consumer;
+
+ /** The message producer for outgoing messages. */
+ MessageProducer producer;
+
+ /** The well-known or temporary destination to receive replies on. */
+ Destination receiveDestination;
+
+ /** Holds the queue implementation class for the reply queue. */
+ Class<? extends BlockingQueue> queueClass;
+
+ /** Used to hold any replies that are received outside of the context of a conversation. */
+ BlockingQueue<Message> deadLetterBox = new LinkedBlockingQueue<Message>();
+
+ /* Used to hold conversation state on a per thread basis. */
+ /*
+ ThreadLocal<Conversation> threadLocals =
+ new ThreadLocal<Conversation>()
+ {
+ protected Conversation initialValue()
+ {
+ Conversation settings = new Conversation();
+ settings.conversationId = conversationIdGenerator.getAndIncrement();
+
+ return settings;
+ }
+ };
+ */
+
+ /** Generates new coversation id's as needed. */
+ AtomicLong conversationIdGenerator = new AtomicLong();
+
+ /**
+ * Creates a conversation helper on the specified connection with the default sending destination, and listening
+ * to the specified receiving destination.
+ *
+ * @param connection The connection to build the conversation helper on.
+ * @param receiveDestination The destination to listen to for incoming messages. This may be null to use a temporary
+ * queue.
+ * @param queueClass The queue implementation class.
+ *
+ * @throws JMSException All underlying JMSExceptions are allowed to fall through.
+ */
+ public ConversationFactory(Connection connection, Destination receiveDestination,
+ Class<? extends BlockingQueue> queueClass) throws JMSException
+ {
+ log.debug("public ConversationFactory(Connection connection, Destination receiveDestination = " + receiveDestination
+ + ", Class<? extends BlockingQueue> queueClass = " + queueClass + "): called");
+
+ this.connection = connection;
+ this.queueClass = queueClass;
+
+ session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+ // Check if a well-known receive destination has been provided, or use a temporary queue if not.
+ this.receiveDestination = (receiveDestination != null) ? receiveDestination : session.createTemporaryQueue();
+
+ consumer = session.createConsumer(receiveDestination);
+ producer = session.createProducer(null);
+
+ consumer.setMessageListener(new Receiver());
+ }
+
+ /**
+ * Creates a new conversation context.
+ *
+ * @return A new conversation context.
+ */
+ public Conversation startConversation()
+ {
+ log.debug("public Conversation startConversation(): called");
+
+ Conversation conversation = new Conversation();
+ conversation.conversationId = conversationIdGenerator.getAndIncrement();
+
+ return conversation;
+ }
+
+ /**
+ * Ensures that the reply queue for a conversation exists.
+ *
+ * @param conversationId The conversation correlation id.
+ */
+ private void initQueueForId(long conversationId)
+ {
+ if (!idsToQueues.containsKey(conversationId))
+ {
+ idsToQueues.put(conversationId, ReflectionUtils.<BlockingQueue>newInstance(queueClass));
+ }
+ }
+
+ /**
+ * Clears the dead letter box, returning all messages that were in it.
+ *
+ * @return All messages in the dead letter box.
+ */
+ public Collection<Message> emptyDeadLetterBox()
+ {
+ log.debug("public Collection<Message> emptyDeadLetterBox(): called");
+
+ Collection<Message> result = new ArrayList<Message>();
+ deadLetterBox.drainTo(result);
+
+ return result;
+ }
+
+ /**
+ * Gets the session over which the conversation is conducted.
+ *
+ * @return The session over which the conversation is conducted.
+ */
+ public Session getSession()
+ {
+ // Conversation settings = threadLocals.get();
+
+ return session;
+ }
+
+ /**
+ * Used to hold a conversation context. This consists of a correlating id for the conversation, and a reply
+ * destination automatically updated to the last received reply-to destination.
+ */
+ public class Conversation
+ {
+ /** Holds the correlation id for the context. */
+ long conversationId;
+
+ /**
+ * Holds the send destination for the context. This will automatically be updated to the most recently received
+ * reply-to destination.
+ */
+ Destination sendDestination;
+
+ /**
+ * Sends a message to the default sending location. The correlation id of the message will be assigned by this
+ * method, overriding any previously set value.
+ *
+ * @param sendDestination The destination to send to. This may be null to use the last received reply-to
+ * destination.
+ * @param message The message to send.
+ *
+ * @throws JMSException All undelying JMSExceptions are allowed to fall through. This will also be thrown if no
+ * send destination is specified and there is no most recent reply-to destination available
+ * to use.
+ */
+ public void send(Destination sendDestination, Message message) throws JMSException
+ {
+ log.debug("public void send(Destination sendDestination = " + sendDestination + ", Message message = " + message
+ + "): called");
+
+ // Conversation settings = threadLocals.get();
+ // long conversationId = conversationId;
+ message.setJMSCorrelationID(Long.toString(conversationId));
+ message.setJMSReplyTo(receiveDestination);
+
+ // Ensure that the reply queue for this conversation exists.
+ initQueueForId(conversationId);
+
+ // Check if an overriding send to destination has been set or use the last reply-to if not.
+ Destination sendTo = null;
+
+ if (sendDestination != null)
+ {
+ sendTo = sendDestination;
+ }
+ else if (sendDestination != null)
+ {
+ sendTo = sendDestination;
+ }
+ else
+ {
+ throw new JMSException("The send destination was specified, and no most recent reply-to available to use.");
+ }
+
+ // Send the message.
+ synchronized (this)
+ {
+ producer.send(sendTo, message);
+ }
+ }
+
+ /**
+ * Gets the next message in an ongoing conversation. This method may block until such a message is received.
+ *
+ * @return The next incoming message in the conversation.
+ *
+ * @throws JMSException All undelying JMSExceptions are allowed to fall through. Thrown if the received message
+ * did not have its reply-to destination set up.
+ */
+ public Message receive() throws JMSException
+ {
+ log.debug("public Message receive(): called");
+
+ // Conversation settings = threadLocals.get();
+ // long conversationId = settings.conversationId;
+
+ // Ensure that the reply queue for this conversation exists.
+ initQueueForId(conversationId);
+
+ BlockingQueue<Message> queue = idsToQueues.get(conversationId);
+
+ try
+ {
+ Message result = queue.take();
+
+ // Keep the reply-to destination to send replies to.
+ sendDestination = result.getJMSReplyTo();
+
+ return result;
+ }
+ catch (InterruptedException e)
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Gets many messages in an ongoing conversation. If a limit is specified, then once that many messages are
+ * received they will be returned. If a timeout is specified, then all messages up to the limit, received within
+ * that timespan will be returned. At least one of the message count or timeout should be set to a value of
+ * 1 or greater.
+ *
+ * @param num The number of messages to receive, or all if this is less than 1.
+ * @param timeout The timeout in milliseconds to receive the messages in, or forever if this is less than 1.
+ *
+ * @return All messages received within the count limit and the timeout.
+ *
+ * @throws JMSException All undelying JMSExceptions are allowed to fall through.
+ */
+ public Collection<Message> receiveAll(int num, long timeout) throws JMSException
+ {
+ log.debug("public Collection<Message> receiveAll(int num = " + num + ", long timeout = " + timeout
+ + "): called");
+
+ // Check that a timeout or message count was set.
+ if ((num < 1) && (timeout < 1))
+ {
+ throw new IllegalArgumentException("At least one of message count (num) or timeout must be set.");
+ }
+
+ // Ensure that the reply queue for this conversation exists.
+ initQueueForId(conversationId);
+ BlockingQueue<Message> queue = idsToQueues.get(conversationId);
+
+ // Used to collect the received messages in.
+ Collection<Message> result = new ArrayList<Message>();
+
+ // Used to indicate when the timeout or message count has expired.
+ boolean receiveMore = true;
+
+ int messageCount = 0;
+
+ // Receive messages until the timeout or message count expires.
+ do
+ {
+ try
+ {
+ Message next = null;
+
+ // Try to receive the message with a timeout if one has been set.
+ if (timeout > 0)
+ {
+ next = queue.poll(timeout, TimeUnit.MILLISECONDS);
+
+ // Check if the timeout expired, and stop receiving if so.
+ if (next == null)
+ {
+ receiveMore = false;
+ }
+ }
+ // Receive the message without a timeout.
+ else
+ {
+ next = queue.take();
+ }
+
+ // Increment the message count if a message was received.
+ messageCount += (next != null) ? 1 : 0;
+
+ // Check if all the requested messages were received, and stop receiving if so.
+ if ((num > 0) && (messageCount >= num))
+ {
+ receiveMore = false;
+ }
+
+ // Keep the reply-to destination to send replies to.
+ sendDestination = (next != null) ? next.getJMSReplyTo() : sendDestination;
+
+ if (next != null)
+ {
+ result.add(next);
+ }
+ }
+ catch (InterruptedException e)
+ {
+ // Restore the threads interrupted status.
+ Thread.currentThread().interrupt();
+
+ // Stop receiving but return the messages received so far.
+ receiveMore = false;
+ }
+ }
+ while (receiveMore);
+
+ return result;
+ }
+
+ /**
+ * Completes the conversation. Any correlation id's pertaining to the conversation are no longer valid, and any
+ * incoming messages using them will go to the dead letter box.
+ */
+ public void end()
+ {
+ log.debug("public void end(): called");
+
+ // Ensure that the thread local for the current thread is cleaned up.
+ // Conversation settings = threadLocals.get();
+ // long conversationId = settings.conversationId;
+ // threadLocals.remove();
+
+ // Ensure that its queue is removed from the queue map.
+ BlockingQueue<Message> queue = idsToQueues.remove(conversationId);
+
+ // Move any outstanding messages on the threads conversation id into the dead letter box.
+ queue.drainTo(deadLetterBox);
+ }
+ }
+
+ /**
+ * Implements the message listener for this conversation handler.
+ */
+ protected class Receiver implements MessageListener
+ {
+ /**
+ * Handles all incoming messages in the ongoing conversations. These messages are split up by correaltion id
+ * and placed into queues.
+ *
+ * @param message The incoming message.
+ */
+ public void onMessage(Message message)
+ {
+ log.debug("public void onMessage(Message message = " + message + "): called");
+
+ try
+ {
+ Long conversationId = Long.parseLong(message.getJMSCorrelationID());
+
+ // Find the converstaion queue to place the message on. If there is no conversation for the message id,
+ // the the dead letter box queue is used.
+ BlockingQueue<Message> queue = idsToQueues.get(conversationId);
+ queue = (queue == null) ? deadLetterBox : queue;
+
+ queue.put(message);
+ }
+ catch (JMSException e)
+ {
+ throw new RuntimeException(e);
+ }
+ catch (InterruptedException e)
+ {
+ throw new RuntimeException(e);
+ }
+ }
+ }
+}
|
