summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authornick@chromium.org <nick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-22 22:50:18 +0000
committernick@chromium.org <nick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-22 22:50:18 +0000
commit6060cc40a173ae7e0d504fc7d545987a9603beda (patch)
tree8d2716780b723bbfe302f961c79eadd9e08a82e0 /net
parent73ab356682200243d2a07be449a079773b929d11 (diff)
downloadchromium_src-6060cc40a173ae7e0d504fc7d545987a9603beda.zip
chromium_src-6060cc40a173ae7e0d504fc7d545987a9603beda.tar.gz
chromium_src-6060cc40a173ae7e0d504fc7d545987a9603beda.tar.bz2
Implement changes_remaining GetUpdates response; this will reduce
the number of GetUpdates that the client actually does, since "changes_remaining == 0" is treated as a termination condition. Also, add an indication of client identity to the logger. BUG=55809 TEST=sync_integration_tests, chromiumsync_test.py Review URL: http://codereview.chromium.org/3462006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60229 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rwxr-xr-xnet/tools/testserver/chromiumsync.py47
-rwxr-xr-xnet/tools/testserver/chromiumsync_test.py76
-rw-r--r--net/tools/testserver/testserver.py2
3 files changed, 82 insertions, 43 deletions
diff --git a/net/tools/testserver/chromiumsync.py b/net/tools/testserver/chromiumsync.py
index c36054c..843761a 100755
--- a/net/tools/testserver/chromiumsync.py
+++ b/net/tools/testserver/chromiumsync.py
@@ -9,9 +9,11 @@ The details of the protocol are described mostly by comments in the protocol
buffer definition at chrome/browser/sync/protocol/sync.proto.
"""
+import cgi
import copy
import operator
import random
+import sys
import threading
import app_specifics_pb2
@@ -395,9 +397,11 @@ class SyncDataModel(object):
more recently than this value will be retrieved; older items will
be filtered out.
Returns:
- A tuple of (version, entries). Version is a new timestamp value, which
- should be used as the starting point for the next query. Entries is the
- batch of entries meeting the current timestamp query.
+ A tuple of (version, entries, changes_remaining). Version is a new
+ timestamp value, which should be used as the starting point for the
+ next query. Entries is the batch of entries meeting the current
+ timestamp query. Changes_remaining indicates the number of changes
+ left on the server after this batch.
"""
if timestamp == 0:
self._CreatePermanentItems(requested_types)
@@ -409,7 +413,7 @@ class SyncDataModel(object):
batch = new_changes[:self._BATCH_SIZE]
if not batch:
# Client is up to date.
- return (timestamp, [])
+ return (timestamp, [], 0)
# Restrict batch to requested types. Tombstones are untyped
# and will always get included.
@@ -418,7 +422,7 @@ class SyncDataModel(object):
# The new client timestamp is the timestamp of the last item in the
# batch, even if that item was filtered out.
- return (batch[-1].version, filtered)
+ return (batch[-1].version, filtered, len(new_changes) - len(batch))
def _CheckVersionForCommit(self, entry):
"""Perform an optimistic concurrency check on the version number.
@@ -607,6 +611,7 @@ class SyncDataModel(object):
self._SaveEntry(entry)
return entry
+
class TestServer(object):
"""An object to handle requests for one (and only one) Chrome Sync account.
@@ -619,8 +624,23 @@ class TestServer(object):
# The implementation supports exactly one account; its state is here.
self.account = SyncDataModel()
self.account_lock = threading.Lock()
-
- def HandleCommand(self, raw_request):
+ # Clients that have talked to us: a map from the full client ID
+ # to its nickname.
+ self.clients = {}
+ self.client_name_generator = ('+' * times + chr(c)
+ for times in xrange(0, sys.maxint) for c in xrange(ord('A'),ord('Z')))
+
+ def GetShortClientName(self, query):
+ parsed = cgi.parse_qs(query[query.find('?')+1:])
+ client_id = parsed.get('client_id')
+ if not client_id:
+ return '?'
+ client_id = client_id[0]
+ if client_id not in self.clients:
+ self.clients[client_id] = self.client_name_generator.next()
+ return self.clients[client_id]
+
+ def HandleCommand(self, query, raw_request):
"""Decode and handle a sync command from a raw input of bytes.
This is the main entry point for this class. It is safe to call this
@@ -643,19 +663,21 @@ class TestServer(object):
response = sync_pb2.ClientToServerResponse()
response.error_code = sync_pb2.ClientToServerResponse.SUCCESS
response.store_birthday = self.account.store_birthday
+ log_context = "[Client %s -> %s.py]" % (self.GetShortClientName(query),
+ __name__)
if contents == sync_pb2.ClientToServerMessage.AUTHENTICATE:
- print 'Authenticate'
+ print '%s Authenticate' % log_context
# We accept any authentication token, and support only one account.
# TODO(nick): Mock out the GAIA authentication as well; hook up here.
response.authenticate.user.email = 'syncjuser@chromium'
response.authenticate.user.display_name = 'Sync J User'
elif contents == sync_pb2.ClientToServerMessage.COMMIT:
- print 'Commit'
+ print '%s Commit' % log_context
self.HandleCommit(request.commit, response.commit)
elif contents == sync_pb2.ClientToServerMessage.GET_UPDATES:
- print ('GetUpdates from timestamp %d' %
- request.get_updates.from_timestamp)
+ print ('%s GetUpdates from timestamp %d' %
+ (log_context, request.get_updates.from_timestamp))
self.HandleGetUpdates(request.get_updates, response.get_updates)
return (200, response.SerializeToString())
finally:
@@ -716,9 +738,10 @@ class TestServer(object):
"""
update_response.SetInParent()
requested_types = GetRequestedTypes(update_request)
- new_timestamp, entries = self.account.GetChangesFromTimestamp(
+ new_timestamp, entries, remaining = self.account.GetChangesFromTimestamp(
requested_types, update_request.from_timestamp)
+ update_response.changes_remaining = remaining
# If the client is up to date, we are careful not to set the
# new_timestamp field.
if new_timestamp != update_request.from_timestamp:
diff --git a/net/tools/testserver/chromiumsync_test.py b/net/tools/testserver/chromiumsync_test.py
index 6d2beef..f753c3b 100755
--- a/net/tools/testserver/chromiumsync_test.py
+++ b/net/tools/testserver/chromiumsync_test.py
@@ -116,7 +116,8 @@ class SyncDataModelTest(unittest.TestCase):
self.model = chromiumsync.SyncDataModel()
request_types = [sync_type, chromiumsync.TOP_LEVEL]
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
expected_count = self.ExpectedPermanentItemCount(sync_type)
self.assertEqual(expected_count, version)
@@ -128,19 +129,24 @@ class SyncDataModelTest(unittest.TestCase):
self.assertTrue(change.version <= version)
# Test idempotence: another GetUpdates from ts=0 shouldn't recreate.
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
self.assertEqual(expected_count, version)
self.assertEqual(expected_count, len(changes))
+ self.assertEqual(0, remaining)
# Doing a wider GetUpdates from timestamp zero shouldn't recreate either.
- new_version, changes = self.model.GetChangesFromTimestamp(
- chromiumsync.ALL_TYPES, 0)
+ new_version, changes, remaining = (
+ self.model.GetChangesFromTimestamp(chromiumsync.ALL_TYPES, 0))
self.assertEqual(len(chromiumsync.SyncDataModel._PERMANENT_ITEM_SPECS),
new_version)
self.assertEqual(new_version, len(changes))
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ self.assertEqual(0, remaining)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
self.assertEqual(new_version, version)
self.assertEqual(expected_count, len(changes))
+ self.assertEqual(0, remaining)
def testBatchSize(self):
for sync_type in chromiumsync.ALL_TYPES[1:]:
@@ -153,19 +159,23 @@ class SyncDataModelTest(unittest.TestCase):
entry.id_string = 'batch test %d' % i
entry.specifics.CopyFrom(specifics)
self.model._SaveEntry(entry)
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ last_bit = self.ExpectedPermanentItemCount(sync_type)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
self.assertEqual(self.model._BATCH_SIZE, version)
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
+ self.assertEqual(self.model._BATCH_SIZE*2 + last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
self.assertEqual(self.model._BATCH_SIZE*2, version)
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
+ self.assertEqual(self.model._BATCH_SIZE + last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
self.assertEqual(self.model._BATCH_SIZE*3, version)
- expected_dingleberry = self.ExpectedPermanentItemCount(sync_type)
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
- self.assertEqual(self.model._BATCH_SIZE*3 + expected_dingleberry,
- version)
+ self.assertEqual(last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
+ self.assertEqual(self.model._BATCH_SIZE*3 + last_bit, version)
+ self.assertEqual(0, changes_remaining)
# Now delete a third of the items.
for i in xrange(self.model._BATCH_SIZE*3 - 1, 0, -3):
@@ -175,19 +185,23 @@ class SyncDataModelTest(unittest.TestCase):
self.model._SaveEntry(entry)
# The batch counts shouldn't change.
- version, changes = self.model.GetChangesFromTimestamp(request_types, 0)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, 0))
self.assertEqual(self.model._BATCH_SIZE, len(changes))
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
+ self.assertEqual(self.model._BATCH_SIZE*2 + last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
self.assertEqual(self.model._BATCH_SIZE, len(changes))
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
+ self.assertEqual(self.model._BATCH_SIZE + last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
self.assertEqual(self.model._BATCH_SIZE, len(changes))
- expected_dingleberry = self.ExpectedPermanentItemCount(sync_type)
- version, changes = self.model.GetChangesFromTimestamp(request_types,
- version)
- self.assertEqual(expected_dingleberry, len(changes))
- self.assertEqual(self.model._BATCH_SIZE*4 + expected_dingleberry, version)
+ self.assertEqual(last_bit, changes_remaining)
+ version, changes, changes_remaining = (
+ self.model.GetChangesFromTimestamp(request_types, version))
+ self.assertEqual(last_bit, len(changes))
+ self.assertEqual(self.model._BATCH_SIZE*4 + last_bit, version)
+ self.assertEqual(0, changes_remaining)
def testCommitEachDataType(self):
for sync_type in chromiumsync.ALL_TYPES[1:]:
@@ -198,7 +212,7 @@ class SyncDataModelTest(unittest.TestCase):
commit_session = {}
# Start with a GetUpdates from timestamp 0, to populate permanent items.
- original_version, original_changes = (
+ original_version, original_changes, changes_remaining = (
self.model.GetChangesFromTimestamp([sync_type], 0))
def DoCommit(original=None, id_string='', name=None, parent=None,
@@ -251,9 +265,10 @@ class SyncDataModelTest(unittest.TestCase):
self.assertTrue(r.version > original_version)
self.assertEqual(result1.parent_id_string, proto1.parent_id_string)
self.assertEqual(result2.parent_id_string, result1.id_string)
- version, changes = self.model.GetChangesFromTimestamp([sync_type],
- original_version)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp([sync_type], original_version))
self.assertEqual(3, len(changes))
+ self.assertEqual(0, remaining)
self.assertEqual(original_version + 3, version)
self.assertEqual([result1, result2, result3], changes)
for c in changes:
@@ -298,9 +313,10 @@ class SyncDataModelTest(unittest.TestCase):
self.assertTrue(p is not self.model._entries[r.id_string],
"Commit didn't make a defensive copy.")
self.assertTrue(r.version > p.version)
- version, changes = self.model.GetChangesFromTimestamp([sync_type],
- original_version)
+ version, changes, remaining = (
+ self.model.GetChangesFromTimestamp([sync_type], original_version))
self.assertEqual(5, len(changes))
+ self.assertEqual(0, remaining)
self.assertEqual(original_version + 7, version)
self.assertEqual([result3, result2b, result4, result1b, result5], changes)
for c in changes:
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index ee2476c..9f99d71 100644
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -1018,7 +1018,7 @@ class TestPageHandler(BaseHTTPServer.BaseHTTPRequestHandler):
import chromiumsync
self.server._sync_handler = chromiumsync.TestServer()
http_response, raw_reply = self.server._sync_handler.HandleCommand(
- raw_request)
+ self.path, raw_request)
self.send_response(http_response)
self.end_headers()
self.wfile.write(raw_reply)