From 2660a8554b1b75895874230d47d669f8ebde70c7 Mon Sep 17 00:00:00 2001 From: Bryan Housel Date: Mon, 8 Apr 2019 15:59:42 -0400 Subject: [PATCH] Add `isDataLoaded` and tilecache rtree for testing (re: #2248, #5938, maybe others) --- modules/services/osm.js | 31 +++++++------ test/spec/services/osm.js | 93 +++++++++++++++++++++++++++------------ 2 files changed, 84 insertions(+), 40 deletions(-) diff --git a/modules/services/osm.js b/modules/services/osm.js index 1f57c9fc6..3a3424232 100644 --- a/modules/services/osm.js +++ b/modules/services/osm.js @@ -27,7 +27,7 @@ var oauth = osmAuth({ }); var _blacklists = ['.*\.google(apis)?\..*/(vt|kh)[\?/].*([xyz]=.*){3}.*']; -var _tileCache = { loaded: {}, inflight: {}, seen: {} }; +var _tileCache = { loaded: {}, inflight: {}, seen: {}, rtree: rbush() }; var _noteCache = { loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: rbush() }; var _userCache = { toLoad: {}, user: {} }; var _changeset = {}; @@ -365,7 +365,7 @@ export default { Object.values(_noteCache.inflightPost).forEach(abortRequest); if (_changeset.inflight) abortRequest(_changeset.inflight); - _tileCache = { loaded: {}, inflight: {}, seen: {} }; + _tileCache = { loaded: {}, inflight: {}, seen: {}, rtree: rbush() }; _noteCache = { loaded: {}, inflight: {}, inflightPost: {}, note: {}, closed: {}, rtree: rbush() }; _userCache = { toLoad: {}, user: {} }; _changeset = {}; @@ -801,6 +801,9 @@ export default { delete _tileCache.inflight[tile.id]; if (!err) { _tileCache.loaded[tile.id] = true; + var bbox = tile.extent.bbox(); + bbox.id = tile.id; + _tileCache.rtree.insert(bbox); } if (callback) { callback(err, Object.assign({ data: parsed }, tile)); @@ -819,6 +822,12 @@ export default { }, + isDataLoaded: function(loc) { + var bbox = { minX: loc[0], minY: loc[1], maxX: loc[0], maxY: loc[1] }; + return _tileCache.rtree.collides(bbox); + }, + + // Load notes from the API in tiles // GET /api/0.6/notes?bbox= loadNotes: function(projection, noteOptions) { @@ -992,22 +1001,18 @@ export default { // This is used to save/restore the state when entering/exiting the walkthrough // Also used for testing purposes. caches: function(obj) { - function cloneDeep(source) { - return JSON.parse(JSON.stringify(source)); - } - - function cloneNoteCache(source) { + function cloneCache(source) { var target = {}; Object.keys(source).forEach(function(k) { if (k === 'rtree') { - target.rtree = rbush().fromJSON(source.rtree.toJSON()); + target.rtree = rbush().fromJSON(source.rtree.toJSON()); // clone rbush } else if (k === 'note') { target.note = {}; Object.keys(source.note).forEach(function(id) { - target.note[id] = osmNote(source.note[id]); + target.note[id] = osmNote(source.note[id]); // copy notes }); } else { - target[k] = cloneDeep(source[k]); + target[k] = JSON.parse(JSON.stringify(source[k])); // clone deep } }); return target; @@ -1015,9 +1020,9 @@ export default { if (!arguments.length) { return { - tile: cloneDeep(_tileCache), - note: cloneNoteCache(_noteCache), - user: cloneDeep(_userCache) + tile: cloneCache(_tileCache), + note: cloneCache(_noteCache), + user: cloneCache(_userCache) }; } diff --git a/test/spec/services/osm.js b/test/spec/services/osm.js index 476ff73c3..561f25406 100644 --- a/test/spec/services/osm.js +++ b/test/spec/services/osm.js @@ -293,14 +293,62 @@ describe('iD.serviceOsm', function () { }); + describe('#loadTiles', function() { + var tileXML = '' + + '' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ' ' + + ''; + + beforeEach(function() { + var dimensions = [64, 64]; + context.projection + .scale(iD.geoZoomToScale(20)) + .translate([55212042.434589595, 33248879.510193843]) // -74.0444216, 40.6694299 + .clipExtent([[0,0], dimensions]); + }); + + it('calls callback when data tiles are loaded', function() { + var spy = sinon.spy(); + connection.loadTiles(context.projection, spy); + + server.respondWith('GET', /map\?bbox/, + [200, { 'Content-Type': 'text/xml' }, tileXML]); + server.respond(); + + expect(spy).to.have.been.calledOnce; + }); + + it('#isDataLoaded', function() { + expect(connection.isDataLoaded([-74.0444216, 40.6694299])).to.be.not.ok; + + connection.loadTiles(context.projection); + server.respondWith('GET', /map\?bbox/, + [200, { 'Content-Type': 'text/xml' }, tileXML]); + server.respond(); + + expect(connection.isDataLoaded([-74.0444216, 40.6694299])).to.be.ok; + }); + }); + describe('#loadEntity', function () { - var nodeXML = '' + - '' + - ''; - var wayXML = '' + - '' + - '' + - ''; + var nodeXML = '' + + '' + + '' + + ''; + var wayXML = '' + + '' + + '' + + '' + + ''; beforeEach(function() { server = sinon.fakeServer.create(); @@ -357,12 +405,14 @@ describe('iD.serviceOsm', function () { describe('#loadEntityVersion', function () { - var nodeXML = '' + - '' + - ''; - var wayXML = '' + - '' + - ''; + var nodeXML = '' + + '' + + '' + + ''; + var wayXML = '' + + '' + + '' + + ''; beforeEach(function() { server = sinon.fakeServer.create(); @@ -539,21 +589,10 @@ describe('iD.serviceOsm', function () { describe('#caches', function() { it('loads reset caches', function (done) { - var resetCaches = { - tile: { - inflight: {}, loaded: {}, seen: {} - }, - note: { - loaded: {}, inflight: {}, inflightPost: {}, note: {} // not including rtree - }, - user: { - toLoad: {}, user: {} - } - }; var caches = connection.caches(); - expect(caches.tile).to.eql(resetCaches.tile); - expect(caches.note.loaded).to.eql(resetCaches.note.loaded); - expect(caches.user).to.eql(resetCaches.user); + expect(caches.tile).to.have.all.keys(['loaded','inflight','seen','rtree']); + expect(caches.note).to.have.all.keys(['loaded','inflight','inflightPost','note','closed','rtree']); + expect(caches.user).to.have.all.keys(['toLoad','user']); done(); });