osm-p2p-server
Version:
Peer-to-peer OpenStreetMap API v0.6 Server
256 lines (239 loc) • 8.19 kB
JavaScript
var test = require('tape')
var contentType = require('content-type')
var parsexml = require('xml-parser')
var hyperquest = require('hyperquest')
var concat = require('concat-stream')
var createServer = require('./lib/test_server.js')
var base, server, changeId
test('bbox.js: setup changeset server', function (t) {
createServer(function (d) {
base = d.base
server = d.server
t.end()
})
})
test('create bbox', 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></changeset></osm>')
})
var uploaded = {}
var SIZE = 100
test('add docs to changeset', function (t) {
t.plan(4)
var docs = []
for (var i = 0; i < SIZE; i++) {
docs.push({
type: 'node',
id: 0 - i - 1,
lat: 64 + i / SIZE,
lon: -121 - i / SIZE,
changeset: changeId
})
}
docs.push({
type: 'way',
id: 0 - i - 1,
changeset: changeId,
refs: docs.map(function (d, i) { return 0 - (i + 1) })
})
var kdocs = {}
docs.forEach(function (doc, i) {
kdocs[0 - i - 1] = doc
})
var href = base + 'changeset/' + changeId + '/upload'
var hq = hyperquest.post(href, {
headers: { 'content-type': 'text/xml' }
})
hq.once('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')
xml.root.children.forEach(function (node, i) {
var id = node.attributes.new_id
uploaded[id] = kdocs[0 - i - 1]
uploaded[id].id = id
if (node.name === 'way') {
uploaded[id].refs = uploaded[id].refs.map(function (ref) {
return kdocs[ref].id
})
}
})
}))
hq.end(`<osmChange version="1.0">
<create>
${docs.map(function (doc) {
return `<${doc.type} changeset="${doc.changeset}"
id="${doc.id}"
${doc.lat ? `lat="${doc.lat}"` : ''}
${doc.lon ? `lon="${doc.lon}"` : ''}>
${(doc.refs || []).map(function (ref) {
return `<nd ref="${ref}"/>`
}).join('\n')}
</${doc.type}>`
}).join('\n')}
</create>
</osmChange>`)
})
test('bbox', function (t) {
t.plan(8 + SIZE * 3)
var href = base + 'map?bbox=-123,63,-120,66'
var hq = hyperquest(href)
hq.once('response', function (res) {
t.equal(res.statusCode, 200)
t.equal(res.headers['content-type'].split(/\s*;\s*/)[0], 'text/xml')
})
hq.pipe(concat({ encoding: 'string' }, function (body) {
var xml = parsexml(body)
t.equal(xml.root.name, 'osm')
t.equal(xml.root.children[0].name, 'bounds')
t.deepEqual(xml.root.children[0].attributes, { maxlat: '66', maxlon: '-120', minlat: '63', minlon: '-123' }, 'bounds matches request')
t.ok(orderedTypes(xml.root.children.map(function (c) {
return c.name
})), 'ordered types')
for (var i = 1; i < xml.root.children.length; i++) {
var c = xml.root.children[i]
var node = uploaded[c.attributes.id]
if (c.name === 'node') {
t.equal(c.attributes.changeset, node.changeset)
t.equal(c.attributes.lat, String(node.lat))
t.equal(c.attributes.lon, String(node.lon))
} else if (c.name === 'way') {
t.equal(c.children.length, SIZE, 'way')
t.deepEqual(c.children.map(function (nd) {
return nd.attributes.ref
}), node.refs, 'way refs')
}
}
}))
})
test('missing bbox', function (t) {
t.plan(4)
var href = base + 'map'
var hq = hyperquest(href)
hq.once('response', function (res) {
t.equal(res.statusCode, 400)
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, 'Missing bbox query string parameter')
}))
})
test('invalid bbox', function (t) {
t.plan(4)
var href = base + 'map?bbox=invalid'
var hq = hyperquest(href)
hq.once('response', function (res) {
t.equal(res.statusCode, 400)
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, 'Invalid bbox query string parameter')
}))
})
test('out of range bbox', function (t) {
t.plan(4)
var href = base + 'map?bbox=-181,1,2,2'
var hq = hyperquest(href)
hq.once('response', function (res) {
t.equal(res.statusCode, 400)
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, 'Invalid bbox query string parameter')
}))
})
test('bbox json', function (t) {
t.plan(7 + SIZE * 3)
var href = base + 'map?bbox=-123,63,-120,66'
var hq = hyperquest(href, {headers: { 'Accept': 'application/json' }})
hq.once('response', function (res) {
t.equal(res.statusCode, 200)
t.equal(res.headers['content-type'].split(/\s*;\s*/)[0], 'application/json')
})
hq.pipe(concat({ encoding: 'string' }, function (body) {
var json = JSON.parse(body)
t.equal(json.version, 0.6)
t.deepEqual(json.bounds, { maxlat: 66, maxlon: -120, minlat: 63, minlon: -123 }, 'bounds matches request')
t.ok(orderedTypes(json.elements.map(function (c) {
return c.type
})), 'ordered types')
for (var i = 0; i < json.elements.length; i++) {
var c = json.elements[i]
var node = uploaded[c.id]
if (c.type === 'node') {
t.equal(c.changeset, node.changeset)
t.equal(c.lat, node.lat)
t.equal(c.lon, node.lon)
} else if (c.type === 'way') {
t.equal(c.nodes.length, SIZE, 'way')
t.deepEqual(c.nodes, node.refs, 'way refs')
}
}
}))
})
test('bbox json /w forks', function (t) {
t.plan(7 + SIZE * 3)
var href = base + 'map?bbox=-123,63,-120,66&forks=true'
var hq = hyperquest(href, {headers: { 'Accept': 'application/json' }})
hq.once('response', function (res) {
t.equal(res.statusCode, 200)
t.equal(res.headers['content-type'].split(/\s*;\s*/)[0], 'application/json')
})
hq.pipe(concat({ encoding: 'string' }, function (body) {
var json = JSON.parse(body)
t.equal(json.version, 0.6)
t.deepEqual(json.bounds, { maxlat: 66, maxlon: -120, minlat: 63, minlon: -123 }, 'bounds matches request')
t.ok(orderedTypes(json.elements.map(function (c) {
return c.type
})), 'ordered types')
for (var i = 0; i < json.elements.length; i++) {
var c = json.elements[i]
var node = uploaded[c.id]
if (c.type === 'node') {
t.equal(c.changeset, node.changeset)
t.equal(c.lat, node.lat)
t.equal(c.lon, node.lon)
} else if (c.type === 'way') {
t.equal(c.nodes.length, SIZE, 'way')
t.deepEqual(c.nodes, node.refs, 'way refs')
}
}
}))
})
test('bbox.js: teardown server', function (t) {
server.cleanup(function () {
t.end()
})
})
function orderedTypes (types) {
var order = { bounds: 0, node: 0, way: 1, relation: 2 }
for (var i = 1; i < types.length; i++) {
if (order[types[i - 1]] > order[types[i]]) return false
}
return true
}