summaryrefslogtreecommitdiffstats
path: root/comm/mailnews/news/test/unit/test_server.js
blob: f0954add1cd9f470c268f9e21bb3eb0d30eb945f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
// Protocol tests for NNTP. These actually aren't too important, but their main
// purpose is to make sure that maild is working properly and to provide
// examples for how using maild. They also help make sure that I coded Nntpd.jsm
// right, both logically and for RFC compliance.
// TODO:
// * We need to hook up mochitest,
// * TLS negotiation.

// The basic daemon to use for testing Nntpd.jsm implementations
var daemon = setupNNTPDaemon();

// NNTP SERVER TESTS
// -----------------
// Functions in order as defined in Nntpd.jsm. Each function tests the URLs
// that are located over the implementation of nsNNTPProtocol::LoadURL and
// added in bug 400331. Furthermore, they are tested in rough order as they
// would be expected to be used in a session. If more URL types are modified,
// please add a corresponding type to the following tests.
// When adding new servers, only test the commands that become different for
// each specified server, to keep down redudant tests.

function testRFC977() {
  var server = makeServer(NNTP_RFC977_handler, daemon);
  server.start(NNTP_PORT);

  try {
    var prefix = "news://localhost:" + NNTP_PORT + "/";
    var transaction;

    // Test - group subscribe listing
    test = "news:*";
    setupProtocolTest(NNTP_PORT, prefix + "*");
    server.performTest();
    transaction = server.playTransaction();
    do_check_transaction(transaction, ["MODE READER", "LIST"]);

    // Test - getting group headers
    test = "news:test.subscribe.empty";
    server.resetTest();
    setupProtocolTest(NNTP_PORT, prefix + "test.subscribe.empty");
    server.performTest();
    transaction = server.playTransaction();
    do_check_transaction(transaction, [
      "MODE READER",
      "GROUP test.subscribe.empty",
    ]);

    // Test - getting an article
    test = "news:MESSAGE_ID";
    server.resetTest();
    setupProtocolTest(NNTP_PORT, prefix + "TSS1@nntp.invalid");
    server.performTest();
    transaction = server.playTransaction();
    do_check_transaction(transaction, [
      "MODE READER",
      "ARTICLE <TSS1@nntp.invalid>",
    ]);
  } catch (e) {
    dump("NNTP Protocol test " + test + " failed for type RFC 977:\n");
    try {
      var trans = server.playTransaction();
      if (trans) {
        dump("Commands called: " + trans.them + "\n");
      }
    } catch (exp) {}
    do_throw(e);
  }
  server.stop();

  var thread = gThreadManager.currentThread;
  while (thread.hasPendingEvents()) {
    thread.processNextEvent(true);
  }
}

function testConnectionLimit() {
  var server = makeServer(NNTP_RFC977_handler, daemon);
  server.start(NNTP_PORT);
  // 1 is the default, but other tests do change it, so let's be explicit.
  _server.maximumConnectionsNumber = 1;

  var prefix = "news://localhost:" + NNTP_PORT + "/";

  // To test make connections limit, we run two URIs simultaneously.
  var url = Services.io.newURI(prefix + "*");
  _server.loadNewsUrl(url, null, null);
  setupProtocolTest(NNTP_PORT, prefix + "TSS1@nntp.invalid");
  server.performTest();
  // We should have length one... which means this must be a transaction object,
  // containing only us and them
  // (playTransactions() returns an array of transaction objects if there is
  // more than one of them, so this assert will fail in that case).
  Assert.ok("us" in server.playTransaction());
  server.stop();

  var thread = gThreadManager.currentThread;
  while (thread.hasPendingEvents()) {
    thread.processNextEvent(true);
  }
}

function testReentrantClose() {
  // What we are testing is that a CloseConnection that spins the event loop
  // does not cause a crash.
  var server = makeServer(NNTP_RFC977_handler, daemon);
  server.start(NNTP_PORT);

  var listener = {
    OnStartRunningUrl(url) {},
    OnStopRunningUrl(url, rv) {
      // Spin the event loop (entering nsNNTPProtocol::ProcessProtocolState)
      let thread = gThreadManager.currentThread;
      while (thread.hasPendingEvents()) {
        thread.processNextEvent(true);
      }
    },
  };
  // Nice multi-step command--we can close while executing this URL if we are
  // careful.
  var url = Services.io.newURI(
    "news://localhost:" + NNTP_PORT + "/test.filter"
  );
  url.QueryInterface(Ci.nsIMsgMailNewsUrl);
  url.RegisterListener(listener);

  _server.loadNewsUrl(url, null, {
    QueryInterface: ChromeUtils.generateQI(["nsIStreamListener"]),
    onStartRequest() {},
    onStopRequest() {},
  });
  server.performTest("GROUP");
  dump("Stopping server\n");
  gThreadManager.currentThread.dispatch(
    {
      run() {
        _server.closeCachedConnections();
      },
    },
    Ci.nsIEventTarget.DISPATCH_NORMAL
  );
  server.performTest();
  server.stop();

  // Break refcnt loops
  listener = url = null;
}

function testManyConnections() {
  // Start up 2 connections at once and make sure that they don't conflict
  var server = makeServer(NNTP_RFC2980_handler, daemon);
  setupLocalServer(NNTP_PORT);
  server.start(NNTP_PORT);
  _server.maximumConnectionsNumber = 3;
  var listener = {
    ran: 0,
    OnStartRunningUrl(url) {},
    OnStopRunningUrl(url, rv) {
      if (--this.ran == 0) {
        _server.closeCachedConnections();
      }
    },
  };
  for (let group of _server.rootFolder.subFolders) {
    group.getNewMessages(null, listener);
    listener.ran++;
  }
  server.performTest();
  // The last one that is processed is test.filter, so make sure that
  // test.subscribed.simple is not retrieving the data meant for test.filter
  let folder = _server.rootFolder.getChildNamed("test.subscribe.simple");
  Assert.equal(folder.getTotalMessages(false), 1);
}

function run_test() {
  testRFC977();
  testConnectionLimit();
  testReentrantClose();
  testManyConnections();
}