Merge m-c to s-c
authorPhilipp von Weitershausen <philipp@weitershausen.de>
Thu, 18 Aug 2011 08:31:34 -0700
changeset 75717 ce40d612aa2707d326dff9c2ac948dc8f6a9a2b0
parent 75467 fb919f4fa210316d936e4cc4677462b0bf4fab68 (current diff)
parent 75716 d3d4b249830da7297387515d2898f42127a7df07 (diff)
child 75718 875ce445cdbf0fb2ae1d5d493a7172728b71fa7f
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
milestone9.0a1
Merge m-c to s-c
--- a/services/sync/modules/engines/clients.js
+++ b/services/sync/modules/engines/clients.js
@@ -194,17 +194,18 @@ ClientEngine.prototype = {
    * and the value is a hash containing information about the command such as
    * number of arguments and description.
    */
   _commands: {
     resetAll:    { args: 0, desc: "Clear temporary local data for all engines" },
     resetEngine: { args: 1, desc: "Clear temporary local data for engine" },
     wipeAll:     { args: 0, desc: "Delete all client data for all engines" },
     wipeEngine:  { args: 1, desc: "Delete all client data for engine" },
-    logout:      { args: 0, desc: "Log out client" }
+    logout:      { args: 0, desc: "Log out client" },
+    displayURI:  { args: 2, desc: "Instruct a client to display a URI" }
   },
 
   /**
    * Remove any commands for the local client and mark it for upload.
    */
   clearCommands: function clearCommands() {
     delete this.localCommands;
     this._tracker.addChangedID(this.localID);
@@ -279,16 +280,19 @@ ClientEngine.prototype = {
             engines = null;
             // Fallthrough
           case "wipeEngine":
             Weave.Service.wipeClient(engines);
             break;
           case "logout":
             Weave.Service.logout();
             return false;
+          case "displayURI":
+            this._handleDisplayURI(args[0], args[1]);
+            break;
           default:
             this._log.debug("Received an unknown command: " + command);
             break;
         }
       }
 
       return true;
     })();
@@ -325,16 +329,62 @@ ClientEngine.prototype = {
 
     if (clientId) {
       this._sendCommandToClient(command, args, clientId);
     } else {
       for (let id in this._store._remoteClients) {
         this._sendCommandToClient(command, args, id);
       }
     }
+  },
+
+  /**
+   * Send a URI to another client for display.
+   *
+   * A side effect is the score is increased dramatically to incur an
+   * immediate sync.
+   *
+   * If an unknown client ID is specified, sendCommand() will throw an
+   * Error object.
+   *
+   * @param uri
+   *        URI (as a string) to send and display on the remote client
+   * @param clientId
+   *        ID of client to send the command to. If not defined, will be sent
+   *        to all remote clients.
+   */
+  sendURIToClientForDisplay: function sendURIToClientForDisplay(uri, clientId) {
+    this._log.info("Sending URI to client: " + uri + " -> " + clientId);
+    this.sendCommand("displayURI", [uri, this.syncID], clientId);
+
+    Clients._tracker.score += SCORE_INCREMENT_XLARGE;
+  },
+
+  /**
+   * Handle a single received 'displayURI' command.
+   *
+   * Interested parties should observe the "weave:engine:clients:display-uri"
+   * topic. The callback will receive an object as the subject parameter with
+   * the following keys:
+   *
+   *   uri       URI (string) that is requested for display
+   *   clientId  ID of client that sent the command
+   *
+   * The 'data' parameter to the callback will not be defined.
+   *
+   * @param uri
+   *        String URI that was received
+   * @param clientId
+   *        ID of client that sent URI
+   */
+  _handleDisplayURI: function _handleDisplayURI(uri, clientId) {
+    this._log.info("Received a URI for display: " + uri + " from " + clientId);
+
+    let subject = { uri: uri, client: clientId };
+    Svc.Obs.notify("weave:engine:clients:display-uri", subject);
   }
 };
 
 function ClientStore(name) {
   Store.call(this, name);
 }
 ClientStore.prototype = {
   __proto__: Store.prototype,
--- a/services/sync/modules/policies.js
+++ b/services/sync/modules/policies.js
@@ -231,17 +231,17 @@ let SyncScheduler = {
       this.syncInterval = this.immediateInterval;
     } else {
       this._log.trace("Adjusting syncInterval to activeInterval.");
       this.syncInterval = this.activeInterval;
     }
   },
 
   calculateScore: function calculateScore() {
-    var engines = Engines.getEnabled();
+    let engines = [Clients].concat(Engines.getEnabled());
     for (let i = 0;i < engines.length;i++) {
       this._log.trace(engines[i].name + ": score: " + engines[i].score);
       this.globalScore += engines[i].score;
       engines[i]._tracker.resetScore();
     }
 
     this._log.trace("Global score updated: " + this.globalScore);
     this.checkSyncStatus();
--- a/services/sync/tests/unit/test_clients_engine.js
+++ b/services/sync/tests/unit/test_clients_engine.js
@@ -444,13 +444,94 @@ add_test(function test_command_sync() {
 
   } finally {
     Svc.Prefs.resetBranch("");
     Records.clearCache();
     server.stop(run_next_test);
   }
 });
 
