UNPKG

9.72 kBJavaScriptView Raw
1var test = require('tape')
2var contentType = require('content-type')
3var parsexml = require('xml-parser')
4var hyperquest = require('hyperquest')
5var concat = require('concat-stream')
6var isISODate = require('isostring')
7
8var createServer = require('./lib/test_server.js')
9
10var base, server, changeId
11
12test('changeset_upload.js: setup server', function (t) {
13 createServer(function (d) {
14 base = d.base
15 server = d.server
16 t.end()
17 })
18})
19
20test('create changeset upload', function (t) {
21 t.plan(4)
22 var href = base + 'changeset/create'
23 var hq = hyperquest.put(href, {
24 headers: { 'content-type': 'text/xml' }
25 })
26 hq.once('response', function (res) {
27 t.equal(res.statusCode, 200, 'create 200 ok')
28 var contentObj = contentType.parse(res)
29 t.equal(contentObj.type, 'text/plain', 'media type correct')
30 t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
31 })
32 hq.pipe(concat({ encoding: 'string' }, function (body) {
33 changeId = body
34 t.ok(/^[0-9A-Fa-f]+$/.test(changeId), 'expected changeset id response')
35 }))
36 hq.end(`<osm>
37 <changeset>
38 <tag k="comment" v="wow"/>
39 </changeset>
40 </osm>`)
41})
42
43var ids = {}
44var versions = {}
45test('add docs to changeset upload', function (t) {
46 t.plan(8)
47
48 var href = base + 'changeset/' + changeId + '/upload'
49 var hq = hyperquest.post(href, {
50 headers: { 'content-type': 'text/xml' }
51 })
52 hq.on('response', function (res) {
53 t.equal(res.statusCode, 200)
54 var contentObj = contentType.parse(res)
55 t.equal(contentObj.type, 'text/xml', 'media type correct')
56 t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
57 })
58 hq.pipe(concat({ encoding: 'string' }, function (body) {
59 var xml = parsexml(body)
60 t.equal(xml.root.name, 'diffResult')
61 t.deepEqual(xml.root.children.map(function (c) {
62 return c.attributes.old_id
63 }).sort(), ['-1', '-2', '-3'])
64 xml.root.children.forEach(function (c) {
65 ids[c.attributes.old_id] = c.attributes.new_id
66 t.notEqual(c.attributes.old_id, c.attributes.new_id,
67 'placeholder id should not equal new id')
68 versions[c.attributes.old_id] = c.attributes.new_version
69 })
70 }))
71 hq.end(`<osmChange version="1.0" generator="acme osm editor">
72 <create>
73 <node id="-1" changeset="${changeId}" lat="64.5" lon="-121.5"/>
74 <node id="-2" changeset="${changeId}" lat="63.9" lon="-120.9"/>
75 <way id="-3" changeset="${changeId}">
76 <nd ref="-1"/>
77 <nd ref="-2"/>
78 </way>
79 </create>
80 </osmChange>`)
81})
82
83test('get osmchange doc from upload', function (t) {
84 t.plan(7)
85 var expected = [
86 {
87 name: 'node',
88 attributes: {
89 changeset: changeId,
90 id: ids['-1'],
91 version: versions['-1'],
92 lat: '64.5',
93 lon: '-121.5'
94 },
95 children: []
96 },
97 {
98 name: 'node',
99 attributes: {
100 changeset: changeId,
101 id: ids['-2'],
102 version: versions['-2'],
103 lat: '63.9',
104 lon: '-120.9'
105 },
106 children: []
107 },
108 {
109 name: 'way',
110 attributes: {
111 changeset: changeId,
112 id: ids['-3'],
113 version: versions['-3']
114 },
115 content: '',
116 children: [
117 {
118 name: 'nd',
119 attributes: { ref: ids['-2'] },
120 children: []
121 },
122 {
123 name: 'nd',
124 attributes: { ref: ids['-1'] },
125 children: []
126 }
127 ].sort(cmpref)
128 }
129 ].sort(cmpch)
130 var href = base + 'changeset/' + changeId + '/download'
131 var hq = hyperquest(href, {
132 headers: { 'content-type': 'text/xml' }
133 })
134 hq.pipe(concat({ encoding: 'string' }, function (body) {
135 var xml = parsexml(body)
136 t.equal(xml.root.name, 'osmChange')
137 t.equal(xml.root.children.length, 1)
138 t.equal(xml.root.children[0].name, 'create')
139 xml.root.children[0].children.sort(cmpch)
140 xml.root.children[0].children.forEach(function (c) {
141 c.children.sort(cmpref)
142 })
143 xml.root.children[0].children.forEach(function (c) {
144 t.true(isISODate(c.attributes.timestamp))
145 delete c.attributes.timestamp
146 })
147 t.deepEqual(xml.root.children[0].children, expected)
148 }))
149})
150
151test('close changeset', function (t) {
152 t.plan(2)
153 var href = base + 'changeset/' + changeId + '/close'
154 var hq = hyperquest.put(href)
155 hq.once('response', function (res) {
156 t.equal(res.statusCode, 200, 'create 200 ok')
157 })
158 hq.pipe(concat({ encoding: 'string' }, function (body) {
159 t.equal(body, '', 'empty response')
160 }))
161 hq.end()
162})
163
164test('close already closed changeset', function (t) {
165 t.plan(4)
166 var href = base + 'changeset/' + changeId + '/close'
167 var hq = hyperquest.put(href)
168 hq.once('response', function (res) {
169 t.equal(res.statusCode, 409, 'expected conflict code')
170 var contentObj = contentType.parse(res)
171 t.equal(contentObj.type, 'text/plain', 'media type correct')
172 t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
173 })
174 hq.pipe(concat({ encoding: 'string' }, function (body) {
175 t.equal(
176 body.trim().replace(/closed at.*/, 'closed at'),
177 'The changeset ' + changeId + ' was closed at',
178 'already closed message'
179 )
180 }))
181 hq.end()
182})
183
184test('upload to closed changeset', function (t) {
185 t.plan(4)
186 var href = base + 'changeset/' + changeId + '/upload'
187 var hq = hyperquest.post(href, {
188 headers: { 'content-type': 'text/xml' }
189 })
190 hq.on('response', function (res) {
191 t.equal(res.statusCode, 409, 'expected conflict code')
192 var contentObj = contentType.parse(res)
193 t.equal(contentObj.type, 'text/plain', 'media type correct')
194 t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
195 })
196 hq.pipe(concat({ encoding: 'string' }, function (body) {
197 t.equal(
198 body.trim().replace(/closed at.*/, 'closed at'),
199 'The changeset ' + changeId + ' was closed at',
200 'already closed message'
201 )
202 }))
203 hq.end(`<osmChange version="1.0" generator="acme osm editor">
204 <create>
205 <node id="-1" changeset="${changeId}" lat="64.5" lon="-121.5"/>
206 <node id="-2" changeset="${changeId}" lat="63.9" lon="-120.9"/>
207 <way id="-3" changeset="${changeId}">
208 <nd ref="-1"/>
209 <nd ref="-2"/>
210 </way>
211 </create>
212 </osmChange>`)
213})
214
215var secondChangeId
216test('create second changeset', function (t) {
217 t.plan(4)
218 var href = base + 'changeset/create'
219 var hq = hyperquest.put(href, {
220 headers: { 'content-type': 'text/xml' }
221 })
222 hq.once('response', function (res) {
223 t.equal(res.statusCode, 200, 'create 200 ok')
224 var contentObj = contentType.parse(res)
225 t.equal(contentObj.type, 'text/plain', 'media type correct')
226 t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
227 })
228 hq.pipe(concat({ encoding: 'string' }, function (body) {
229 secondChangeId = body
230 t.ok(/^[0-9A-Fa-f]+$/.test(secondChangeId), 'expected changeset id response')
231 }))
232 hq.end(`<osm>
233 <changeset>
234 <tag k="comment" v="second"/>
235 </changeset>
236 </osm>`)
237})
238
239test('second changeset upload', function (t) {
240 t.plan(13)
241 var href = base + 'changeset/' + secondChangeId + '/upload'
242 var hq = hyperquest.post(href, {
243 headers: { 'content-type': 'text/xml' }
244 })
245 hq.on('response', function (res) {
246 t.equal(res.statusCode, 200)
247 var contentObj = contentType.parse(res)
248 t.equal(contentObj.type, 'text/xml', 'media type correct')
249 t.equal(contentObj.parameters.charset.toLowerCase(), 'utf-8', 'charset correct')
250 })
251 var oldv, newv
252 hq.pipe(concat({ encoding: 'string' }, function (body) {
253 var xml = parsexml(body)
254 t.equal(xml.root.name, 'diffResult')
255 t.deepEqual(xml.root.children.map(function (c) {
256 return c.attributes.old_id
257 }).sort(), [ids['-1']])
258
259 oldv = versions['-1']
260 newv = xml.root.children[0].attributes.new_version
261 hyperquest.get(base + 'node/' + ids['-1'] + '/' + newv)
262 .on('response', function (res) {
263 t.equal(res.statusCode, 200)
264 })
265 .pipe(concat({ encoding: 'string' }, onnew))
266 hyperquest.get(base + 'node/' + ids['-1'] + '/' + oldv)
267 .on('response', function (res) {
268 t.equal(res.statusCode, 200)
269 })
270 .pipe(concat({ encoding: 'string' }, onold))
271 }))
272 hq.end(`<osmChange version="1.0" generator="acme osm editor">
273 <modify>
274 <node id="${ids['-1']}" changeset="${secondChangeId}" lat="111" lon="222"/>
275 </modify>
276 </osmChange>`)
277
278 function onnew (body) {
279 var xml = parsexml(body)
280 t.equal(xml.root.name, 'osm')
281 t.true(isISODate(xml.root.children[0].attributes.timestamp))
282 delete xml.root.children[0].attributes.timestamp
283 t.deepEqual(xml.root.children, [
284 {
285 name: 'node',
286 attributes: {
287 changeset: secondChangeId,
288 lat: '111',
289 lon: '222',
290 id: ids['-1'],
291 version: newv
292 },
293 children: []
294 }
295 ])
296 }
297 function onold (body) {
298 var xml = parsexml(body)
299 t.equal(xml.root.name, 'osm')
300 t.true(isISODate(xml.root.children[0].attributes.timestamp))
301 delete xml.root.children[0].attributes.timestamp
302 t.deepEqual(xml.root.children, [
303 {
304 name: 'node',
305 attributes: {
306 changeset: changeId,
307 lat: '64.5',
308 lon: '-121.5',
309 id: ids['-1'],
310 version: oldv
311 },
312 children: []
313 }
314 ])
315 }
316})
317
318test('changeset_upload.js: teardown server', function (t) {
319 server.cleanup(function () {
320 t.end()
321 })
322})
323
324function cmpch (a, b) {
325 return a.attributes.id < b.attributes.id ? -1 : 1
326}
327
328function cmpref (a, b) {
329 return a.attributes.ref < b.attributes.ref ? -1 : 1
330}