UNPKG

osm-p2p-server

Version:

Peer-to-peer OpenStreetMap API v0.6 Server

365 lines (347 loc) 10.6 kB
var test = require('tape') var contentType = require('content-type') var parsexml = require('xml-parser') var hyperquest = require('hyperquest') var concat = require('concat-stream') var isISODate = require('isostring') var base, server, changeId var createServer = require('./lib/test_server.js') test('changeset_upload_relation.js: setup server', function (t) { createServer(function (d) { base = d.base server = d.server t.end() }) }) test('create changeset upload', function (t) { t.plan(4) var href = base + 'changeset/create' var hq = hyperquest.put(href, { headers: { 'content-type': 'text/xml' } }) hq.once('response', function (res) { t.equal(res.statusCode, 200, 'create 200 ok') var contentObj = contentType.parse(res) t.equal(contentObj.type, 'text/plain', 'media type correct') t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct') }) hq.pipe(concat({ encoding: 'string' }, function (body) { changeId = body.trim() t.ok(/^[0-9A-Fa-f]+$/.test(changeId), 'expected changeset id response') })) hq.end(`<osm> <changeset> <tag k="comment" v="wow"/> </changeset> </osm>`) }) var ids = {} var versions = {} test('add docs to changeset upload', function (t) { t.plan(9) var href = base + 'changeset/' + changeId + '/upload' var hq = hyperquest.post(href, { headers: { 'content-type': 'text/xml' } }) hq.on('response', function (res) { t.equal(res.statusCode, 200) var contentObj = contentType.parse(res) t.equal(contentObj.type, 'text/xml', 'media type correct') t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct') }) hq.pipe(concat({ encoding: 'string' }, function (body) { var xml = parsexml(body) t.equal(xml.root.name, 'diffResult') t.deepEqual(xml.root.children.map(function (c) { return c.attributes.old_id }).sort(), ['-1', '-2', '-3', '-4']) xml.root.children.forEach(function (c) { ids[c.attributes.old_id] = c.attributes.new_id t.notEqual(c.attributes.old_id, c.attributes.new_id, 'placeholder id should not equal new id') versions[c.attributes.old_id] = c.attributes.new_version }) })) hq.end(`<osmChange version="1.0" generator="acme osm editor"> <create> <node id="-1" changeset="${changeId}" lat="64.5" lon="-121.5"/> <node id="-2" changeset="${changeId}" lat="63.9" lon="-120.9"/> <way id="-3" changeset="${changeId}"> <nd ref="-1"/> <nd ref="-2"/> </way> <relation id="-4" changeset="${changeId}"> <tag k="hello" v="world" /> <member type="way" ref="-3" role="" /> </relation> </create> </osmChange>`) }) test('get osmchange doc from upload', function (t) { t.plan(8) var expected = [ { name: 'node', attributes: { changeset: changeId, id: ids['-1'], version: versions['-1'], lat: '64.5', lon: '-121.5' }, children: [] }, { name: 'node', attributes: { changeset: changeId, id: ids['-2'], version: versions['-2'], lat: '63.9', lon: '-120.9' }, children: [] }, { name: 'way', attributes: { changeset: changeId, id: ids['-3'], version: versions['-3'] }, content: '', children: [ { name: 'nd', attributes: { ref: ids['-2'] }, children: [] }, { name: 'nd', attributes: { ref: ids['-1'] }, children: [] } ].sort(cmpref) }, { name: 'relation', attributes: { changeset: changeId, id: ids['-4'], version: versions['-4'] }, content: '', children: [ { name: 'member', attributes: { type: 'way', ref: ids['-3'], role: '' }, children: [] }, { name: 'tag', attributes: { k: 'hello', v: 'world' }, children: [] } ] } ].sort(cmpch) var href = base + 'changeset/' + changeId + '/download' var hq = hyperquest(href, { headers: { 'content-type': 'text/xml' } }) hq.pipe(concat({ encoding: 'string' }, function (body) { var xml = parsexml(body) t.equal(xml.root.name, 'osmChange') t.equal(xml.root.children.length, 1) t.equal(xml.root.children[0].name, 'create') xml.root.children[0].children.sort(cmpch) xml.root.children[0].children.forEach(function (c) { c.children.sort(cmpref) }) xml.root.children[0].children.forEach(function (c) { t.true(isISODate(c.attributes.timestamp)) delete c.attributes.timestamp }) t.deepEqual(xml.root.children[0].children, expected) })) }) test('close changeset', function (t) { t.plan(2) var href = base + 'changeset/' + changeId + '/close' var hq = hyperquest.put(href) hq.once('response', function (res) { t.equal(res.statusCode, 200, 'create 200 ok') }) hq.pipe(concat({ encoding: 'string' }, function (body) { t.equal(body.trim(), '', 'empty response') })) hq.end() }) test('close already closed changeset', function (t) { t.plan(4) var href = base + 'changeset/' + changeId + '/close' var hq = hyperquest.put(href) hq.once('response', function (res) { t.equal(res.statusCode, 409, 'expected conflict code') var contentObj = contentType.parse(res) t.equal(contentObj.type, 'text/plain', 'media type correct') t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct') }) hq.pipe(concat({ encoding: 'string' }, function (body) { t.equal( body.trim().replace(/closed at.*/, 'closed at'), 'The changeset ' + changeId + ' was closed at', 'already closed message' ) })) hq.end() }) test('upload to closed changeset', function (t) { t.plan(4) var href = base + 'changeset/' + changeId + '/upload' var hq = hyperquest.post(href, { headers: { 'content-type': 'text/xml' } }) hq.on('response', function (res) { t.equal(res.statusCode, 409, 'expected conflict code') var contentObj = contentType.parse(res) t.equal(contentObj.type, 'text/plain', 'media type correct') t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct') }) hq.pipe(concat({ encoding: 'string' }, function (body) { t.equal( body.trim().replace(/closed at.*/, 'closed at'), 'The changeset ' + changeId + ' was closed at', 'already closed message' ) })) hq.end(`<osmChange version="1.0" generator="acme osm editor"> <create> <node id="-1" changeset="${changeId}" lat="64.5" lon="-121.5"/> <node id="-2" changeset="${changeId}" lat="63.9" lon="-120.9"/> <way id="-3" changeset="${changeId}"> <nd ref="-1"/> <nd ref="-2"/> </way> </create> </osmChange>`) }) var secondChangeId test('create second changeset', function (t) { t.plan(4) var href = base + 'changeset/create' var hq = hyperquest.put(href, { headers: { 'content-type': 'text/xml' } }) hq.once('response', function (res) { t.equal(res.statusCode, 200, 'create 200 ok') var contentObj = contentType.parse(res) t.equal(contentObj.type, 'text/plain', 'media type correct') t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct') }) hq.pipe(concat({ encoding: 'string' }, function (body) { secondChangeId = body.trim() t.ok(/^[0-9A-Fa-f]+$/.test(secondChangeId), 'expected changeset id response') })) hq.end(`<osm> <changeset> <tag k="comment" v="second"/> </changeset> </osm>`) }) test('second changeset upload', function (t) { t.plan(13) var href = base + 'changeset/' + secondChangeId + '/upload' var hq = hyperquest.post(href, { headers: { 'content-type': 'text/xml' } }) hq.on('response', function (res) { t.equal(res.statusCode, 200) var contentObj = contentType.parse(res) t.equal(contentObj.type, 'text/xml', 'media type correct') t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct') }) var oldv, newv hq.pipe(concat({ encoding: 'string' }, function (body) { var xml = parsexml(body) t.equal(xml.root.name, 'diffResult') t.deepEqual(xml.root.children.map(function (c) { return c.attributes.old_id }).sort(), [ids['-1']]) oldv = versions['-1'] newv = xml.root.children[0].attributes.new_version hyperquest.get(base + 'node/' + ids['-1'] + '/' + newv) .on('response', function (res) { t.equal(res.statusCode, 200) }) .pipe(concat({ encoding: 'string' }, onnew)) hyperquest.get(base + 'node/' + ids['-1'] + '/' + oldv) .on('response', function (res) { t.equal(res.statusCode, 200) }) .pipe(concat({ encoding: 'string' }, onold)) })) hq.end(`<osmChange version="1.0" generator="acme osm editor"> <modify> <node id="${ids['-1']}" changeset="${secondChangeId}" lat="111" lon="222"/> </modify> </osmChange>`) function onnew (body) { var xml = parsexml(body) t.equal(xml.root.name, 'osm') t.true(isISODate(xml.root.children[0].attributes.timestamp)) delete xml.root.children[0].attributes.timestamp t.deepEqual(xml.root.children, [ { name: 'node', attributes: { changeset: secondChangeId, lat: '111', lon: '222', id: ids['-1'], version: newv }, children: [] } ]) } function onold (body) { var xml = parsexml(body) t.equal(xml.root.name, 'osm') t.true(isISODate(xml.root.children[0].attributes.timestamp)) delete xml.root.children[0].attributes.timestamp t.deepEqual(xml.root.children, [ { name: 'node', attributes: { changeset: changeId, lat: '64.5', lon: '-121.5', id: ids['-1'], version: oldv }, children: [] } ]) } }) test('changeset_upload_relation.js: teardown server', function (t) { server.cleanup(function () { t.end() }) }) function cmpch (a, b) { return a.attributes.id < b.attributes.id ? -1 : 1 } function cmpref (a, b) { if (a.name === 'tag' && b.name !== 'tag') { return 1 } if (a.name !== 'tag' && b.name === 'tag') { return -1 } if (a.name === 'tag' && b.name === 'tag') { return a.attributes.k < b.attributes.tag ? -1 : 1 } return a.attributes.ref < b.attributes.ref ? -1 : 1 }