summaryrefslogtreecommitdiffstats
path: root/toolkit/components/url-classifier/tests/unit/test_hashcompleter.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/url-classifier/tests/unit/test_hashcompleter.js')
-rw-r--r--toolkit/components/url-classifier/tests/unit/test_hashcompleter.js403
1 files changed, 0 insertions, 403 deletions
diff --git a/toolkit/components/url-classifier/tests/unit/test_hashcompleter.js b/toolkit/components/url-classifier/tests/unit/test_hashcompleter.js
deleted file mode 100644
index 40fafd923..000000000
--- a/toolkit/components/url-classifier/tests/unit/test_hashcompleter.js
+++ /dev/null
@@ -1,403 +0,0 @@
-/* Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ */
-
-// This test ensures that the nsIUrlClassifierHashCompleter works as expected
-// and simulates an HTTP server to provide completions.
-//
-// In order to test completions, each group of completions sent as one request
-// to the HTTP server is called a completion set. There is currently not
-// support for multiple requests being sent to the server at once, in this test.
-// This tests makes a request for each element of |completionSets|, waits for
-// a response and then moves to the next element.
-// Each element of |completionSets| is an array of completions, and each
-// completion is an object with the properties:
-// hash: complete hash for the completion. Automatically right-padded
-// to be COMPLETE_LENGTH.
-// expectCompletion: boolean indicating whether the server should respond
-// with a full hash.
-// forceServerError: boolean indicating whether the server should respond
-// with a 503.
-// table: name of the table that the hash corresponds to. Only needs to be set
-// if a completion is expected.
-// chunkId: positive integer corresponding to the chunk that the hash belongs
-// to. Only needs to be set if a completion is expected.
-// multipleCompletions: boolean indicating whether the server should respond
-// with more than one full hash. If this is set to true
-// then |expectCompletion| must also be set to true and
-// |hash| must have the same prefix as all |completions|.
-// completions: an array of completions (objects with a hash, table and
-// chunkId property as described above). This property is only
-// used when |multipleCompletions| is set to true.
-
-// Basic prefixes with 2/3 completions.
-var basicCompletionSet = [
- {
- hash: "abcdefgh",
- expectCompletion: true,
- table: "test",
- chunkId: 1234,
- },
- {
- hash: "1234",
- expectCompletion: false,
- },
- {
- hash: "\u0000\u0000\u000012312",
- expectCompletion: true,
- table: "test",
- chunkId: 1234,
- }
-];
-
-// 3 prefixes with 0 completions to test HashCompleter handling a 204 status.
-var falseCompletionSet = [
- {
- hash: "1234",
- expectCompletion: false,
- },
- {
- hash: "",
- expectCompletion: false,
- },
- {
- hash: "abc",
- expectCompletion: false,
- }
-];
-
-// The current implementation (as of Mar 2011) sometimes sends duplicate
-// entries to HashCompleter and even expects responses for duplicated entries.
-var dupedCompletionSet = [
- {
- hash: "1234",
- expectCompletion: true,
- table: "test",
- chunkId: 1,
- },
- {
- hash: "5678",
- expectCompletion: false,
- table: "test2",
- chunkId: 2,
- },
- {
- hash: "1234",
- expectCompletion: true,
- table: "test",
- chunkId: 1,
- },
- {
- hash: "5678",
- expectCompletion: false,
- table: "test2",
- chunkId: 2
- }
-];
-
-// It is possible for a hash completion request to return with multiple
-// completions, the HashCompleter should return all of these.
-var multipleResponsesCompletionSet = [
- {
- hash: "1234",
- expectCompletion: true,
- multipleCompletions: true,
- completions: [
- {
- hash: "123456",
- table: "test1",
- chunkId: 3,
- },
- {
- hash: "123478",
- table: "test2",
- chunkId: 4,
- }
- ],
- }
-];
-
-function buildCompletionRequest(aCompletionSet) {
- let prefixes = [];
- let prefixSet = new Set();
- aCompletionSet.forEach(s => {
- let prefix = s.hash.substring(0, 4);
- if (prefixSet.has(prefix)) {
- return;
- }
- prefixSet.add(prefix);
- prefixes.push(prefix);
- });
- return 4 + ":" + (4 * prefixes.length) + "\n" + prefixes.join("");
-}
-
-function parseCompletionRequest(aRequest) {
- // Format: [partial_length]:[num_of_prefix * partial_length]\n[prefixes_data]
-
- let tokens = /(\d):(\d+)/.exec(aRequest);
- if (tokens.length < 3) {
- dump("Request format error.");
- return null;
- }
-
- let partialLength = parseInt(tokens[1]);
- let payloadLength = parseInt(tokens[2]);
-
- let payloadStart = tokens[1].length + // partial length
- 1 + // ':'
- tokens[2].length + // payload length
- 1; // '\n'
-
- let prefixSet = [];
- for (let i = payloadStart; i < aRequest.length; i += partialLength) {
- let prefix = aRequest.substr(i, partialLength);
- if (prefix.length !== partialLength) {
- dump("Header info not correct: " + aRequest.substr(0, payloadStart));
- return null;
- }
- prefixSet.push(prefix);
- }
- prefixSet.sort();
-
- return prefixSet;
-}
-
-// Compare the requests in string format.
-function compareCompletionRequest(aRequest1, aRequest2) {
- let prefixSet1 = parseCompletionRequest(aRequest1);
- let prefixSet2 = parseCompletionRequest(aRequest2);
-
- return equal(JSON.stringify(prefixSet1), JSON.stringify(prefixSet2));
-}
-
-// The fifth completion set is added at runtime by getRandomCompletionSet.
-// Each completion in the set only has one response and its purpose is to
-// provide an easy way to test the HashCompleter handling an arbitrarily large
-// completion set (determined by SIZE_OF_RANDOM_SET).
-const SIZE_OF_RANDOM_SET = 16;
-function getRandomCompletionSet(forceServerError) {
- let completionSet = [];
- let hashPrefixes = [];
-
- let seed = Math.floor(Math.random() * Math.pow(2, 32));
- dump("Using seed of " + seed + " for random completion set.\n");
- let rand = new LFSRgenerator(seed);
-
- for (let i = 0; i < SIZE_OF_RANDOM_SET; i++) {
- let completion = { expectCompletion: false, forceServerError: false, _finished: false };
-
- // Generate a random 256 bit hash. First we get a random number and then
- // convert it to a string.
- let hash;
- let prefix;
- do {
- hash = "";
- let length = 1 + rand.nextNum(5);
- for (let i = 0; i < length; i++)
- hash += String.fromCharCode(rand.nextNum(8));
- prefix = hash.substring(0,4);
- } while (hashPrefixes.indexOf(prefix) != -1);
-
- hashPrefixes.push(prefix);
- completion.hash = hash;
-
- if (!forceServerError) {
- completion.expectCompletion = rand.nextNum(1) == 1;
- } else {
- completion.forceServerError = true;
- }
- if (completion.expectCompletion) {
- // Generate a random alpha-numeric string of length at most 6 for the
- // table name.
- completion.table = (rand.nextNum(31)).toString(36);
-
- completion.chunkId = rand.nextNum(16);
- }
- completionSet.push(completion);
- }
-
- return completionSet;
-}
-
-var completionSets = [basicCompletionSet, falseCompletionSet,
- dupedCompletionSet, multipleResponsesCompletionSet];
-var currentCompletionSet = -1;
-var finishedCompletions = 0;
-
-const SERVER_PORT = 8080;
-const SERVER_PATH = "/hash-completer";
-var server;
-
-// Completion hashes are automatically right-padded with null chars to have a
-// length of COMPLETE_LENGTH.
-// Taken from nsUrlClassifierDBService.h
-const COMPLETE_LENGTH = 32;
-
-var completer = Cc["@mozilla.org/url-classifier/hashcompleter;1"].
- getService(Ci.nsIUrlClassifierHashCompleter);
-
-var gethashUrl;
-
-// Expected highest completion set for which the server sends a response.
-var expectedMaxServerCompletionSet = 0;
-var maxServerCompletionSet = 0;
-
-function run_test() {
- // Generate a random completion set that return successful responses.
- completionSets.push(getRandomCompletionSet(false));
- // We backoff after receiving an error, so requests shouldn't reach the
- // server after that.
- expectedMaxServerCompletionSet = completionSets.length;
- // Generate some completion sets that return 503s.
- for (let j = 0; j < 10; ++j) {
- completionSets.push(getRandomCompletionSet(true));
- }
-
- // Fix up the completions before running the test.
- for (let completionSet of completionSets) {
- for (let completion of completionSet) {
- // Pad the right of each |hash| so that the length is COMPLETE_LENGTH.
- if (completion.multipleCompletions) {
- for (let responseCompletion of completion.completions) {
- let numChars = COMPLETE_LENGTH - responseCompletion.hash.length;
- responseCompletion.hash += (new Array(numChars + 1)).join("\u0000");
- }
- }
- else {
- let numChars = COMPLETE_LENGTH - completion.hash.length;
- completion.hash += (new Array(numChars + 1)).join("\u0000");
- }
- }
- }
- do_test_pending();
-
- server = new HttpServer();
- server.registerPathHandler(SERVER_PATH, hashCompleterServer);
-
- server.start(-1);
- const SERVER_PORT = server.identity.primaryPort;
-
- gethashUrl = "http://localhost:" + SERVER_PORT + SERVER_PATH;
-
- runNextCompletion();
-}
-
-function runNextCompletion() {
- // The server relies on currentCompletionSet to send the correct response, so
- // don't increment it until we start the new set of callbacks.
- currentCompletionSet++;
- if (currentCompletionSet >= completionSets.length) {
- finish();
- return;
- }
-
- dump("Now on completion set index " + currentCompletionSet + ", length " +
- completionSets[currentCompletionSet].length + "\n");
- // Number of finished completions for this set.
- finishedCompletions = 0;
- for (let completion of completionSets[currentCompletionSet]) {
- completer.complete(completion.hash.substring(0,4), gethashUrl,
- (new callback(completion)));
- }
-}
-
-function hashCompleterServer(aRequest, aResponse) {
- let stream = aRequest.bodyInputStream;
- let wrapperStream = Cc["@mozilla.org/binaryinputstream;1"].
- createInstance(Ci.nsIBinaryInputStream);
- wrapperStream.setInputStream(stream);
-
- let len = stream.available();
- let data = wrapperStream.readBytes(len);
-
- // Check if we got the expected completion request.
- let expectedRequest = buildCompletionRequest(completionSets[currentCompletionSet]);
- compareCompletionRequest(data, expectedRequest);
-
- // To avoid a response with duplicate hash completions, we keep track of all
- // completed hash prefixes so far.
- let completedHashes = [];
- let responseText = "";
-
- function responseForCompletion(x) {
- return x.table + ":" + x.chunkId + ":" + x.hash.length + "\n" + x.hash;
- }
- // As per the spec, a server should response with a 204 if there are no
- // full-length hashes that match the prefixes.
- let httpStatus = 204;
- for (let completion of completionSets[currentCompletionSet]) {
- if (completion.expectCompletion &&
- (completedHashes.indexOf(completion.hash) == -1)) {
- completedHashes.push(completion.hash);
-
- if (completion.multipleCompletions)
- responseText += completion.completions.map(responseForCompletion).join("");
- else
- responseText += responseForCompletion(completion);
- }
- if (completion.forceServerError) {
- httpStatus = 503;
- }
- }
-
- dump("Server sending response for " + currentCompletionSet + "\n");
- maxServerCompletionSet = currentCompletionSet;
- if (responseText && httpStatus != 503) {
- aResponse.write(responseText);
- } else {
- aResponse.setStatusLine(null, httpStatus, null);
- }
-}
-
-
-function callback(completion) {
- this._completion = completion;
-}
-
-callback.prototype = {
- completion: function completion(hash, table, chunkId, trusted) {
- do_check_true(this._completion.expectCompletion);
- if (this._completion.multipleCompletions) {
- for (let completion of this._completion.completions) {
- if (completion.hash == hash) {
- do_check_eq(JSON.stringify(hash), JSON.stringify(completion.hash));
- do_check_eq(table, completion.table);
- do_check_eq(chunkId, completion.chunkId);
-
- completion._completed = true;
-
- if (this._completion.completions.every(x => x._completed))
- this._completed = true;
-
- break;
- }
- }
- }
- else {
- // Hashes are not actually strings and can contain arbitrary data.
- do_check_eq(JSON.stringify(hash), JSON.stringify(this._completion.hash));
- do_check_eq(table, this._completion.table);
- do_check_eq(chunkId, this._completion.chunkId);
-
- this._completed = true;
- }
- },
-
- completionFinished: function completionFinished(status) {
- finishedCompletions++;
- do_check_eq(!!this._completion.expectCompletion, !!this._completed);
- this._completion._finished = true;
-
- // currentCompletionSet can mutate before all of the callbacks are complete.
- if (currentCompletionSet < completionSets.length &&
- finishedCompletions == completionSets[currentCompletionSet].length) {
- runNextCompletion();
- }
- },
-};
-
-function finish() {
- do_check_eq(expectedMaxServerCompletionSet, maxServerCompletionSet);
- server.stop(function() {
- do_test_finished();
- });
-}