diff options
author | Aleksey Lim <alsroot@sugarlabs.org> | 2014-05-01 12:09:10 (GMT) |
---|---|---|
committer | Aleksey Lim <alsroot@sugarlabs.org> | 2014-05-01 12:09:10 (GMT) |
commit | d575dade236cd1c5ca345b79dc7a29f5d9a6959e (patch) | |
tree | dcaed3340cf1f3de1c42c5788932c630a6d0ea27 | |
parent | 7b650854958d03386ae54e87cbbb2bc82053661e (diff) |
Return metadata for aggregated items in API gets
-rw-r--r-- | sugar_network/client/model.py | 24 | ||||
-rw-r--r-- | sugar_network/db/blobs.py | 8 | ||||
-rw-r--r-- | sugar_network/db/metadata.py | 9 | ||||
-rw-r--r-- | sugar_network/node/model.py | 10 | ||||
-rwxr-xr-x | tests/units/client/client_routes.py | 24 | ||||
-rwxr-xr-x | tests/units/db/db_routes.py | 52 | ||||
-rwxr-xr-x | tests/units/model/context.py | 29 | ||||
-rwxr-xr-x | tests/units/node/node_model.py | 33 | ||||
-rwxr-xr-x | tests/units/node/node_routes.py | 19 |
9 files changed, 124 insertions, 84 deletions
diff --git a/sugar_network/client/model.py b/sugar_network/client/model.py index 0c5991f..0b3208b 100644 --- a/sugar_network/client/model.py +++ b/sugar_network/client/model.py @@ -65,24 +65,26 @@ def dump_volume(volume): if meta is None or 'seqno' not in meta: continue if isinstance(prop, db.Aggregated): - for aggid, value in doc.repr(name): + for agg in doc.repr(name): aggop = { 'method': 'POST', - 'path': [resource, doc.guid, name, aggid], + 'path': [resource, doc.guid, name, agg['key']], } - if isinstance(value, File): - value.meta['op'] = aggop - postfix.append(value) + aggvalue = agg['value'] + if isinstance(aggvalue, File): + aggvalue.meta['op'] = aggop + postfix.append(aggvalue) else: - postfix.append({'op': aggop, 'content': value}) + postfix.append({'op': aggop, 'content': aggvalue}) elif prop.acl & (ACL.WRITE | ACL.CREATE): if isinstance(prop, db.Blob): blob = volume.blobs.get(doc[name]) - blob.meta['op'] = { - 'method': 'PUT', - 'path': [resource, doc.guid, name], - } - postfix.append(blob) + if blob is not None: + blob.meta['op'] = { + 'method': 'PUT', + 'path': [resource, doc.guid, name], + } + postfix.append(blob) else: if isinstance(prop, db.Reference): keys.append(name) diff --git a/sugar_network/db/blobs.py b/sugar_network/db/blobs.py index 2faedb0..f283cb2 100644 --- a/sugar_network/db/blobs.py +++ b/sugar_network/db/blobs.py @@ -172,7 +172,7 @@ class Blobs(object): return blob def delete(self, path): - self._delete(self.path(path), None) + self._delete(path, self.path(path), None) def wipe(self, path): path = self.path(path) @@ -243,7 +243,7 @@ class Blobs(object): else: path = self._blob_path(patch.digest) if not patch.size: - self._delete(path, seqno) + self._delete(path.digest, path, seqno) return if not exists(dirname(path)): os.makedirs(dirname(path)) @@ -257,7 +257,9 @@ class Blobs(object): meta['x-seqno'] = str(seqno) _write_meta(path, meta, seqno) - def _delete(self, path, seqno): + def _delete(self, digest, path, seqno): + if digest.startswith('assets/'): + return if exists(path + _META_SUFFIX): if seqno is None: seqno = self._seqno.next() diff --git a/sugar_network/db/metadata.py b/sugar_network/db/metadata.py index 53034aa..53d3f40 100644 --- a/sugar_network/db/metadata.py +++ b/sugar_network/db/metadata.py @@ -390,7 +390,14 @@ class Aggregated(Composite): raise RuntimeError('Aggregated properties cannot be set directly') def reprcast(self, value): - return [(i, self.subreprcast(j['value'])) for i, j in value.items()] + result = [] + for key, aggvalue in value.items(): + if 'value' not in aggvalue: + continue + aggvalue['key'] = key + aggvalue['value'] = self._subtype.reprcast(aggvalue['value']) + result.append(aggvalue) + return result def encode(self, items): for agg in items.values(): diff --git a/sugar_network/node/model.py b/sugar_network/node/model.py index 310d2db..380963f 100644 --- a/sugar_network/node/model.py +++ b/sugar_network/node/model.py @@ -56,6 +56,7 @@ class _ReleaseValue(dict): class _Release(object): + _subcast = db.Dict() _package_subcast = db.Dict(db.List()) def typecast(self, value): @@ -71,6 +72,9 @@ class _Release(object): __, value = load_bundle(bundle, context=this.request.guid) return value.guid, value + def reprcast(self, value): + return self._subcast.reprcast(value) + def encode(self, value): return [] @@ -205,7 +209,7 @@ def diff_resource(in_r): blobs = [] def add_blob(blob): - if not isinstance(blob, File): + if not isinstance(blob, File) or 'x-seqno' not in blob.meta: return seqno = int(blob.meta['x-seqno']) ranges.include(out_r, seqno, seqno) @@ -215,8 +219,8 @@ def diff_resource(in_r): prop = doc.metadata[prop] value = prop.reprcast(meta['value']) if isinstance(prop, db.Aggregated): - for __, aggvalue in value: - add_blob(aggvalue) + for aggvalue in value: + add_blob(aggvalue['value']) else: add_blob(value) diff --git a/tests/units/client/client_routes.py b/tests/units/client/client_routes.py index e65a79d..863d1af 100755 --- a/tests/units/client/client_routes.py +++ b/tests/units/client/client_routes.py @@ -848,7 +848,7 @@ class ClientRoutesTest(tests.Test): 'content2', 'content3', ]), - sorted([''.join(ipc.download(i[1])) for i in ipc.get(['report', guid, 'logs'])])) + sorted([''.join(ipc.download(i['value'])) for i in ipc.get(['report', guid, 'logs'])])) assert not home_volume['report'][guid].exists self.stop_master() @@ -872,7 +872,7 @@ class ClientRoutesTest(tests.Test): 'content2', 'content3', ]), - sorted([''.join(ipc.download(i[1])) for i in ipc.get(['report', guid, 'logs'])])) + sorted([''.join(ipc.download(i['value'])) for i in ipc.get(['report', guid, 'logs'])])) assert home_volume['report'][guid].exists def test_inline(self): @@ -1092,14 +1092,14 @@ class ClientRoutesTest(tests.Test): self.assertEqual('1', local.get(['context', guid])['title']) coroutine.sleep(1.1) - self.assertEqual([[1, 1], [6, None]], self.client_routes._refresh_r.value) + self.assertEqual([[1, 1], [3, None]], self.client_routes._refresh_r.value) self.assertEqual(0, local_volume.seqno.value) remote.put(['context', guid, 'title'], '2') self.assertEqual('2', remote.get(['context', guid, 'title'])) self.assertEqual('1', local.get(['context', guid])['title']) - self.assertEqual([[1, 1], [6, None]], self.client_routes._refresh_r.value) + self.assertEqual([[1, 1], [3, None]], self.client_routes._refresh_r.value) self.assertEqual(0, local_volume.seqno.value) self.assertEqual('2', local.get(['context'], reply='title')['result'][0]['title']) @@ -1107,7 +1107,7 @@ class ClientRoutesTest(tests.Test): self.assertEqual('2', remote.get(['context', guid, 'title'])) self.assertEqual('2', local.get(['context', guid])['title']) - self.assertEqual([[1, 1], [7, None]], self.client_routes._refresh_r.value) + self.assertEqual([[1, 1], [4, None]], self.client_routes._refresh_r.value) self.assertEqual(0, local_volume.seqno.value) def test_PullCheckinsOnGettingOnline(self): @@ -1135,7 +1135,7 @@ class ClientRoutesTest(tests.Test): remote.put(['context', guid, 'title'], '2') self.assertEqual('2', remote.get(['context', guid, 'title'])) self.assertEqual('1', local.get(['context', guid])['title']) - self.assertEqual([[1, 1], [6, None]], self.client_routes._refresh_r.value) + self.assertEqual([[1, 1], [3, None]], self.client_routes._refresh_r.value) self.assertEqual(0, local_volume.seqno.value) self.stop_master() @@ -1144,7 +1144,7 @@ class ClientRoutesTest(tests.Test): self.wait_for_events(event='sync', state='done').wait() self.assertEqual('2', local.get(['context', guid])['title']) - self.assertEqual([[1, 1], [7, None]], self.client_routes._refresh_r.value) + self.assertEqual([[1, 1], [4, None]], self.client_routes._refresh_r.value) self.assertEqual(0, local_volume.seqno.value) def test_PullCheckinsOnUpdates(self): @@ -1171,7 +1171,7 @@ class ClientRoutesTest(tests.Test): self.assertEqual('1', remote.get(['context', guid, 'summary'])) self.assertEqual('1', local.get(['context', guid])['title']) self.assertEqual('1', local.get(['context', guid])['summary']) - self.assertEqual([[1, 1], [6, None]], self.client_routes._refresh_r.value) + self.assertEqual([[1, 1], [3, None]], self.client_routes._refresh_r.value) self.assertEqual(0, local_volume.seqno.value) local.put(['context', guid, 'summary'], '2') @@ -1179,7 +1179,7 @@ class ClientRoutesTest(tests.Test): self.assertEqual('2', remote.get(['context', guid, 'summary'])) self.assertEqual('2', local.get(['context', guid])['title']) self.assertEqual('2', local.get(['context', guid])['summary']) - self.assertEqual([[1, 1], [8, None]], self.client_routes._refresh_r.value) + self.assertEqual([[1, 1], [5, None]], self.client_routes._refresh_r.value) self.assertEqual(0, local_volume.seqno.value) def test_PushOfflineChanges(self): @@ -1190,10 +1190,10 @@ class ClientRoutesTest(tests.Test): local = IPCConnection() remote = Connection() - guid1 = local.post(['context'], {'type': 'activity', 'title': '1', 'summary': '1', 'description': '1'}) - guid2 = local.post(['context'], {'type': 'activity', 'title': '2', 'summary': '2', 'description': '2'}) + guid1 = local.post(['context'], {'type': 'activity', 'title': '1', 'summary': '1', 'description': '1', 'icon': '1'}) + guid2 = local.post(['context'], {'type': 'activity', 'title': '2', 'summary': '2', 'description': '2', 'icon': '2'}) local.put(['context', guid2], {'summary': '2_'}) - guid3 = local.post(['context'], {'type': 'activity', 'title': '3', 'summary': '3', 'description': '3'}) + guid3 = local.post(['context'], {'type': 'activity', 'title': '3', 'summary': '3', 'description': '3', 'icon': '3'}) local.delete(['context', guid3]) assert not local_volume.empty diff --git a/tests/units/db/db_routes.py b/tests/units/db/db_routes.py index 997aeec..9a0648e 100755 --- a/tests/units/db/db_routes.py +++ b/tests/units/db/db_routes.py @@ -1639,42 +1639,42 @@ class DbRoutesTest(tests.Test): agg1 = this.call(method='POST', path=['document', guid, 'props'], content=-1) agg2 = this.call(method='POST', path=['document', guid, 'props'], content=None) agg3 = this.call(method='POST', path=['document', guid, 'props'], content={'foo': 'bar'}) + this.call(method='DELETE', path=['document', guid, 'props', agg2]) self.assertEqual({ agg1: {'seqno': 2, 'ctime': 0, 'value': -1}, - agg2: {'seqno': 3, 'ctime': 0, 'value': None}, + agg2: {'seqno': 5, 'ctime': 0}, agg3: {'seqno': 4, 'ctime': 0, 'value': {'foo': 'bar'}}, }, volume['document'][guid]['props']) - self.assertEqual({ - agg1: -1, - agg2: None, - agg3: {'foo': 'bar'}, - }, - dict(this.call(method='GET', path=['document', guid, 'props']))) - self.assertEqual({ - agg1: -1, - agg2: None, - agg3: {'foo': 'bar'}, - }, - dict(this.call(method='GET', path=['document', guid], reply=['props'])['props'])) - self.assertEqual({ - agg1: -1, - agg2: None, - agg3: {'foo': 'bar'}, - }, - dict(this.call(method='GET', path=['document'], reply=['props'])['result'][0]['props'])) + self.assertEqual( + sorted([ + {'key': agg1, 'seqno': 2, 'ctime': 0, 'value': -1}, + {'key': agg3, 'seqno': 4, 'ctime': 0, 'value': {'foo': 'bar'}}, + ]), + sorted(this.call(method='GET', path=['document', guid, 'props']))) + self.assertEqual( + sorted([ + {'key': agg1, 'seqno': 2, 'ctime': 0, 'value': -1}, + {'key': agg3, 'seqno': 4, 'ctime': 0, 'value': {'foo': 'bar'}}, + ]), + sorted(this.call(method='GET', path=['document', guid], reply=['props'])['props'])) + self.assertEqual( + sorted([ + {'key': agg1, 'seqno': 2, 'ctime': 0, 'value': -1}, + {'key': agg3, 'seqno': 4, 'ctime': 0, 'value': {'foo': 'bar'}}, + ]), + sorted(this.call(method='GET', path=['document'], reply=['props'])['result'][0]['props'])) agg1 = this.call(method='POST', path=['document', guid, 'blobs'], content='1') - agg2 = this.call(method='POST', path=['document', guid, 'blobs'], content='2') agg3 = this.call(method='POST', path=['document', guid, 'blobs'], content='3') - self.assertEqual({ - agg1: 'http://localhost/blobs/' + hashlib.sha1('1').hexdigest(), - agg2: 'http://localhost/blobs/' + hashlib.sha1('2').hexdigest(), - agg3: 'http://localhost/blobs/' + hashlib.sha1('3').hexdigest(), - }, - dict(this.call(method='GET', path=['document', guid, 'blobs'], environ={'HTTP_HOST': 'localhost'}))) + self.assertEqual( + sorted([ + {'key': agg1, 'seqno': 7, 'ctime': 0, 'value': 'http://localhost/blobs/' + hashlib.sha1('1').hexdigest()}, + {'key': agg3, 'seqno': 9, 'ctime': 0, 'value': 'http://localhost/blobs/' + hashlib.sha1('3').hexdigest()}, + ]), + sorted(this.call(method='GET', path=['document', guid, 'blobs'], environ={'HTTP_HOST': 'localhost'}))) def test_FailOnAbsentAggprops(self): diff --git a/tests/units/model/context.py b/tests/units/model/context.py index 15315ec..457f072 100755 --- a/tests/units/model/context.py +++ b/tests/units/model/context.py @@ -44,32 +44,9 @@ class ContextTest(tests.Test): 'summary': 'summary', 'description': 'description', }) - svg = color_svg(file(volume.blobs.get('assets/activity.svg').path).read(), guid) - assert conn.request('GET', ['context', guid, 'artefact_icon']).content == svg - assert conn.request('GET', ['context', guid, 'icon']).content == svg_to_png(svg, 55).getvalue() - assert conn.request('GET', ['context', guid, 'logo']).content == svg_to_png(svg, 140).getvalue() - - guid = conn.post(['context'], { - 'type': 'book', - 'title': 'title', - 'summary': 'summary', - 'description': 'description', - }) - svg = color_svg(file(volume.blobs.get('assets/book.svg').path).read(), guid) - assert conn.request('GET', ['context', guid, 'artefact_icon']).content == svg - assert conn.request('GET', ['context', guid, 'icon']).content == svg_to_png(svg, 55).getvalue() - assert conn.request('GET', ['context', guid, 'logo']).content == svg_to_png(svg, 140).getvalue() - - guid = conn.post(['context'], { - 'type': 'group', - 'title': 'title', - 'summary': 'summary', - 'description': 'description', - }) - svg = color_svg(file(volume.blobs.get('assets/group.svg').path).read(), guid) - assert conn.request('GET', ['context', guid, 'artefact_icon']).content == svg - assert conn.request('GET', ['context', guid, 'icon']).content == svg_to_png(svg, 55).getvalue() - assert conn.request('GET', ['context', guid, 'logo']).content == svg_to_png(svg, 140).getvalue() + assert conn.request('GET', ['context', guid, 'artefact_icon']).content == file(volume.blobs.get('assets/missing.svg').path).read() + assert conn.request('GET', ['context', guid, 'icon']).content == file(volume.blobs.get('assets/missing.png').path).read() + assert conn.request('GET', ['context', guid, 'logo']).content == file(volume.blobs.get('assets/missing-logo.png').path).read() if __name__ == '__main__': diff --git a/tests/units/node/node_model.py b/tests/units/node/node_model.py index 6f0b9c7..6501e1d 100755 --- a/tests/units/node/node_model.py +++ b/tests/units/node/node_model.py @@ -1132,6 +1132,7 @@ class NodeModelTest(tests.Test): self.assertEqual(1, volume.release_seqno.value) def test_Packages(self): + self.override(time, 'time', lambda: 0) self.override(obs, 'get_repos', lambda: [ {'lsb_id': 'Gentoo', 'lsb_release': '2.1', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']}, {'lsb_id': 'Debian', 'lsb_release': '6.0', 'name': 'Debian-6.0', 'arches': ['x86']}, @@ -1156,6 +1157,8 @@ class NodeModelTest(tests.Test): '*': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']}, + 'ctime': 0, + 'seqno': 3, }, 'resolves': { 'Gentoo-2.1': {'status': 'success', 'packages': ['pkg1.bin', 'pkg2.bin', 'pkg3.devel'], 'version': [[1, 0], 0]}, @@ -1179,6 +1182,8 @@ class NodeModelTest(tests.Test): 'Gentoo': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']}, + 'ctime': 0, + 'seqno': 5, }, 'resolves': { 'Gentoo-2.1': {'status': 'success', 'packages': ['pkg1.bin', 'pkg2.bin', 'pkg3.devel'], 'version': [[1, 0], 0]}, @@ -1200,6 +1205,8 @@ class NodeModelTest(tests.Test): 'Debian-6.0': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']}, + 'ctime': 0, + 'seqno': 7, }, 'resolves': { 'Debian-6.0': {'status': 'success', 'packages': ['pkg1.bin', 'pkg2.bin', 'pkg3.devel'], 'version': [[1, 0], 0]}, @@ -1208,6 +1215,7 @@ class NodeModelTest(tests.Test): volume['context'][guid]['releases']) def test_UnresolvedPackages(self): + self.override(time, 'time', lambda: 0) self.override(obs, 'get_repos', lambda: [ {'lsb_id': 'Gentoo', 'lsb_release': '2.1', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']}, ]) @@ -1230,6 +1238,8 @@ class NodeModelTest(tests.Test): '*': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['pkg1.bin', 'pkg2.bin'], 'devel': ['pkg3.devel']}, + 'ctime': 0, + 'seqno': 3, }, 'resolves': { 'Gentoo-2.1': {'status': 'resolve failed'}, @@ -1238,6 +1248,7 @@ class NodeModelTest(tests.Test): volume['context'][guid]['releases']) def test_PackageOverrides(self): + self.override(time, 'time', lambda: 0) self.override(obs, 'get_repos', lambda: [ {'lsb_id': 'Gentoo', 'lsb_release': '2.1', 'name': 'Gentoo-2.1', 'arches': ['x86', 'x86_64']}, {'lsb_id': 'Debian', 'lsb_release': '6.0', 'name': 'Debian-6.0', 'arches': ['x86']}, @@ -1259,6 +1270,8 @@ class NodeModelTest(tests.Test): '*': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['1']}, + 'ctime': 0, + 'seqno': 3, }, 'resolves': { 'Gentoo-2.1': {'status': '1'}, @@ -1274,10 +1287,14 @@ class NodeModelTest(tests.Test): '*': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['1']}, + 'ctime': 0, + 'seqno': 3, }, 'Debian': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['2']}, + 'ctime': 0, + 'seqno': 4, }, 'resolves': { 'Gentoo-2.1': {'status': '1'}, @@ -1293,14 +1310,20 @@ class NodeModelTest(tests.Test): '*': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['1']}, + 'ctime': 0, + 'seqno': 3, }, 'Debian': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['2']}, + 'ctime': 0, + 'seqno': 4, }, 'Debian-6.0': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['3']}, + 'ctime': 0, + 'seqno': 5, }, 'resolves': { 'Gentoo-2.1': {'status': '1'}, @@ -1316,14 +1339,20 @@ class NodeModelTest(tests.Test): '*': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['1']}, + 'ctime': 0, + 'seqno': 3, }, 'Debian': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['4']}, + 'ctime': 0, + 'seqno': 6, }, 'Debian-6.0': { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, 'value': {'binary': ['3']}, + 'ctime': 0, + 'seqno': 5, }, 'resolves': { 'Gentoo-2.1': {'status': '1'}, @@ -1918,7 +1947,7 @@ class NodeModelTest(tests.Test): 'content-type': 'application/vnd.olpc-sugar', 'content-disposition': 'attachment; filename="Activity-1%s"' % (mimetypes.guess_extension('application/vnd.olpc-sugar') or ''), 'content-length': str(len(bundle)), - 'x-seqno': '6', + 'x-seqno': '3', }, blobs.get(blob.digest).meta) self.assertEqual(bundle_id, context) self.assertEqual([[1], 0], release['version']) @@ -1973,7 +2002,7 @@ class NodeModelTest(tests.Test): 'content-type': 'application/pdf', 'content-disposition': 'attachment; filename="NonActivity-2.pdf"', 'content-length': str(len(bundle)), - 'x-seqno': '6', + 'x-seqno': '3', }, blobs.get(blob.digest).meta) self.assertEqual(bundle_id, context) self.assertEqual([[2], 0], release['version']) diff --git a/tests/units/node/node_routes.py b/tests/units/node/node_routes.py index 74bba7b..2332e36 100755 --- a/tests/units/node/node_routes.py +++ b/tests/units/node/node_routes.py @@ -409,6 +409,8 @@ class NodeRoutesTest(tests.Test): assert 'last-modified' not in response.headers def test_SubmitReleasesViaAggpropsIface(self): + ts = int(time.time()) + self.override(time, 'time', lambda: ts) volume = self.start_master() conn = Connection() @@ -443,6 +445,8 @@ class NodeRoutesTest(tests.Test): 'bundles': {'*-*': {'blob': str(hashlib.sha1(bundle1).hexdigest()), 'unpack_size': len(activity_info1)}}, 'stability': 'stable', }, + 'ctime': ts, + 'seqno': 6, }, }, volume['context'][context]['releases']) assert volume.blobs.get(str(hashlib.sha1(bundle1).hexdigest())).exists @@ -471,6 +475,8 @@ class NodeRoutesTest(tests.Test): 'bundles': {'*-*': {'blob': str(hashlib.sha1(bundle1).hexdigest()), 'unpack_size': len(activity_info1)}}, 'stability': 'stable', }, + 'ctime': ts, + 'seqno': 6, }, release2: { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, @@ -483,6 +489,8 @@ class NodeRoutesTest(tests.Test): 'bundles': {'*-*': {'blob': str(hashlib.sha1(bundle2).hexdigest()), 'unpack_size': len(activity_info2)}}, 'stability': 'stable', }, + 'ctime': ts, + 'seqno': 9, }, }, volume['context'][context]['releases']) assert volume.blobs.get(str(hashlib.sha1(bundle1).hexdigest())).exists @@ -492,6 +500,8 @@ class NodeRoutesTest(tests.Test): self.assertEqual({ release1: { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, + 'ctime': ts, + 'seqno': 11, }, release2: { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, @@ -504,6 +514,8 @@ class NodeRoutesTest(tests.Test): 'bundles': {'*-*': {'blob': str(hashlib.sha1(bundle2).hexdigest()), 'unpack_size': len(activity_info2)}}, 'stability': 'stable', }, + 'ctime': ts, + 'seqno': 9, }, }, volume['context'][context]['releases']) assert not volume.blobs.get(str(hashlib.sha1(bundle1).hexdigest())).exists @@ -513,9 +525,13 @@ class NodeRoutesTest(tests.Test): self.assertEqual({ release1: { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, + 'ctime': ts, + 'seqno': 11, }, release2: { 'author': {tests.UID: {'name': 'test', 'order': 0, 'role': 3}}, + 'ctime': ts, + 'seqno': 13, }, }, volume['context'][context]['releases']) assert not volume.blobs.get(str(hashlib.sha1(bundle1).hexdigest())).exists @@ -540,6 +556,7 @@ class NodeRoutesTest(tests.Test): ('topdir/activity/activity.info', activity_info), ('topdir/CHANGELOG', changelog), ) + self.override(time, 'time', lambda: 0) release = json.load(conn.request('POST', ['context'], bundle, params={'cmd': 'submit', 'initial': True}).raw) announce = next(volume['post'].find(query='1', limit=1)[0]).guid @@ -555,6 +572,8 @@ class NodeRoutesTest(tests.Test): 'commands': {'activity': {'exec': 'true'}}, 'stability': 'developer', }, + 'ctime': 0, + 'seqno': 5, }, }, volume['context']['bundle_id']['releases']) |