test_forwardingprefix.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197
  1. /* Any copyright is dedicated to the Public Domain.
  2. http://creativecommons.org/publicdomain/zero/1.0/ */
  3. /* Exercise prefix-based forwarding of packets to other transports. */
  4. const { RootActor } = require("devtools/server/actors/root");
  5. var gMainConnection, gMainTransport;
  6. var gSubconnection1, gSubconnection2;
  7. var gClient;
  8. function run_test()
  9. {
  10. DebuggerServer.init();
  11. add_test(createMainConnection);
  12. add_test(TestNoForwardingYet);
  13. add_test(createSubconnection1);
  14. add_test(TestForwardPrefix1OnlyRoot);
  15. add_test(createSubconnection2);
  16. add_test(TestForwardPrefix12OnlyRoot);
  17. add_test(TestForwardPrefix12WithActor1);
  18. add_test(TestForwardPrefix12WithActor12);
  19. run_next_test();
  20. }
  21. /*
  22. * Create a pipe connection, and return an object |{ conn, transport }|,
  23. * where |conn| is the new DebuggerServerConnection instance, and
  24. * |transport| is the client side of the transport on which it communicates
  25. * (that is, packets sent on |transport| go to the new connection, and
  26. * |transport|'s hooks receive replies).
  27. *
  28. * |aPrefix| is optional; if present, it's the prefix (minus the '/') for
  29. * actors in the new connection.
  30. */
  31. function newConnection(aPrefix)
  32. {
  33. var conn;
  34. DebuggerServer.createRootActor = function (aConn) {
  35. conn = aConn;
  36. return new RootActor(aConn, {});
  37. };
  38. var transport = DebuggerServer.connectPipe(aPrefix);
  39. return { conn: conn, transport: transport };
  40. }
  41. /* Create the main connection for these tests. */
  42. function createMainConnection()
  43. {
  44. ({ conn: gMainConnection, transport: gMainTransport } = newConnection());
  45. gClient = new DebuggerClient(gMainTransport);
  46. gClient.connect().then(([aType, aTraits]) => run_next_test());
  47. }
  48. /*
  49. * Exchange 'echo' messages with five actors:
  50. * - root
  51. * - prefix1/root
  52. * - prefix1/actor
  53. * - prefix2/root
  54. * - prefix2/actor
  55. *
  56. * Expect proper echos from those named in |aReachables|, and 'noSuchActor'
  57. * errors from the others. When we've gotten all our replies (errors or
  58. * otherwise), call |aCompleted|.
  59. *
  60. * To avoid deep stacks, we call aCompleted from the next tick.
  61. */
  62. function tryActors(aReachables, aCompleted) {
  63. let count = 0;
  64. let outerActor;
  65. for (outerActor of [ "root",
  66. "prefix1/root", "prefix1/actor",
  67. "prefix2/root", "prefix2/actor" ]) {
  68. /*
  69. * Let each callback capture its own iteration's value; outerActor is
  70. * local to the whole loop, not to a single iteration.
  71. */
  72. let actor = outerActor;
  73. count++;
  74. gClient.request({ to: actor, type: "echo", value: "tango"}, // phone home
  75. (aResponse) => {
  76. if (aReachables.has(actor))
  77. do_check_matches({ from: actor, to: actor, type: "echo", value: "tango" }, aResponse);
  78. else
  79. do_check_matches({ from: actor, error: "noSuchActor", message: "No such actor for ID: " + actor }, aResponse);
  80. if (--count == 0)
  81. do_execute_soon(aCompleted, "tryActors callback " + aCompleted.name);
  82. });
  83. }
  84. }
  85. /*
  86. * With no forwarding established, sending messages to root should work,
  87. * but sending messages to prefixed actor names, or anyone else, should get
  88. * an error.
  89. */
  90. function TestNoForwardingYet()
  91. {
  92. tryActors(new Set(["root"]), run_next_test);
  93. }
  94. /*
  95. * Create a new pipe connection which forwards its reply packets to
  96. * gMainConnection's client, and to which gMainConnection forwards packets
  97. * directed to actors whose names begin with |aPrefix + '/'|, and.
  98. *
  99. * Return an object { conn, transport }, as for newConnection.
  100. */
  101. function newSubconnection(aPrefix)
  102. {
  103. let { conn, transport } = newConnection(aPrefix);
  104. transport.hooks = {
  105. onPacket: (aPacket) => gMainConnection.send(aPacket),
  106. onClosed: () => {}
  107. };
  108. gMainConnection.setForwarding(aPrefix, transport);
  109. return { conn: conn, transport: transport };
  110. }
  111. /* Create a second root actor, to which we can forward things. */
  112. function createSubconnection1()
  113. {
  114. let { conn, transport } = newSubconnection("prefix1");
  115. gSubconnection1 = conn;
  116. transport.ready();
  117. gClient.expectReply("prefix1/root", (aReply) => run_next_test());
  118. }
  119. // Establish forwarding, but don't put any actors in that server.
  120. function TestForwardPrefix1OnlyRoot()
  121. {
  122. tryActors(new Set(["root", "prefix1/root"]), run_next_test);
  123. }
  124. /* Create a third root actor, to which we can forward things. */
  125. function createSubconnection2()
  126. {
  127. let { conn, transport } = newSubconnection("prefix2");
  128. gSubconnection2 = conn;
  129. transport.ready();
  130. gClient.expectReply("prefix2/root", (aReply) => run_next_test());
  131. }
  132. function TestForwardPrefix12OnlyRoot()
  133. {
  134. tryActors(new Set(["root", "prefix1/root", "prefix2/root"]), run_next_test);
  135. }
  136. // A dumb actor that implements 'echo'.
  137. //
  138. // It's okay that both subconnections' actors behave identically, because
  139. // the reply-sending code attaches the replying actor's name to the packet,
  140. // so simply matching the 'from' field in the reply ensures that we heard
  141. // from the right actor.
  142. function EchoActor(aConnection)
  143. {
  144. this.conn = aConnection;
  145. }
  146. EchoActor.prototype.actorPrefix = "EchoActor";
  147. EchoActor.prototype.onEcho = function (aRequest) {
  148. /*
  149. * Request packets are frozen. Copy aRequest, so that
  150. * DebuggerServerConnection.onPacket can attach a 'from' property.
  151. */
  152. return JSON.parse(JSON.stringify(aRequest));
  153. };
  154. EchoActor.prototype.requestTypes = {
  155. "echo": EchoActor.prototype.onEcho
  156. };
  157. function TestForwardPrefix12WithActor1()
  158. {
  159. let actor = new EchoActor(gSubconnection1);
  160. actor.actorID = "prefix1/actor";
  161. gSubconnection1.addActor(actor);
  162. tryActors(new Set(["root", "prefix1/root", "prefix1/actor", "prefix2/root"]), run_next_test);
  163. }
  164. function TestForwardPrefix12WithActor12()
  165. {
  166. let actor = new EchoActor(gSubconnection2);
  167. actor.actorID = "prefix2/actor";
  168. gSubconnection2.addActor(actor);
  169. tryActors(new Set(["root", "prefix1/root", "prefix1/actor", "prefix2/root", "prefix2/actor"]), run_next_test);
  170. }