1 | var test = require('tape')
|
2 | var hyperlog = require('hyperlog')
|
3 | var memdb = require('memdb')
|
4 | var path = require('path')
|
5 | var fdstore = require('fd-chunk-store')
|
6 | var osmdb = require('osm-p2p-db')
|
7 | var http = require('http')
|
8 | var url = require('url')
|
9 | var concat = require('concat-stream')
|
10 | var waterfall = require('run-waterfall')
|
11 | var eos = require('end-of-stream')
|
12 | var once = require('once')
|
13 |
|
14 | var tmpdir = require('os').tmpdir()
|
15 | var createServer = require('./lib/test_server.js')
|
16 | var slowdb = require('./lib/slowdb.js')
|
17 |
|
18 | var DELAY = process.env.OSM_P2P_DB_DELAY
|
19 |
|
20 | function createOsm () {
|
21 | var storefile = path.join(tmpdir, 'osm-store-' + Math.random())
|
22 | return osmdb({
|
23 | log: hyperlog(memdb(), { valueEncoding: 'json' }),
|
24 | db: DELAY ? slowdb({delay: DELAY}) : memdb(),
|
25 | store: fdstore(4096, storefile)
|
26 | })
|
27 | }
|
28 |
|
29 | test('do not include points from an excluded way fork', function (t) {
|
30 | t.plan(10)
|
31 |
|
32 |
|
33 | var osmBase = createOsm()
|
34 |
|
35 |
|
36 | var osmForkA = createOsm()
|
37 |
|
38 |
|
39 | var osmForkB = createOsm()
|
40 |
|
41 | var nodes = [
|
42 | {
|
43 | type: 'node',
|
44 | lon: 0,
|
45 | lat: -1
|
46 | },
|
47 | {
|
48 | type: 'node',
|
49 | lon: 0,
|
50 | lat: 0
|
51 | },
|
52 | {
|
53 | type: 'node',
|
54 | lon: 0,
|
55 | lat: 1
|
56 | }
|
57 | ]
|
58 |
|
59 | var wayId
|
60 | var wayVersionId
|
61 | var keyIds
|
62 | var forkARefs
|
63 | var forkAWayVersionId
|
64 | var forkBRefs
|
65 | var forkBWayVersionId
|
66 | var osmServer
|
67 |
|
68 |
|
69 | waterfall([
|
70 | step1,
|
71 | step2,
|
72 | step3,
|
73 | step4,
|
74 | step5,
|
75 | step6,
|
76 | step7,
|
77 | step8,
|
78 | step9
|
79 | ], function (err) {
|
80 | t.error(err)
|
81 | })
|
82 |
|
83 |
|
84 | function step1 (done) {
|
85 | createChangeset(osmBase, function (err, cs) {
|
86 | t.error(err)
|
87 | createNodes(osmBase, nodes, cs, function (keys) {
|
88 | keyIds = keys
|
89 | createWay(osmBase, keys, cs, function (err, way, wayVersion) {
|
90 | t.error(err)
|
91 | wayId = way
|
92 | wayVersionId = wayVersion
|
93 | done()
|
94 | })
|
95 | })
|
96 | })
|
97 | }
|
98 |
|
99 |
|
100 | function step2 (done) {
|
101 | sync(osmBase.log, osmForkA.log, function (err) {
|
102 | if (err) return done(err)
|
103 | osmForkB.ready(done)
|
104 | })
|
105 | }
|
106 |
|
107 |
|
108 | function step3 (done) {
|
109 | var node = {
|
110 | type: 'node',
|
111 | lon: 10,
|
112 | lat: 10
|
113 | }
|
114 | createChangeset(osmForkA, function (err, cs) {
|
115 | t.error(err)
|
116 | createNodes(osmForkA, [node], cs, function (keys) {
|
117 | var refs = keyIds.concat(keys)
|
118 | forkARefs = refs
|
119 | updateWay(osmForkA, wayId, wayVersionId, refs, cs, function (err, way) {
|
120 | t.error(err)
|
121 | forkAWayVersionId = way.key
|
122 | done()
|
123 | })
|
124 | })
|
125 | })
|
126 | }
|
127 |
|
128 |
|
129 | function step4 (done) {
|
130 | sync(osmBase.log, osmForkB.log, function (err) {
|
131 | if (err) return done(err)
|
132 | osmForkB.ready(done)
|
133 | })
|
134 | }
|
135 |
|
136 |
|
137 | function step5 (done) {
|
138 | var node = {
|
139 | type: 'node',
|
140 | lon: -10,
|
141 | lat: -10
|
142 | }
|
143 | createChangeset(osmForkB, function (err, cs) {
|
144 | t.error(err)
|
145 | createNodes(osmForkB, [node], cs, function (keys) {
|
146 | var refs = keyIds.concat(keys)
|
147 | forkBRefs = refs
|
148 | updateWay(osmForkB, wayId, wayVersionId, refs, cs, function (err, way) {
|
149 | forkBWayVersionId = way.key
|
150 | done(err)
|
151 | })
|
152 | })
|
153 | })
|
154 | }
|
155 |
|
156 |
|
157 | function step6 (done) {
|
158 | sync(osmForkA.log, osmForkB.log, function (err) {
|
159 | if (err) return done(err)
|
160 | osmForkB.ready(done)
|
161 | })
|
162 | }
|
163 |
|
164 |
|
165 | function step7 (done) {
|
166 | createServer(function (d) {
|
167 | osmServer = d
|
168 | done()
|
169 | })
|
170 | }
|
171 |
|
172 |
|
173 | function step8 (done) {
|
174 | sync(osmServer.osm.log, osmForkA.log, function (err) {
|
175 | t.error(err)
|
176 | osmServer.osm.ready(done)
|
177 | })
|
178 | }
|
179 |
|
180 |
|
181 | function step9 (done) {
|
182 | var opts = {
|
183 | hostname: 'localhost',
|
184 | port: url.parse(osmServer.base).port,
|
185 | path: '/api/0.6/map?bbox=-90,-90,90,90',
|
186 | headers: {
|
187 | 'Accept': 'application/json'
|
188 | }
|
189 | }
|
190 | http.get(opts, function (res) {
|
191 | res.pipe(concat(function (json) {
|
192 | var data = JSON.parse(json)
|
193 | var nodeIds = data.elements
|
194 | .filter(function (elm) { return elm.type === 'node' })
|
195 | .map(function (elm) { return elm.id })
|
196 | var ways = data.elements.filter(function (elm) { return elm.type === 'way' })
|
197 |
|
198 | t.equal(ways.length, 1)
|
199 |
|
200 |
|
201 | if (ways[0].version === forkAWayVersionId) {
|
202 | t.equal(ways[0].version, forkAWayVersionId)
|
203 | t.deepEqual(nodeIds.sort(), forkARefs.sort())
|
204 | } else if (ways[0].version === forkBWayVersionId) {
|
205 | t.equal(ways[0].version, forkBWayVersionId)
|
206 | t.deepEqual(nodeIds.sort(), forkBRefs.sort())
|
207 | } else {
|
208 | t.error('unexpected way version id')
|
209 | }
|
210 |
|
211 | osmServer.server.cleanup(done)
|
212 | }))
|
213 | })
|
214 | }
|
215 | })
|
216 |
|
217 | test('no extra points from forks /w 1 deleted node and 1 modified node', function (t) {
|
218 | t.plan(11)
|
219 |
|
220 |
|
221 | var osmBase = createOsm()
|
222 |
|
223 |
|
224 | var osmForkA = createOsm()
|
225 |
|
226 |
|
227 | var osmForkB = createOsm()
|
228 |
|
229 | var nodes = [
|
230 | {
|
231 | type: 'node',
|
232 | lon: 0,
|
233 | lat: -1
|
234 | },
|
235 | {
|
236 | type: 'node',
|
237 | lon: 0,
|
238 | lat: 0
|
239 | },
|
240 | {
|
241 | type: 'node',
|
242 | lon: 0,
|
243 | lat: 1
|
244 | }
|
245 | ]
|
246 |
|
247 | var wayId
|
248 | var wayVersionId
|
249 | var keyIds
|
250 | var forkBRefs
|
251 | var osmServer
|
252 |
|
253 |
|
254 | waterfall([
|
255 | step1,
|
256 | step2,
|
257 | step3,
|
258 | step4,
|
259 | step5,
|
260 | step6,
|
261 | step7,
|
262 | step8,
|
263 | step9
|
264 | ], function (err) {
|
265 | t.error(err)
|
266 | })
|
267 |
|
268 |
|
269 | function step1 (done) {
|
270 | createChangeset(osmBase, function (err, cs) {
|
271 | t.error(err)
|
272 | createNodes(osmBase, nodes, cs, function (keys) {
|
273 | keyIds = keys
|
274 | createWay(osmBase, keys, cs, function (err, way, wayVersion) {
|
275 | t.error(err)
|
276 | wayId = way
|
277 | wayVersionId = wayVersion
|
278 | done()
|
279 | })
|
280 | })
|
281 | })
|
282 | }
|
283 |
|
284 |
|
285 | function step2 (done) {
|
286 | sync(osmBase.log, osmForkA.log, function (err) {
|
287 | if (err) return done(err)
|
288 | osmForkB.ready(done)
|
289 | })
|
290 | }
|
291 |
|
292 |
|
293 | function step3 (done) {
|
294 | var node = {
|
295 | type: 'node',
|
296 | lon: 10,
|
297 | lat: 10
|
298 | }
|
299 | createChangeset(osmForkA, function (err, cs) {
|
300 | t.error(err)
|
301 | createNodes(osmForkA, [node], cs, function (keys) {
|
302 | var refs = keyIds.concat([])
|
303 | refs[2] = keys[0]
|
304 | updateWay(osmForkA, wayId, wayVersionId, refs, cs, function (err, way) {
|
305 | t.error(err)
|
306 | done()
|
307 | })
|
308 | })
|
309 | })
|
310 | }
|
311 |
|
312 |
|
313 | function step4 (done) {
|
314 | sync(osmBase.log, osmForkB.log, function (err) {
|
315 | if (err) return done(err)
|
316 | osmForkB.ready(done)
|
317 | })
|
318 | }
|
319 |
|
320 |
|
321 | function step5 (done) {
|
322 | createChangeset(osmForkB, function (err, cs) {
|
323 | t.error(err)
|
324 | deleteNode(osmForkB, keyIds[2], cs, function (err) {
|
325 | t.error(err)
|
326 | forkBRefs = keyIds.slice(0, 2)
|
327 | updateWay(osmForkB, wayId, wayVersionId, keyIds.slice(0, 2), cs, function (err, way) {
|
328 | done(err)
|
329 | })
|
330 | })
|
331 | })
|
332 | }
|
333 |
|
334 |
|
335 | function step6 (done) {
|
336 | sync(osmForkA.log, osmForkB.log, function (err) {
|
337 | if (err) return done(err)
|
338 | osmForkB.ready(done)
|
339 | })
|
340 | }
|
341 |
|
342 |
|
343 | function step7 (done) {
|
344 | createServer(function (d) {
|
345 | osmServer = d
|
346 | done()
|
347 | })
|
348 | }
|
349 |
|
350 |
|
351 | function step8 (done) {
|
352 | sync(osmServer.osm.log, osmForkA.log, function (err) {
|
353 | t.error(err)
|
354 | osmServer.osm.ready(done)
|
355 | })
|
356 | }
|
357 |
|
358 |
|
359 | function step9 (done) {
|
360 |
|
361 | function query (forks, done) {
|
362 | var opts = {
|
363 | hostname: 'localhost',
|
364 | port: url.parse(osmServer.base).port,
|
365 | path: '/api/0.6/map?bbox=-90,-90,90,90' + (forks ? '&forks=true' : ''),
|
366 | headers: {
|
367 | 'Accept': 'application/json'
|
368 | }
|
369 | }
|
370 | http.get(opts, function (res) {
|
371 | res.pipe(concat(function (json) {
|
372 | done(null, json)
|
373 | }))
|
374 | })
|
375 | }
|
376 |
|
377 | query(false, function (_, json) {
|
378 | var data = JSON.parse(json)
|
379 | var nodeIds = data.elements
|
380 | .filter(function (elm) { return elm.type === 'node' })
|
381 | .map(function (elm) { return elm.id })
|
382 | var ways = data.elements.filter(function (elm) { return elm.type === 'way' })
|
383 |
|
384 |
|
385 |
|
386 |
|
387 | if (nodeIds.length !== 2) {
|
388 | console.error('ERROR -- show @noffle this output!')
|
389 | query(true, function (_, json) {
|
390 | console.error(json.toString())
|
391 | osmServer.server.cleanup(done)
|
392 | })
|
393 | } else {
|
394 |
|
395 |
|
396 | t.equal(ways.length, 1)
|
397 | t.equal(nodeIds.length, 2)
|
398 | t.deepEqual(nodeIds.sort(), forkBRefs.sort())
|
399 |
|
400 | osmServer.server.cleanup(done)
|
401 | }
|
402 | })
|
403 | }
|
404 | })
|
405 |
|
406 |
|
407 | function createNodes (osm, nodes, changesetId, done) {
|
408 | var keys = []
|
409 | ;(function next () {
|
410 | var node = nodes.shift()
|
411 | if (!node) return done(keys)
|
412 | node.changeset = changesetId
|
413 | node.timestamp = (new Date()).toISOString()
|
414 | osm.create(node, function (err, key) {
|
415 | if (err) return done(err)
|
416 | keys.push(key)
|
417 | next()
|
418 | })
|
419 | })()
|
420 | }
|
421 |
|
422 |
|
423 | function deleteNode (osm, nodeId, changesetId, done) {
|
424 | var op = {
|
425 | type: 'del',
|
426 | key: nodeId,
|
427 | value: { type: 'node', changeset: changesetId }
|
428 | }
|
429 | osm.batch([op], done)
|
430 | }
|
431 |
|
432 |
|
433 | function createWay (osm, nodeIds, changesetId, done) {
|
434 | osm.create({
|
435 | type: 'way',
|
436 | refs: nodeIds,
|
437 | changeset: changesetId,
|
438 | timestamp: (new Date()).toISOString()
|
439 | }, function (err, key, node) {
|
440 | done(err, key, node.key)
|
441 | })
|
442 | }
|
443 |
|
444 |
|
445 | function updateWay (osm, way, parentId, refs, changesetId, done) {
|
446 | osm.put(way, {
|
447 | type: 'way',
|
448 | refs: refs,
|
449 | changeset: changesetId,
|
450 | timestamp: (new Date()).toISOString()
|
451 | },
|
452 | { links: [parentId] },
|
453 | function (err, way) {
|
454 | done(err, way)
|
455 | })
|
456 | }
|
457 |
|
458 |
|
459 | function createChangeset (osm, done) {
|
460 | osm.create({
|
461 | type: 'changeset'
|
462 | }, function (err, key, node) {
|
463 | done(err, key, node.key)
|
464 | })
|
465 | }
|
466 |
|
467 | function sync (log1, log2, done) {
|
468 | done = once(done)
|
469 | var r1 = log1.replicate()
|
470 | eos(r1, onEnd)
|
471 |
|
472 | var r2 = log2.replicate()
|
473 | eos(r2, onEnd)
|
474 |
|
475 | r1.pipe(r2).pipe(r1)
|
476 |
|
477 | var pending = 2
|
478 | function onEnd (err) {
|
479 | if (err) {
|
480 | return done(err)
|
481 | }
|
482 | if (--pending === 0) {
|
483 | return done()
|
484 | }
|
485 | }
|
486 | }
|