+add_test(function test_send_uri_to_client_for_display() {
+  _("Ensure sendURIToClientForDisplay() sends command properly.");
+
+  let tracker = Clients._tracker;
+  let store = Clients._store;
+
+  let remoteId = Utils.makeGUID();
+  let rec = new ClientsRec("clients", remoteId);
+  rec.name = "remote";
+  store.create(rec);
+  let remoteRecord = store.createRecord(remoteId, "clients");
+
+  tracker.clearChangedIDs();
+  let initialScore = tracker.score;
+
+  let uri = "http://www.mozilla.org/";
+  Clients.sendURIToClientForDisplay(uri, remoteId);
+
+  let newRecord = store._remoteClients[remoteId];
+
+  do_check_neq(newRecord, undefined);
+  do_check_eq(newRecord.commands.length, 1);
+
+  let command = newRecord.commands[0];
+  do_check_eq(command.command, "displayURI");
+  do_check_eq(command.args.length, 2);
+  do_check_eq(command.args[0], uri);
+
+  do_check_true(tracker.score > initialScore);
+  do_check_true(tracker.score - initialScore >= SCORE_INCREMENT_XLARGE);
+
+  _("Ensure unknown client IDs result in exception.");
+  let unknownId = Utils.makeGUID();
+  let error;
+
+  try {
+    Clients.sendURIToClientForDisplay(uri, unknownId);
+  } catch (ex) {
+    error = ex;
+  }
+
+  do_check_eq(error.message.indexOf("Unknown remote client ID: "), 0);
+
+  run_next_test();
+});
+
+add_test(function test_receive_display_uri() {
+  _("Ensure processing of received 'displayURI' commands works.");
+
+  // We don't set up WBOs and perform syncing because other tests verify
+  // the command API works as advertised. This saves us a little work.
+
+  let uri = "http://www.mozilla.org/";
+  let remoteId = Utils.makeGUID();
+
+  let command = {
+    command: "displayURI",
+    args: [uri, remoteId],
+  };
+
+  Clients.localCommands = [command];
+
+  // Received 'displayURI' command should result in the topic defined below
+  // being called.
+  let ev = "weave:engine:clients:display-uri";
+
+  let handler = function(subject, data) {
+    Svc.Obs.remove(ev, handler);
+
+    do_check_eq(subject.uri, uri);
+    do_check_eq(subject.client, remoteId);
+    do_check_eq(data, null);
+
+    run_next_test();
+  };
+
+  Svc.Obs.add(ev, handler);
+
+  do_check_true(Clients.processIncomingCommands());
+});
+
 function run_test() {
   initTestLogging("Trace");
   Log4Moz.repository.getLogger("Sync.Engine.Clients").level = Log4Moz.Level.Trace;
   run_next_test();
 }
--- a/services/sync/tests/unit/test_score_triggers.js
+++ b/services/sync/tests/unit/test_score_triggers.js
@@ -1,12 +1,13 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-sync/engines.js");
+Cu.import("resource://services-sync/engines/clients.js");
 Cu.import("resource://services-sync/constants.js");
 Cu.import("resource://services-sync/policies.js");
 
 Svc.DefaultPrefs.set("registerEngines", "");
 Cu.import("resource://services-sync/service.js");
 
 Engines.register(RotaryEngine);
 let engine = Engines.get("rotary");
@@ -90,8 +91,30 @@ add_test(function test_sync_triggered() 
     Svc.Obs.remove("weave:service:sync:finish", onSyncFinish);
     _("Sync completed!");
     server.stop(run_next_test);
   });
 
   tracker.score += SCORE_INCREMENT_XLARGE;
 });
 
+add_test(function test_clients_engine_sync_triggered() {
+  _("Ensure that client engine score changes trigger a sync.");
+
+  // The clients engine is not registered like other engines. Therefore,
+  // it needs special treatment throughout the code. Here, we verify the
+  // global score tracker gives it that treatment. See bug 676042 for more.
+
+  let server = sync_httpd_setup();
+  setUp();
+  Service.login();
+
+  const TOPIC = "weave:service:sync:finish";
+  Svc.Obs.add(TOPIC, function onSyncFinish() {
+    Svc.Obs.remove(TOPIC, onSyncFinish);
+    _("Sync due to clients engine change completed.");
+    server.stop(run_next_test);
+  });
+
+  SyncScheduler.syncThreshold = MULTI_DEVICE_THRESHOLD;
+  Clients._tracker.score += SCORE_INCREMENT_XLARGE;
+});
+
--- a/testing/tps/setup.py
+++ b/testing/tps/setup.py
@@ -38,17 +38,17 @@
 import sys
 from setuptools import setup, find_packages
 
 version = '0.2.40'
 
 deps = ['pulsebuildmonitor >= 0.2', 'MozillaPulse == .4', 
         'mozinfo == 0.3.1', 'mozprofile == 0.1a',
         'mozprocess == 0.1a', 'mozrunner == 3.0a', 'mozregression == 0.3',
-        'mozautolog >= 0.2.0']
+        'mozautolog >= 0.2.1']
 
 # we only support python 2.6+ right now
 assert sys.version_info[0] == 2
 assert sys.version_info[1] >= 6
 
 setup(name='tps',
       version=version,
       description='run automated multi-profile sync tests',