MessageTest.vala 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. /**
  2. * MessageTest - Unit tests for Protocol messages
  3. */
  4. using Implexus.Core;
  5. using Implexus.Protocol;
  6. using Implexus.Storage;
  7. public static int main(string[] args) {
  8. int passed = 0;
  9. int failed = 0;
  10. // Test 1: Message header serialization
  11. if (test_message_header()) {
  12. passed++;
  13. stdout.puts("PASS: test_message_header\n");
  14. } else {
  15. failed++;
  16. stdout.puts("FAIL: test_message_header\n");
  17. }
  18. // Test 2: GetEntityRequest
  19. if (test_get_entity_request()) {
  20. passed++;
  21. stdout.puts("PASS: test_get_entity_request\n");
  22. } else {
  23. failed++;
  24. stdout.puts("FAIL: test_get_entity_request\n");
  25. }
  26. // Test 3: EntityExistsRequest
  27. if (test_entity_exists_request()) {
  28. passed++;
  29. stdout.puts("PASS: test_entity_exists_request\n");
  30. } else {
  31. failed++;
  32. stdout.puts("FAIL: test_entity_exists_request\n");
  33. }
  34. // Test 4: CreateContainerRequest
  35. if (test_create_container_request()) {
  36. passed++;
  37. stdout.puts("PASS: test_create_container_request\n");
  38. } else {
  39. failed++;
  40. stdout.puts("FAIL: test_create_container_request\n");
  41. }
  42. // Test 5: CreateDocumentRequest
  43. if (test_create_document_request()) {
  44. passed++;
  45. stdout.puts("PASS: test_create_document_request\n");
  46. } else {
  47. failed++;
  48. stdout.puts("FAIL: test_create_document_request\n");
  49. }
  50. // Test 6: DeleteEntityRequest
  51. if (test_delete_entity_request()) {
  52. passed++;
  53. stdout.puts("PASS: test_delete_entity_request\n");
  54. } else {
  55. failed++;
  56. stdout.puts("FAIL: test_delete_entity_request\n");
  57. }
  58. // Test 7: SetPropertyRequest
  59. if (test_set_property_request()) {
  60. passed++;
  61. stdout.puts("PASS: test_set_property_request\n");
  62. } else {
  63. failed++;
  64. stdout.puts("FAIL: test_set_property_request\n");
  65. }
  66. // Test 8: GetPropertyRequest
  67. if (test_get_property_request()) {
  68. passed++;
  69. stdout.puts("PASS: test_get_property_request\n");
  70. } else {
  71. failed++;
  72. stdout.puts("FAIL: test_get_property_request\n");
  73. }
  74. // Test 9: EntityResponse
  75. if (test_entity_response()) {
  76. passed++;
  77. stdout.puts("PASS: test_entity_response\n");
  78. } else {
  79. failed++;
  80. stdout.puts("FAIL: test_entity_response\n");
  81. }
  82. // Test 10: BooleanResponse
  83. if (test_boolean_response()) {
  84. passed++;
  85. stdout.puts("PASS: test_boolean_response\n");
  86. } else {
  87. failed++;
  88. stdout.puts("FAIL: test_boolean_response\n");
  89. }
  90. // Test 11: PropertyResponse
  91. if (test_property_response()) {
  92. passed++;
  93. stdout.puts("PASS: test_property_response\n");
  94. } else {
  95. failed++;
  96. stdout.puts("FAIL: test_property_response\n");
  97. }
  98. // Test 12: ErrorResponse
  99. if (test_error_response()) {
  100. passed++;
  101. stdout.puts("PASS: test_error_response\n");
  102. } else {
  103. failed++;
  104. stdout.puts("FAIL: test_error_response\n");
  105. }
  106. // Test 13: SuccessResponse
  107. if (test_success_response()) {
  108. passed++;
  109. stdout.puts("PASS: test_success_response\n");
  110. } else {
  111. failed++;
  112. stdout.puts("FAIL: test_success_response\n");
  113. }
  114. // Test 14: MessageFactory
  115. if (test_message_factory()) {
  116. passed++;
  117. stdout.puts("PASS: test_message_factory\n");
  118. } else {
  119. failed++;
  120. stdout.puts("FAIL: test_message_factory\n");
  121. }
  122. // Test 15: Full message round-trip
  123. if (test_full_round_trip()) {
  124. passed++;
  125. stdout.puts("PASS: test_full_round_trip\n");
  126. } else {
  127. failed++;
  128. stdout.puts("FAIL: test_full_round_trip\n");
  129. }
  130. stdout.printf("\nResults: %d passed, %d failed\n", passed, failed);
  131. return failed > 0 ? 1 : 0;
  132. }
  133. // Test 1: Message header serialization
  134. bool test_message_header() {
  135. var header = new MessageHeader();
  136. header.message_type = MessageType.GET_ENTITY;
  137. header.payload_length = 100;
  138. header.request_id = 42;
  139. var data = header.serialize();
  140. if (data.length != HEADER_SIZE) return false;
  141. // Check magic bytes
  142. if (data[0] != 'I' || data[1] != 'M' || data[2] != 'P' || data[3] != 'X') return false;
  143. // Deserialize and verify
  144. try {
  145. var restored = MessageHeader.deserialize(data);
  146. if (restored.message_type != MessageType.GET_ENTITY) return false;
  147. if (restored.payload_length != 100) return false;
  148. if (restored.request_id != 42) return false;
  149. return true;
  150. } catch (ProtocolError e) {
  151. return false;
  152. }
  153. }
  154. // Test 2: GetEntityRequest
  155. bool test_get_entity_request() {
  156. try {
  157. var path = new EntityPath("/users/john");
  158. var request = new GetEntityRequest.for_path(path);
  159. request.request_id = 1;
  160. var data = request.serialize();
  161. // Deserialize header
  162. var header = MessageHeader.deserialize(data);
  163. if (header.message_type != MessageType.GET_ENTITY) return false;
  164. if (header.request_id != 1) return false;
  165. // Deserialize payload
  166. var restored = new GetEntityRequest();
  167. restored.header = header;
  168. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  169. if (!restored.path.equals(path)) return false;
  170. return true;
  171. } catch (Error e) {
  172. return false;
  173. }
  174. }
  175. // Test 3: EntityExistsRequest
  176. bool test_entity_exists_request() {
  177. try {
  178. var path = new EntityPath("/test/path");
  179. var request = new EntityExistsRequest.for_path(path);
  180. request.request_id = 2;
  181. var data = request.serialize();
  182. var header = MessageHeader.deserialize(data);
  183. if (header.message_type != MessageType.ENTITY_EXISTS) return false;
  184. var restored = new EntityExistsRequest();
  185. restored.header = header;
  186. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  187. if (!restored.path.equals(path)) return false;
  188. return true;
  189. } catch (Error e) {
  190. return false;
  191. }
  192. }
  193. // Test 4: CreateContainerRequest
  194. bool test_create_container_request() {
  195. try {
  196. var path = new EntityPath("/new_container");
  197. var request = new CreateContainerRequest.for_path(path);
  198. request.request_id = 3;
  199. var data = request.serialize();
  200. var header = MessageHeader.deserialize(data);
  201. if (header.message_type != MessageType.CREATE_CONTAINER) return false;
  202. var restored = new CreateContainerRequest();
  203. restored.header = header;
  204. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  205. if (!restored.path.equals(path)) return false;
  206. return true;
  207. } catch (Error e) {
  208. return false;
  209. }
  210. }
  211. // Test 5: CreateDocumentRequest
  212. bool test_create_document_request() {
  213. try {
  214. var path = new EntityPath("/docs/new_doc");
  215. var request = new CreateDocumentRequest.for_path_and_type(path, "Document");
  216. request.request_id = 4;
  217. var data = request.serialize();
  218. var header = MessageHeader.deserialize(data);
  219. if (header.message_type != MessageType.CREATE_DOCUMENT) return false;
  220. var restored = new CreateDocumentRequest();
  221. restored.header = header;
  222. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  223. if (!restored.path.equals(path)) return false;
  224. if (restored.type_label != "Document") return false;
  225. return true;
  226. } catch (Error e) {
  227. return false;
  228. }
  229. }
  230. // Test 6: DeleteEntityRequest
  231. bool test_delete_entity_request() {
  232. try {
  233. var path = new EntityPath("/to_delete");
  234. var request = new DeleteEntityRequest.for_path(path);
  235. request.request_id = 5;
  236. var data = request.serialize();
  237. var header = MessageHeader.deserialize(data);
  238. if (header.message_type != MessageType.DELETE_ENTITY) return false;
  239. var restored = new DeleteEntityRequest();
  240. restored.header = header;
  241. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  242. if (!restored.path.equals(path)) return false;
  243. return true;
  244. } catch (Error e) {
  245. return false;
  246. }
  247. }
  248. // Test 7: SetPropertyRequest
  249. bool test_set_property_request() {
  250. try {
  251. var path = new EntityPath("/entity");
  252. var request = new SetPropertyRequest();
  253. request.path = path;
  254. request.property_name = "test_prop";
  255. request.value = new Invercargill.NativeElement<string>("test_value");
  256. request.request_id = 6;
  257. var data = request.serialize();
  258. var header = MessageHeader.deserialize(data);
  259. if (header.message_type != MessageType.SET_PROPERTY) return false;
  260. var restored = new SetPropertyRequest();
  261. restored.header = header;
  262. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  263. if (!restored.path.equals(path)) return false;
  264. if (restored.property_name != "test_prop") return false;
  265. // Check value
  266. if (restored.value == null || ((!) restored.value).is_null()) return false;
  267. string val = ((!) restored.value).as<string>();
  268. if (val != "test_value") return false;
  269. return true;
  270. } catch (Error e) {
  271. return false;
  272. }
  273. }
  274. // Test 8: GetPropertyRequest
  275. bool test_get_property_request() {
  276. try {
  277. var path = new EntityPath("/entity");
  278. var request = new GetPropertyRequest();
  279. request.path = path;
  280. request.property_name = "get_prop";
  281. request.request_id = 7;
  282. var data = request.serialize();
  283. var header = MessageHeader.deserialize(data);
  284. if (header.message_type != MessageType.GET_PROPERTY) return false;
  285. var restored = new GetPropertyRequest();
  286. restored.header = header;
  287. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  288. if (!restored.path.equals(path)) return false;
  289. if (restored.property_name != "get_prop") return false;
  290. return true;
  291. } catch (Error e) {
  292. return false;
  293. }
  294. }
  295. // Test 9: EntityResponse
  296. bool test_entity_response() {
  297. try {
  298. var response = new EntityResponse();
  299. response.entity_data.entity_type = EntityType.DOCUMENT;
  300. response.entity_data.path = new EntityPath("/test/document");
  301. response.entity_data.type_label = "TestDoc";
  302. response.request_id = 8;
  303. var data = response.serialize();
  304. var header = MessageHeader.deserialize(data);
  305. if (header.message_type != MessageType.ENTITY_RESPONSE) return false;
  306. var restored = new EntityResponse();
  307. restored.header = header;
  308. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  309. if (restored.entity_data.entity_type != EntityType.DOCUMENT) return false;
  310. if (!restored.entity_data.path.equals(new EntityPath("/test/document"))) return false;
  311. if (restored.entity_data.type_label != "TestDoc") return false;
  312. return true;
  313. } catch (Error e) {
  314. return false;
  315. }
  316. }
  317. // Test 10: BooleanResponse
  318. bool test_boolean_response() {
  319. try {
  320. // Test true
  321. var response_true = new BooleanResponse();
  322. response_true.value = true;
  323. response_true.request_id = 9;
  324. var data_true = response_true.serialize();
  325. var header_true = MessageHeader.deserialize(data_true);
  326. var restored_true = new BooleanResponse();
  327. restored_true.header = header_true;
  328. restored_true.deserialize_payload(data_true[HEADER_SIZE:data_true.length]);
  329. if (restored_true.value != true) return false;
  330. // Test false
  331. var response_false = new BooleanResponse();
  332. response_false.value = false;
  333. var data_false = response_false.serialize();
  334. var header_false = MessageHeader.deserialize(data_false);
  335. var restored_false = new BooleanResponse();
  336. restored_false.header = header_false;
  337. restored_false.deserialize_payload(data_false[HEADER_SIZE:data_false.length]);
  338. if (restored_false.value != false) return false;
  339. return true;
  340. } catch (Error e) {
  341. return false;
  342. }
  343. }
  344. // Test 11: PropertyResponse
  345. bool test_property_response() {
  346. try {
  347. var response = new PropertyResponse();
  348. response.value = new Invercargill.NativeElement<int64?>(12345);
  349. response.request_id = 10;
  350. var data = response.serialize();
  351. var header = MessageHeader.deserialize(data);
  352. if (header.message_type != MessageType.PROPERTY_RESPONSE) return false;
  353. var restored = new PropertyResponse();
  354. restored.header = header;
  355. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  356. if (restored.value == null || ((!) restored.value).is_null()) return false;
  357. int64? val = ((!) restored.value).as<int64?>();
  358. if (val == null || (!) val != 12345) return false;
  359. return true;
  360. } catch (Error e) {
  361. return false;
  362. }
  363. }
  364. // Test 12: ErrorResponse
  365. bool test_error_response() {
  366. try {
  367. var response = new ErrorResponse.with_error(404, "Entity not found");
  368. response.request_id = 11;
  369. var data = response.serialize();
  370. var header = MessageHeader.deserialize(data);
  371. if (header.message_type != MessageType.ERROR) return false;
  372. var restored = new ErrorResponse();
  373. restored.header = header;
  374. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  375. if (restored.error_code != 404) return false;
  376. if (restored.error_message != "Entity not found") return false;
  377. return true;
  378. } catch (Error e) {
  379. return false;
  380. }
  381. }
  382. // Test 13: SuccessResponse
  383. bool test_success_response() {
  384. try {
  385. var response = new SuccessResponse();
  386. response.request_id = 12;
  387. var data = response.serialize();
  388. var header = MessageHeader.deserialize(data);
  389. if (header.message_type != MessageType.SUCCESS) return false;
  390. if (header.payload_length != 0) return false;
  391. var restored = new SuccessResponse();
  392. restored.header = header;
  393. restored.deserialize_payload(data[HEADER_SIZE:data.length]);
  394. return true;
  395. } catch (Error e) {
  396. return false;
  397. }
  398. }
  399. // Test 14: MessageFactory
  400. bool test_message_factory() {
  401. try {
  402. // Test all message types
  403. var types = new MessageType[] {
  404. MessageType.GET_ENTITY,
  405. MessageType.ENTITY_EXISTS,
  406. MessageType.CREATE_CONTAINER,
  407. MessageType.CREATE_DOCUMENT,
  408. MessageType.DELETE_ENTITY,
  409. MessageType.SET_PROPERTY,
  410. MessageType.GET_PROPERTY,
  411. MessageType.GET_CHILDREN,
  412. MessageType.QUERY_BY_TYPE,
  413. MessageType.BEGIN_TRANSACTION,
  414. MessageType.COMMIT_TRANSACTION,
  415. MessageType.ROLLBACK_TRANSACTION,
  416. MessageType.ENTITY_RESPONSE,
  417. MessageType.BOOLEAN_RESPONSE,
  418. MessageType.PROPERTY_RESPONSE,
  419. MessageType.CHILDREN_RESPONSE,
  420. MessageType.QUERY_RESPONSE,
  421. MessageType.ERROR,
  422. MessageType.SUCCESS,
  423. MessageType.WELCOME
  424. };
  425. foreach (var type in types) {
  426. var message = MessageFactory.create_message(type);
  427. if (message == null) return false;
  428. if (message.message_type != type) return false;
  429. }
  430. return true;
  431. } catch (Error e) {
  432. return false;
  433. }
  434. }
  435. // Test 15: Full message round-trip
  436. bool test_full_round_trip() {
  437. try {
  438. // Create a complex message
  439. var request = new CreateDocumentRequest.for_path_and_type(
  440. new EntityPath("/deeply/nested/path/document"),
  441. "ComplexDocument"
  442. );
  443. request.request_id = 999;
  444. // Serialize
  445. var data = request.serialize();
  446. // Parse header
  447. var header = MessageHeader.deserialize(data);
  448. // Create message from factory
  449. var restored = MessageFactory.create_message(header.message_type);
  450. if (restored == null) return false;
  451. ((!) restored).header = header;
  452. ((!) restored).deserialize_payload(data[HEADER_SIZE:data.length]);
  453. // Verify
  454. var doc_request = ((!) restored) as CreateDocumentRequest;
  455. if (doc_request == null) return false;
  456. if (((!) doc_request).path.to_string() != "/deeply/nested/path/document") return false;
  457. if (((!) doc_request).type_label != "ComplexDocument") return false;
  458. if (((!) doc_request).request_id != 999) return false;
  459. return true;
  460. } catch (Error e) {
  461. return false;
  462. }
  463. }