]> git.openstreetmap.org Git - rails.git/blob - test/controllers/api/amf_controller_test.rb
Remove travis-ci support
[rails.git] / test / controllers / api / amf_controller_test.rb
1 require "test_helper"
2
3 module Api
4   class AmfControllerTest < ActionDispatch::IntegrationTest
5     include Potlatch
6
7     ##
8     # test all routes which lead to this controller
9     def test_routes
10       assert_routing(
11         { :path => "/api/0.6/amf/read", :method => :post },
12         { :controller => "api/amf", :action => "amf_read" }
13       )
14       assert_routing(
15         { :path => "/api/0.6/amf/write", :method => :post },
16         { :controller => "api/amf", :action => "amf_write" }
17       )
18     end
19
20     def test_getpresets
21       user_en_de = create(:user, :languages => %w[en de])
22       user_de = create(:user, :languages => %w[de])
23       [user_en_de, user_de].each do |user|
24         post amf_read_path, amf_content("getpresets", "/1", ["#{user.email}:test", ""])
25         assert_response :success
26         amf_parse_response
27         presets = amf_result("/1")
28
29         assert_equal 15, presets.length
30         assert_equal POTLATCH_PRESETS[0], presets[0]
31         assert_equal POTLATCH_PRESETS[1], presets[1]
32         assert_equal POTLATCH_PRESETS[2], presets[2]
33         assert_equal POTLATCH_PRESETS[3], presets[3]
34         assert_equal POTLATCH_PRESETS[4], presets[4]
35         assert_equal POTLATCH_PRESETS[5], presets[5]
36         assert_equal POTLATCH_PRESETS[6], presets[6]
37         assert_equal POTLATCH_PRESETS[7], presets[7]
38         assert_equal POTLATCH_PRESETS[8], presets[8]
39         assert_equal POTLATCH_PRESETS[9], presets[9]
40         assert_equal POTLATCH_PRESETS[10], presets[10]
41         assert_equal POTLATCH_PRESETS[12], presets[12]
42         assert_equal user.languages.first, presets[13]["__potlatch_locale"]
43       end
44     end
45
46     def test_getway
47       # check a visible way
48       way = create(:way_with_nodes, :nodes_count => 1)
49       node = way.nodes.first
50       user = way.changeset.user
51
52       post amf_read_path, amf_content("getway", "/1", [way.id])
53       assert_response :success
54       amf_parse_response
55       result = amf_result("/1")
56       assert_equal 0, result[0]
57       assert_equal "", result[1]
58       assert_equal way.id, result[2]
59       assert_equal 1, result[3].length
60       assert_equal node.id, result[3][0][2]
61       assert_equal way.version, result[5]
62       assert_equal user.id, result[6]
63     end
64
65     def test_getway_invisible
66       # check an invisible way
67       id = create(:way, :deleted).id
68
69       post amf_read_path, amf_content("getway", "/1", [id])
70       assert_response :success
71       amf_parse_response
72       result = amf_result("/1")
73       assert_equal(-4, result[0])
74       assert_equal "way", result[1]
75       assert_equal id, result[2]
76       assert(result[3].nil? && result[4].nil? && result[5].nil? && result[6].nil?)
77     end
78
79     def test_getway_with_versions
80       # check a way with multiple versions
81       way = create(:way, :with_history, :version => 4)
82       create(:way_node, :way => way)
83       node = way.nodes.first
84       user = way.changeset.user
85
86       post amf_read_path, amf_content("getway", "/1", [way.id])
87       assert_response :success
88       amf_parse_response
89       result = amf_result("/1")
90       assert_equal 0, result[0]
91       assert_equal "", result[1]
92       assert_equal way.id, result[2]
93       assert_equal 1, result[3].length
94       assert_equal node.id, result[3][0][2]
95       assert_equal way.version, result[5]
96       assert_equal user.id, result[6]
97     end
98
99     def test_getway_with_duplicate_nodes
100       # check a way with duplicate nodes
101       way = create(:way)
102       node = create(:node)
103       create(:way_node, :way => way, :node => node, :sequence_id => 1)
104       create(:way_node, :way => way, :node => node, :sequence_id => 2)
105       user = way.changeset.user
106
107       post amf_read_path, amf_content("getway", "/1", [way.id])
108       assert_response :success
109       amf_parse_response
110       result = amf_result("/1")
111       assert_equal 0, result[0]
112       assert_equal "", result[1]
113       assert_equal way.id, result[2]
114       assert_equal 2, result[3].length
115       assert_equal node.id, result[3][0][2]
116       assert_equal node.id, result[3][1][2]
117       assert_equal way.version, result[5]
118       assert_equal user.id, result[6]
119     end
120
121     def test_getway_with_multiple_nodes
122       # check a way with multiple nodes
123       way = create(:way_with_nodes, :nodes_count => 3)
124       a = way.nodes[0].id
125       b = way.nodes[1].id
126       c = way.nodes[2].id
127       user = way.changeset.user
128
129       post amf_read_path, amf_content("getway", "/1", [way.id])
130       assert_response :success
131       amf_parse_response
132       result = amf_result("/1")
133       assert_equal 0, result[0]
134       assert_equal "", result[1]
135       assert_equal way.id, result[2]
136       assert_equal 3, result[3].length
137       assert_equal a, result[3][0][2]
138       assert_equal b, result[3][1][2]
139       assert_equal c, result[3][2][2]
140       assert_equal way.version, result[5]
141       assert_equal user.id, result[6]
142     end
143
144     def test_getway_nonexistent
145       # check chat a non-existent way is not returned
146       post amf_read_path, amf_content("getway", "/1", [0])
147       assert_response :success
148       amf_parse_response
149       way = amf_result("/1")
150       assert_equal(-4, way[0])
151       assert_equal "way", way[1]
152       assert_equal 0, way[2]
153       assert(way[3].nil?) && way[4].nil? && way[5].nil? && way[6].nil?
154     end
155
156     def test_whichways
157       node = create(:node, :lat => 3.0, :lon => 3.0)
158       way = create(:way)
159       deleted_way = create(:way, :deleted)
160       create(:way_node, :way => way, :node => node)
161       create(:way_node, :way => deleted_way, :node => node)
162       create(:way_tag, :way => way)
163
164       minlon = node.lon - 0.1
165       minlat = node.lat - 0.1
166       maxlon = node.lon + 0.1
167       maxlat = node.lat + 0.1
168       post amf_read_path, amf_content("whichways", "/1", [minlon, minlat, maxlon, maxlat])
169       assert_response :success
170       amf_parse_response
171
172       # check contents of message
173       map = amf_result "/1"
174       assert_equal 0, map[0], "map error code should be 0"
175       assert_equal "", map[1], "map error text should be empty"
176
177       # check the formatting of the message
178       assert_equal 5, map.length, "map should have length 5"
179       assert_equal Array, map[2].class, 'map "ways" element should be an array'
180       assert_equal Array, map[3].class, 'map "nodes" element should be an array'
181       assert_equal Array, map[4].class, 'map "relations" element should be an array'
182       map[2].each do |w|
183         assert_equal 2, w.length, "way should be (id, version) pair"
184         assert_equal w[0], w[0].floor, "way ID should be an integer"
185         assert_equal w[1], w[1].floor, "way version should be an integer"
186       end
187
188       map[3].each do |n|
189         assert_equal 5, w.length, "node should be (id, lat, lon, [tags], version) tuple"
190         assert_equal n[0], n[0].floor, "node ID should be an integer"
191         assert n[1] >= minlat - 0.01, "node lat should be greater than min"
192         assert n[1] <= maxlat - 0.01, "node lat should be less than max"
193         assert n[2] >= minlon - 0.01, "node lon should be greater than min"
194         assert n[2] <= maxlon - 0.01, "node lon should be less than max"
195         assert_equal Array, a[3].class, "node tags should be array"
196         assert_equal n[4], n[4].floor, "node version should be an integer"
197       end
198
199       map[4].each do |r|
200         assert_equal 2, r.length, "relation should be (id, version) pair"
201         assert_equal r[0], r[0].floor, "relation ID should be an integer"
202         assert_equal r[1], r[1].floor, "relation version should be an integer"
203       end
204
205       # TODO: looks like amf_controller changed since this test was written
206       # so someone who knows what they're doing should check this!
207       ways = map[2].collect { |x| x[0] }
208       assert_includes ways, way.id,
209                       "map should include used way"
210       assert_not ways.include?(deleted_way.id),
211                  "map should not include deleted way"
212     end
213
214     ##
215     # checks that too-large a bounding box will not be served.
216     def test_whichways_toobig
217       bbox = [-0.1, -0.1, 1.1, 1.1]
218       check_bboxes_are_bad [bbox] do |map, _bbox|
219         assert_boundary_error map, " The server said: The maximum bbox size is 0.25, and your request was too large. Either request a smaller area, or use planet.osm"
220       end
221     end
222
223     ##
224     # checks that an invalid bounding box will not be served. in this case
225     # one with max < min latitudes.
226     #
227     # NOTE: the controller expands the bbox by 0.01 in each direction!
228     def test_whichways_badlat
229       bboxes = [[0, 0.1, 0.1, 0], [-0.1, 80, 0.1, 70], [0.24, 54.35, 0.25, 54.33]]
230       check_bboxes_are_bad bboxes do |map, bbox|
231         assert_boundary_error map, " The server said: The minimum latitude must be less than the maximum latitude, but it wasn't", bbox.inspect
232       end
233     end
234
235     ##
236     # same as test_whichways_badlat, but for longitudes
237     #
238     # NOTE: the controller expands the bbox by 0.01 in each direction!
239     def test_whichways_badlon
240       bboxes = [[80, -0.1, 70, 0.1], [54.35, 0.24, 54.33, 0.25]]
241       check_bboxes_are_bad bboxes do |map, bbox|
242         assert_boundary_error map, " The server said: The minimum longitude must be less than the maximum longitude, but it wasn't", bbox.inspect
243       end
244     end
245
246     def test_whichways_deleted
247       node = create(:node, :with_history, :lat => 24.0, :lon => 24.0)
248       way = create(:way, :with_history)
249       way_v1 = way.old_ways.find_by(:version => 1)
250       deleted_way = create(:way, :with_history, :deleted)
251       deleted_way_v1 = deleted_way.old_ways.find_by(:version => 1)
252       create(:way_node, :way => way, :node => node)
253       create(:way_node, :way => deleted_way, :node => node)
254       create(:old_way_node, :old_way => way_v1, :node => node)
255       create(:old_way_node, :old_way => deleted_way_v1, :node => node)
256
257       minlon = node.lon - 0.1
258       minlat = node.lat - 0.1
259       maxlon = node.lon + 0.1
260       maxlat = node.lat + 0.1
261       post amf_read_path, amf_content("whichways_deleted", "/1", [minlon, minlat, maxlon, maxlat])
262       assert_response :success
263       amf_parse_response
264
265       # check contents of message
266       map = amf_result "/1"
267       assert_equal 0, map[0], "first map element should be 0"
268       assert_equal "", map[1], "second map element should be an empty string"
269       assert_equal Array, map[2].class, "third map element should be an array"
270       # TODO: looks like amf_controller changed since this test was written
271       # so someone who knows what they're doing should check this!
272       assert_not map[2].include?(way.id),
273                  "map should not include visible way"
274       assert_includes map[2], deleted_way.id,
275                       "map should include deleted way"
276     end
277
278     def test_whichways_deleted_toobig
279       bbox = [-0.1, -0.1, 1.1, 1.1]
280       post amf_read_path, amf_content("whichways_deleted", "/1", bbox)
281       assert_response :success
282       amf_parse_response
283
284       map = amf_result "/1"
285       assert_deleted_boundary_error map, " The server said: The maximum bbox size is 0.25, and your request was too large. Either request a smaller area, or use planet.osm"
286     end
287
288     def test_getrelation
289       id = create(:relation).id
290       post amf_read_path, amf_content("getrelation", "/1", [id])
291       assert_response :success
292       amf_parse_response
293       rel = amf_result("/1")
294       assert_equal(0, rel[0])
295       assert_equal rel[2], id
296     end
297
298     def test_getrelation_invisible
299       id = create(:relation, :deleted).id
300       post amf_read_path, amf_content("getrelation", "/1", [id])
301       assert_response :success
302       amf_parse_response
303       rel = amf_result("/1")
304       assert_equal(-4, rel[0])
305       assert_equal("relation", rel[1])
306       assert_equal rel[2], id
307       assert(rel[3].nil?) && rel[4].nil?
308     end
309
310     def test_getrelation_nonexistent
311       id = 0
312       post amf_read_path, amf_content("getrelation", "/1", [id])
313       assert_response :success
314       amf_parse_response
315       rel = amf_result("/1")
316       assert_equal(-4, rel[0])
317       assert_equal("relation", rel[1])
318       assert_equal rel[2], id
319       assert(rel[3].nil?) && rel[4].nil?
320     end
321
322     def test_getway_old
323       latest = create(:way, :version => 2)
324       v1 = create(:old_way, :current_way => latest, :version => 1, :timestamp => Time.now.utc - 2.minutes)
325       _v2 = create(:old_way, :current_way => latest, :version => 2, :timestamp => Time.now.utc - 1.minute)
326
327       # try to get the last visible version (specified by <0) (should be current version)
328       # NOTE: looks from the API changes that this now expects a timestamp
329       # instead of a version number...
330       # try to get version 1
331       { latest.id => "",
332         v1.way_id => (v1.timestamp + 1).strftime("%d %b %Y, %H:%M:%S") }.each do |id, t|
333         post amf_read_path, amf_content("getway_old", "/1", [id, t])
334         assert_response :success
335         amf_parse_response
336         returned_way = amf_result("/1")
337         assert_equal 0, returned_way[0]
338         assert_equal id, returned_way[2]
339         # API returns the *latest* version, even for old ways...
340         assert_equal latest.version, returned_way[5]
341       end
342     end
343
344     ##
345     # test that the server doesn't fall over when rubbish is passed
346     # into the method args.
347     def test_getway_old_invalid
348       way_id = create(:way, :with_history, :version => 2).id
349       { "foo" => "bar",
350         way_id => "not a date",
351         way_id => "2009-03-25 00:00:00",                   # <- wrong format
352         way_id => "0 Jan 2009 00:00:00",                   # <- invalid date
353         -1 => "1 Jan 2009 00:00:00" }.each do |id, t| # <- invalid
354         post amf_read_path, amf_content("getway_old", "/1", [id, t])
355         assert_response :success
356         amf_parse_response
357         returned_way = amf_result("/1")
358         assert_equal(-1, returned_way[0])
359         assert returned_way[3].nil?
360         assert returned_way[4].nil?
361         assert returned_way[5].nil?
362       end
363     end
364
365     def test_getway_old_nonexistent
366       # try to get the last version-10 (shoudn't exist)
367       way = create(:way, :with_history, :version => 2)
368       v1 = way.old_ways.find_by(:version => 1)
369       # try to get last visible version of non-existent way
370       # try to get specific version of non-existent way
371       [[0, ""],
372        [0, "1 Jan 1970, 00:00:00"],
373        [v1.way_id, (v1.timestamp - 10).strftime("%d %b %Y, %H:%M:%S")]].each do |id, t|
374         post amf_read_path, amf_content("getway_old", "/1", [id, t])
375         assert_response :success
376         amf_parse_response
377         returned_way = amf_result("/1")
378         assert_equal(-1, returned_way[0])
379         assert returned_way[3].nil?
380         assert returned_way[4].nil?
381         assert returned_way[5].nil?
382       end
383     end
384
385     def test_getway_old_invisible
386       way = create(:way, :deleted, :with_history, :version => 1)
387       v1 = way.old_ways.find_by(:version => 1)
388       # try to get deleted version
389       [[v1.way_id, (v1.timestamp + 10).strftime("%d %b %Y, %H:%M:%S")]].each do |id, t|
390         post amf_read_path, amf_content("getway_old", "/1", [id, t])
391         assert_response :success
392         amf_parse_response
393         returned_way = amf_result("/1")
394         assert_equal(-1, returned_way[0])
395         assert returned_way[3].nil?
396         assert returned_way[4].nil?
397         assert returned_way[5].nil?
398       end
399     end
400
401     def test_getway_history
402       latest = create(:way, :version => 2)
403       oldest = create(:old_way, :current_way => latest, :version => 1, :timestamp => latest.timestamp - 2.minutes)
404       create(:old_way, :current_way => latest, :version => 2, :timestamp => latest.timestamp)
405
406       post amf_read_path, amf_content("getway_history", "/1", [latest.id])
407       assert_response :success
408       amf_parse_response
409       history = amf_result("/1")
410
411       # ['way',wayid,history]
412       assert_equal "way", history[0]
413       assert_equal latest.id, history[1]
414       # We use dates rather than version numbers here, because you might
415       # have moved a node within a way (i.e. way version not incremented).
416       # The timestamp is +1 because we say "give me the revision of 15:33:02",
417       # but that might actually include changes at 15:33:02.457.
418       assert_equal (latest.timestamp + 1).strftime("%d %b %Y, %H:%M:%S"), history[2].first[0]
419       assert_equal (oldest.timestamp + 1).strftime("%d %b %Y, %H:%M:%S"), history[2].last[0]
420     end
421
422     def test_getway_history_nonexistent
423       post amf_read_path, amf_content("getway_history", "/1", [0])
424       assert_response :success
425       amf_parse_response
426       history = amf_result("/1")
427
428       # ['way',wayid,history]
429       assert_equal("way", history[0])
430       assert_equal(0, history[1])
431       assert_empty history[2]
432     end
433
434     def test_getnode_history
435       node = create(:node, :version => 2)
436       node_v1 = create(:old_node, :current_node => node, :version => 1, :timestamp => 3.days.ago)
437       _node_v2 = create(:old_node, :current_node => node, :version => 2, :timestamp => 2.days.ago)
438       node_v3 = create(:old_node, :current_node => node, :version => 3, :timestamp => 1.day.ago)
439
440       post amf_read_path, amf_content("getnode_history", "/1", [node.id])
441       assert_response :success
442       amf_parse_response
443       history = amf_result("/1")
444
445       # ['node',nodeid,history]
446       # note that (as per getway_history) we actually round up
447       # to the next second
448       assert_equal("node", history[0], 'first element should be "node"')
449       assert_equal history[1], node.id,
450                    "second element should be the input node ID"
451       assert_equal history[2].first[0],
452                    (node_v3.timestamp + 1).strftime("%d %b %Y, %H:%M:%S"),
453                    "first element in third element (array) should be the latest version"
454       assert_equal history[2].last[0],
455                    (node_v1.timestamp + 1).strftime("%d %b %Y, %H:%M:%S"),
456                    "last element in third element (array) should be the initial version"
457     end
458
459     def test_getnode_history_nonexistent
460       post amf_read_path, amf_content("getnode_history", "/1", [0])
461       assert_response :success
462       amf_parse_response
463       history = amf_result("/1")
464
465       # ['node',nodeid,history]
466       assert_equal("node", history[0])
467       assert_equal(0, history[1])
468       assert_empty history[2]
469     end
470
471     def test_findgpx_bad_user
472       post amf_read_path, amf_content("findgpx", "/1", [1, "test@example.com:wrong"])
473       assert_response :success
474       amf_parse_response
475       result = amf_result("/1")
476
477       assert_equal 2, result.length
478       assert_equal(-1, result[0])
479       assert_match(/must be logged in/, result[1])
480
481       blocked_user = create(:user)
482       create(:user_block, :user => blocked_user)
483       post amf_read_path, amf_content("findgpx", "/1", [1, "#{blocked_user.email}:test"])
484       assert_response :success
485       amf_parse_response
486       result = amf_result("/1")
487
488       assert_equal 2, result.length
489       assert_equal(-1, result[0])
490       assert_match(/access to the API has been blocked/, result[1])
491     end
492
493     def test_findgpx_by_id
494       user = create(:user)
495       trace = create(:trace, :visibility => "private", :user => user)
496
497       post amf_read_path, amf_content("findgpx", "/1", [trace.id, "#{user.email}:test"])
498       assert_response :success
499       amf_parse_response
500       result = amf_result("/1")
501
502       assert_equal 3, result.length
503       assert_equal 0, result[0]
504       assert_equal "", result[1]
505       traces = result[2]
506       assert_equal 1, traces.length
507       assert_equal 3, traces[0].length
508       assert_equal trace.id, traces[0][0]
509       assert_equal trace.name, traces[0][1]
510       assert_equal trace.description, traces[0][2]
511     end
512
513     def test_findgpx_by_name
514       user = create(:user)
515
516       post amf_read_path, amf_content("findgpx", "/1", ["Trace", "#{user.email}:test"])
517       assert_response :success
518       amf_parse_response
519       result = amf_result("/1")
520
521       # find by name fails as it uses mysql text search syntax...
522       assert_equal 2, result.length
523       assert_equal(-2, result[0])
524     end
525
526     def test_findrelations_by_id
527       relation = create(:relation, :version => 4)
528
529       post amf_read_path, amf_content("findrelations", "/1", [relation.id])
530       assert_response :success
531       amf_parse_response
532       result = amf_result("/1")
533
534       assert_equal 1, result.length
535       assert_equal 4, result[0].length
536       assert_equal relation.id, result[0][0]
537       assert_equal relation.tags, result[0][1]
538       assert_equal relation.members, result[0][2]
539       assert_equal relation.version, result[0][3]
540
541       post amf_read_path, amf_content("findrelations", "/1", [999999])
542       assert_response :success
543       amf_parse_response
544       result = amf_result("/1")
545
546       assert_equal 0, result.length
547     end
548
549     def test_findrelations_by_tags
550       visible_relation = create(:relation)
551       create(:relation_tag, :relation => visible_relation, :k => "test", :v => "yes")
552       used_relation = create(:relation)
553       super_relation = create(:relation)
554       create(:relation_member, :relation => super_relation, :member => used_relation)
555       create(:relation_tag, :relation => used_relation, :k => "test", :v => "yes")
556       create(:relation_tag, :relation => used_relation, :k => "name", :v => "Test Relation")
557
558       post amf_read_path, amf_content("findrelations", "/1", ["yes"])
559       assert_response :success
560       amf_parse_response
561       result = amf_result("/1").sort
562
563       assert_equal 2, result.length
564       assert_equal 4, result[0].length
565       assert_equal visible_relation.id, result[0][0]
566       assert_equal visible_relation.tags, result[0][1]
567       assert_equal visible_relation.members, result[0][2]
568       assert_equal visible_relation.version, result[0][3]
569       assert_equal 4, result[1].length
570       assert_equal used_relation.id, result[1][0]
571       assert_equal used_relation.tags, result[1][1]
572       assert_equal used_relation.members, result[1][2]
573       assert_equal used_relation.version, result[1][3]
574
575       post amf_read_path, amf_content("findrelations", "/1", ["no"])
576       assert_response :success
577       amf_parse_response
578       result = amf_result("/1").sort
579
580       assert_equal 0, result.length
581     end
582
583     def test_getpoi_without_timestamp
584       node = create(:node, :with_history, :version => 4)
585       create(:node_tag, :node => node)
586
587       post amf_read_path, amf_content("getpoi", "/1", [node.id, ""])
588       assert_response :success
589       amf_parse_response
590       result = amf_result("/1")
591
592       assert_equal 7, result.length
593       assert_equal 0, result[0]
594       assert_equal "", result[1]
595       assert_equal node.id, result[2]
596       assert_equal node.lon, result[3]
597       assert_equal node.lat, result[4]
598       assert_equal node.tags, result[5]
599       assert_equal node.version, result[6]
600
601       post amf_read_path, amf_content("getpoi", "/1", [999999, ""])
602       assert_response :success
603       amf_parse_response
604       result = amf_result("/1")
605
606       assert_equal 3, result.length
607       assert_equal(-4, result[0])
608       assert_equal "node", result[1]
609       assert_equal 999999, result[2]
610     end
611
612     def test_getpoi_with_timestamp
613       current_node = create(:node, :with_history, :version => 4)
614       node = current_node.old_nodes.find_by(:version => 2)
615
616       # Timestamps are stored with microseconds, but xmlschema truncates them to
617       # previous whole second, causing <= comparison to fail
618       timestamp = (node.timestamp + 1.second).xmlschema
619
620       post amf_read_path, amf_content("getpoi", "/1", [node.node_id, timestamp])
621       assert_response :success
622       amf_parse_response
623       result = amf_result("/1")
624
625       assert_equal 7, result.length
626       assert_equal 0, result[0]
627       assert_equal "", result[1]
628       assert_equal node.node_id, result[2]
629       assert_equal node.lon, result[3]
630       assert_equal node.lat, result[4]
631       assert_equal node.tags, result[5]
632       assert_equal current_node.version, result[6]
633
634       post amf_read_path, amf_content("getpoi", "/1", [node.node_id, "2000-01-01T00:00:00Z"])
635       assert_response :success
636       amf_parse_response
637       result = amf_result("/1")
638
639       assert_equal 3, result.length
640       assert_equal(-4, result[0])
641       assert_equal "node", result[1]
642       assert_equal node.node_id, result[2]
643
644       post amf_read_path, amf_content("getpoi", "/1", [999999, Time.now.xmlschema])
645       assert_response :success
646       amf_parse_response
647       result = amf_result("/1")
648
649       assert_equal 3, result.length
650       assert_equal(-4, result[0])
651       assert_equal "node", result[1]
652       assert_equal 999999, result[2]
653     end
654
655     # ************************************************************
656     # AMF Write tests
657
658     # check that we can update a poi
659     def test_putpoi_update_valid
660       nd = create(:node)
661       cs_id = nd.changeset.id
662       user = nd.changeset.user
663       post amf_write_path, amf_content("putpoi", "/1", ["#{user.email}:test", cs_id, nd.version, nd.id, nd.lon, nd.lat, nd.tags, nd.visible])
664       assert_response :success
665       amf_parse_response
666       result = amf_result("/1")
667
668       assert_equal 5, result.size
669       assert_equal 0, result[0]
670       assert_equal "", result[1]
671       assert_equal nd.id, result[2]
672       assert_equal nd.id, result[3]
673       assert_equal nd.version + 1, result[4]
674
675       # Now try to update again, with a different lat/lon, using the updated version number
676       lat = nd.lat + 0.1
677       lon = nd.lon - 0.1
678       post amf_write_path, amf_content("putpoi", "/2", ["#{user.email}:test", cs_id, nd.version + 1, nd.id, lon, lat, nd.tags, nd.visible])
679       assert_response :success
680       amf_parse_response
681       result = amf_result("/2")
682
683       assert_equal 5, result.size
684       assert_equal 0, result[0]
685       assert_equal "", result[1]
686       assert_equal nd.id, result[2]
687       assert_equal nd.id, result[3]
688       assert_equal nd.version + 2, result[4]
689     end
690
691     # Check that we can create a no valid poi
692     # Using similar method for the node controller test
693     def test_putpoi_create_valid
694       # This node has no tags
695
696       # create a node with random lat/lon
697       lat = rand(-50..49) + rand
698       lon = rand(-50..49) + rand
699
700       changeset = create(:changeset)
701       user = changeset.user
702
703       post amf_write_path, amf_content("putpoi", "/1", ["#{user.email}:test", changeset.id, nil, nil, lon, lat, {}, nil])
704       assert_response :success
705       amf_parse_response
706       result = amf_result("/1")
707
708       # check the array returned by the amf
709       assert_equal 5, result.size
710       assert_equal 0, result[0], "expected to get the status ok from the amf"
711       assert_equal 0, result[2], "The old id should be 0"
712       assert result[3].positive?, "The new id should be greater than 0"
713       assert_equal 1, result[4], "The new version should be 1"
714
715       # Finally check that the node that was saved has saved the data correctly
716       # in both the current and history tables
717       # First check the current table
718       current_node = Node.find(result[3].to_i)
719       assert_in_delta lat, current_node.lat, 0.00001, "The latitude was not retreieved correctly"
720       assert_in_delta lon, current_node.lon, 0.00001, "The longitude was not retreived correctly"
721       assert_equal 0, current_node.tags.size, "There seems to be a tag that has been added to the node"
722       assert_equal result[4], current_node.version, "The version returned, is different to the one returned by the amf"
723       # Now check the history table
724       historic_nodes = OldNode.where(:node_id => result[3])
725       assert_equal 1, historic_nodes.size, "There should only be one historic node created"
726       first_historic_node = historic_nodes.first
727       assert_in_delta lat, first_historic_node.lat, 0.00001, "The latitude was not retreived correctly"
728       assert_in_delta lon, first_historic_node.lon, 0.00001, "The longitude was not retreuved correctly"
729       assert_equal 0, first_historic_node.tags.size, "There seems to be a tag that have been attached to this node"
730       assert_equal result[4], first_historic_node.version, "The version returned, is different to the one returned by the amf"
731
732       ####
733       # This node has some tags
734
735       # create a node with random lat/lon
736       lat = rand(-50..49) + rand
737       lon = rand(-50..49) + rand
738
739       post amf_write_path, amf_content("putpoi", "/2", ["#{user.email}:test", changeset.id, nil, nil, lon, lat, { "key" => "value", "ping" => "pong" }, nil])
740       assert_response :success
741       amf_parse_response
742       result = amf_result("/2")
743
744       # check the array returned by the amf
745       assert_equal 5, result.size
746       assert_equal 0, result[0], "Expected to get the status ok in the amf"
747       assert_equal 0, result[2], "The old id should be 0"
748       assert result[3].positive?, "The new id should be greater than 0"
749       assert_equal 1, result[4], "The new version should be 1"
750
751       # Finally check that the node that was saved has saved the data correctly
752       # in both the current and history tables
753       # First check the current table
754       current_node = Node.find(result[3].to_i)
755       assert_in_delta lat, current_node.lat, 0.00001, "The latitude was not retreieved correctly"
756       assert_in_delta lon, current_node.lon, 0.00001, "The longitude was not retreived correctly"
757       assert_equal 2, current_node.tags.size, "There seems to be a tag that has been added to the node"
758       assert_equal({ "key" => "value", "ping" => "pong" }, current_node.tags, "tags are different")
759       assert_equal result[4], current_node.version, "The version returned, is different to the one returned by the amf"
760       # Now check the history table
761       historic_nodes = OldNode.where(:node_id => result[3])
762       assert_equal 1, historic_nodes.size, "There should only be one historic node created"
763       first_historic_node = historic_nodes.first
764       assert_in_delta lat, first_historic_node.lat, 0.00001, "The latitude was not retreived correctly"
765       assert_in_delta lon, first_historic_node.lon, 0.00001, "The longitude was not retreuved correctly"
766       assert_equal 2, first_historic_node.tags.size, "There seems to be a tag that have been attached to this node"
767       assert_equal({ "key" => "value", "ping" => "pong" }, first_historic_node.tags, "tags are different")
768       assert_equal result[4], first_historic_node.version, "The version returned, is different to the one returned by the amf"
769     end
770
771     # try creating a POI with rubbish in the tags
772     def test_putpoi_create_with_control_chars
773       # This node has no tags
774
775       # create a node with random lat/lon
776       lat = rand(-50..49) + rand
777       lon = rand(-50..49) + rand
778
779       changeset = create(:changeset)
780       user = changeset.user
781
782       mostly_invalid = (0..31).to_a.map(&:chr).join
783       tags = { "something" => "foo#{mostly_invalid}bar" }
784
785       post amf_write_path, amf_content("putpoi", "/1", ["#{user.email}:test", changeset.id, nil, nil, lon, lat, tags, nil])
786       assert_response :success
787       amf_parse_response
788       result = amf_result("/1")
789
790       # check the array returned by the amf
791       assert_equal 5, result.size
792       assert_equal 0, result[0], "Expected to get the status ok in the amf"
793       assert_equal 0, result[2], "The old id should be 0"
794       assert result[3].positive?, "The new id should be greater than 0"
795       assert_equal 1, result[4], "The new version should be 1"
796
797       # Finally check that the node that was saved has saved the data correctly
798       # in both the current and history tables
799       # First check the current table
800       current_node = Node.find(result[3].to_i)
801       assert_equal 1, current_node.tags.size, "There seems to be a tag that has been added to the node"
802       assert_equal({ "something" => "foo\t\n\rbar" }, current_node.tags, "tags were not fixed correctly")
803       assert_equal result[4], current_node.version, "The version returned, is different to the one returned by the amf"
804     end
805
806     # try creating a POI with rubbish in the tags
807     def test_putpoi_create_with_invalid_utf8
808       # This node has no tags
809
810       # create a node with random lat/lon
811       lat = rand(-50..49) + rand
812       lon = rand(-50..49) + rand
813
814       changeset = create(:changeset)
815       user = changeset.user
816
817       invalid = "\xc0\xc0"
818       tags = { "something" => "foo#{invalid}bar" }
819
820       post amf_write_path, amf_content("putpoi", "/1", ["#{user.email}:test", changeset.id, nil, nil, lon, lat, tags, nil])
821       assert_response :success
822       amf_parse_response
823       result = amf_result("/1")
824
825       assert_equal 2, result.size
826       assert_equal(-1, result[0], "Expected to get the status FAIL in the amf")
827       assert_equal "One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1.", result[1]
828     end
829
830     # try deleting a node
831     def test_putpoi_delete_valid
832       nd = create(:node)
833       cs_id = nd.changeset.id
834       user = nd.changeset.user
835
836       post amf_write_path, amf_content("putpoi", "/1", ["#{user.email}:test", cs_id, nd.version, nd.id, nd.lon, nd.lat, nd.tags, false])
837       assert_response :success
838       amf_parse_response
839       result = amf_result("/1")
840
841       assert_equal 5, result.size
842       assert_equal 0, result[0]
843       assert_equal "", result[1]
844       assert_equal nd.id, result[2]
845       assert_equal nd.id, result[3]
846       assert_equal nd.version + 1, result[4]
847
848       current_node = Node.find(result[3].to_i)
849       assert_not current_node.visible
850     end
851
852     # try deleting a node that is already deleted
853     def test_putpoi_delete_already_deleted
854       nd = create(:node, :deleted)
855       cs_id = nd.changeset.id
856       user = nd.changeset.user
857
858       post amf_write_path, amf_content("putpoi", "/1", ["#{user.email}:test", cs_id, nd.version, nd.id, nd.lon, nd.lat, nd.tags, false])
859       assert_response :success
860       amf_parse_response
861       result = amf_result("/1")
862
863       assert_equal 3, result.size
864       assert_equal(-4, result[0])
865       assert_equal "node", result[1]
866       assert_equal nd.id, result[2]
867     end
868
869     # try deleting a node that has never existed
870     def test_putpoi_delete_not_found
871       changeset = create(:changeset)
872       cs_id = changeset.id
873       user = changeset.user
874
875       post amf_write_path, amf_content("putpoi", "/1", ["#{user.email}:test", cs_id, 1, 999999, 0, 0, {}, false])
876       assert_response :success
877       amf_parse_response
878       result = amf_result("/1")
879
880       assert_equal 3, result.size
881       assert_equal(-4, result[0])
882       assert_equal "node", result[1]
883       assert_equal 999999, result[2]
884     end
885
886     # try setting an invalid location on a node
887     def test_putpoi_invalid_latlon
888       nd = create(:node)
889       cs_id = nd.changeset.id
890       user = nd.changeset.user
891
892       post amf_write_path, amf_content("putpoi", "/1", ["#{user.email}:test", cs_id, nd.version, nd.id, 200, 100, nd.tags, true])
893       assert_response :success
894       amf_parse_response
895       result = amf_result("/1")
896
897       assert_equal 2, result.size
898       assert_equal(-2, result[0])
899       assert_match(/Node is not in the world/, result[1])
900     end
901
902     # check that we can create a way
903     def test_putway_create_valid
904       changeset = create(:changeset)
905       cs_id = changeset.id
906       user = changeset.user
907
908       a = create(:node).id
909       b = create(:node).id
910       c = create(:node).id
911       d = create(:node).id
912       e = create(:node).id
913
914       post amf_write_path, amf_content("putway", "/1", ["#{user.email}:test", cs_id, 0, -1, [a, b, c], { "test" => "new" }, [], {}])
915       assert_response :success
916       amf_parse_response
917       result = amf_result("/1")
918       new_way_id = result[3].to_i
919
920       assert_equal 8, result.size
921       assert_equal 0, result[0]
922       assert_equal "", result[1]
923       assert_equal(-1, result[2])
924       assert_not_equal(-1, result[3])
925       assert_equal({}, result[4])
926       assert_equal 1, result[5]
927       assert_equal({}, result[6])
928       assert_equal({}, result[7])
929
930       new_way = Way.find(new_way_id)
931       assert_equal 1, new_way.version
932       assert_equal [a, b, c], new_way.nds
933       assert_equal({ "test" => "new" }, new_way.tags)
934
935       post amf_write_path, amf_content("putway", "/1", ["#{user.email}:test", cs_id, 0, -1, [b, d, e, a], { "test" => "newer" }, [], {}])
936       assert_response :success
937       amf_parse_response
938       result = amf_result("/1")
939       new_way_id = result[3].to_i
940
941       assert_equal 8, result.size
942       assert_equal 0, result[0]
943       assert_equal "", result[1]
944       assert_equal(-1, result[2])
945       assert_not_equal(-1, result[3])
946       assert_equal({}, result[4])
947       assert_equal 1, result[5]
948       assert_equal({}, result[6])
949       assert_equal({}, result[7])
950
951       new_way = Way.find(new_way_id)
952       assert_equal 1, new_way.version
953       assert_equal [b, d, e, a], new_way.nds
954       assert_equal({ "test" => "newer" }, new_way.tags)
955
956       post amf_write_path, amf_content("putway", "/1", ["#{user.email}:test", cs_id, 0, -1, [b, -1, d, e], { "test" => "newest" }, [[4.56, 12.34, -1, 0, { "test" => "new" }], [12.34, 4.56, d, 1, { "test" => "ok" }]], { a => 1 }])
957       assert_response :success
958       amf_parse_response
959       result = amf_result("/1")
960       new_way_id = result[3].to_i
961       new_node_id = result[4]["-1"].to_i
962
963       assert_equal 8, result.size
964       assert_equal 0, result[0]
965       assert_equal "", result[1]
966       assert_equal(-1, result[2])
967       assert_not_equal(-1, result[3])
968       assert_equal({ "-1" => new_node_id }, result[4])
969       assert_equal 1, result[5]
970       assert_equal({ new_node_id.to_s => 1, d.to_s => 2 }, result[6])
971       assert_equal({ a.to_s => 1 }, result[7])
972
973       new_way = Way.find(new_way_id)
974       assert_equal 1, new_way.version
975       assert_equal [b, new_node_id, d, e], new_way.nds
976       assert_equal({ "test" => "newest" }, new_way.tags)
977
978       new_node = Node.find(new_node_id)
979       assert_equal 1, new_node.version
980       assert new_node.visible
981       assert_in_delta(4.56, new_node.lon)
982       assert_in_delta(12.34, new_node.lat)
983       assert_equal({ "test" => "new" }, new_node.tags)
984
985       changed_node = Node.find(d)
986       assert_equal 2, changed_node.version
987       assert changed_node.visible
988       assert_in_delta(12.34, changed_node.lon)
989       assert_in_delta(4.56, changed_node.lat)
990       assert_equal({ "test" => "ok" }, changed_node.tags)
991
992       # node is not deleted because our other ways are using it
993       deleted_node = Node.find(a)
994       assert_equal 1, deleted_node.version
995       assert deleted_node.visible
996     end
997
998     # check that we can update a way
999     def test_putway_update_valid
1000       way = create(:way_with_nodes, :nodes_count => 3)
1001       cs_id = way.changeset.id
1002       user = way.changeset.user
1003
1004       assert_not_equal({ "test" => "ok" }, way.tags)
1005       post amf_write_path, amf_content("putway", "/1", ["#{user.email}:test", cs_id, way.version, way.id, way.nds, { "test" => "ok" }, [], {}])
1006       assert_response :success
1007       amf_parse_response
1008       result = amf_result("/1")
1009
1010       assert_equal 8, result.size
1011       assert_equal 0, result[0]
1012       assert_equal "", result[1]
1013       assert_equal way.id, result[2]
1014       assert_equal way.id, result[3]
1015       assert_equal({}, result[4])
1016       assert_equal way.version + 1, result[5]
1017       assert_equal({}, result[6])
1018       assert_equal({}, result[7])
1019
1020       new_way = Way.find(way.id)
1021       assert_equal way.version + 1, new_way.version
1022       assert_equal way.nds, new_way.nds
1023       assert_equal({ "test" => "ok" }, new_way.tags)
1024
1025       # Test changing the nodes in the way
1026       a = create(:node).id
1027       b = create(:node).id
1028       c = create(:node).id
1029       d = create(:node).id
1030
1031       assert_not_equal [a, b, c, d], way.nds
1032       post amf_write_path, amf_content("putway", "/1", ["#{user.email}:test", cs_id, way.version + 1, way.id, [a, b, c, d], way.tags, [], {}])
1033       assert_response :success
1034       amf_parse_response
1035       result = amf_result("/1")
1036
1037       assert_equal 8, result.size
1038       assert_equal 0, result[0]
1039       assert_equal "", result[1]
1040       assert_equal way.id, result[2]
1041       assert_equal way.id, result[3]
1042       assert_equal({}, result[4])
1043       assert_equal way.version + 2, result[5]
1044       assert_equal({}, result[6])
1045       assert_equal({}, result[7])
1046
1047       new_way = Way.find(way.id)
1048       assert_equal way.version + 2, new_way.version
1049       assert_equal [a, b, c, d], new_way.nds
1050       assert_equal way.tags, new_way.tags
1051
1052       post amf_write_path, amf_content("putway", "/1", ["#{user.email}:test", cs_id, way.version + 2, way.id, [a, -1, b, c], way.tags, [[4.56, 12.34, -1, 0, { "test" => "new" }], [12.34, 4.56, b, 1, { "test" => "ok" }]], { d => 1 }])
1053       assert_response :success
1054       amf_parse_response
1055       result = amf_result("/1")
1056       new_node_id = result[4]["-1"].to_i
1057
1058       assert_equal 8, result.size
1059       assert_equal 0, result[0]
1060       assert_equal "", result[1]
1061       assert_equal way.id, result[2]
1062       assert_equal way.id, result[3]
1063       assert_equal({ "-1" => new_node_id }, result[4])
1064       assert_equal way.version + 3, result[5]
1065       assert_equal({ new_node_id.to_s => 1, b.to_s => 2 }, result[6])
1066       assert_equal({ d.to_s => 1 }, result[7])
1067
1068       new_way = Way.find(way.id)
1069       assert_equal way.version + 3, new_way.version
1070       assert_equal [a, new_node_id, b, c], new_way.nds
1071       assert_equal way.tags, new_way.tags
1072
1073       new_node = Node.find(new_node_id)
1074       assert_equal 1, new_node.version
1075       assert new_node.visible
1076       assert_in_delta(4.56, new_node.lon)
1077       assert_in_delta(12.34, new_node.lat)
1078       assert_equal({ "test" => "new" }, new_node.tags)
1079
1080       changed_node = Node.find(b)
1081       assert_equal 2, changed_node.version
1082       assert changed_node.visible
1083       assert_in_delta(12.34, changed_node.lon)
1084       assert_in_delta(4.56, changed_node.lat)
1085       assert_equal({ "test" => "ok" }, changed_node.tags)
1086
1087       deleted_node = Node.find(d)
1088       assert_equal 2, deleted_node.version
1089       assert_not deleted_node.visible
1090     end
1091
1092     # check that we can delete a way
1093     def test_deleteway_valid
1094       way = create(:way_with_nodes, :nodes_count => 3)
1095       nodes = way.nodes.each_with_object({}) { |n, ns| ns[n.id] = n.version }
1096       cs_id = way.changeset.id
1097       user = way.changeset.user
1098
1099       # Of the three nodes, two should be kept since they are used in
1100       # a different way, and the third deleted since it's unused
1101
1102       a = way.nodes[0]
1103       create(:way_node, :node => a)
1104       b = way.nodes[1]
1105       create(:way_node, :node => b)
1106       c = way.nodes[2]
1107
1108       post amf_write_path, amf_content("deleteway", "/1", ["#{user.email}:test", cs_id, way.id, way.version, nodes])
1109       assert_response :success
1110       amf_parse_response
1111       result = amf_result("/1")
1112
1113       assert_equal 5, result.size
1114       assert_equal 0, result[0]
1115       assert_equal "", result[1]
1116       assert_equal way.id, result[2]
1117       assert_equal way.version + 1, result[3]
1118       assert_equal({ c.id.to_s => 2 }, result[4])
1119
1120       new_way = Way.find(way.id)
1121       assert_equal way.version + 1, new_way.version
1122       assert_not new_way.visible
1123
1124       way.nds.each do |node_id|
1125         assert_equal result[4][node_id.to_s].nil?, Node.find(node_id).visible
1126       end
1127     end
1128
1129     # check that we can't delete a way that is in use
1130     def test_deleteway_inuse
1131       way = create(:way_with_nodes, :nodes_count => 4)
1132       create(:relation_member, :member => way)
1133       nodes = way.nodes.each_with_object({}) { |n, ns| ns[n.id] = n.version }
1134       cs_id = way.changeset.id
1135       user = way.changeset.user
1136
1137       post amf_write_path, amf_content("deleteway", "/1", ["#{user.email}:test", cs_id, way.id, way.version, nodes])
1138       assert_response :success
1139       amf_parse_response
1140       result = amf_result("/1")
1141
1142       assert_equal 2, result.size
1143       assert_equal(-1, result[0])
1144       assert_match(/Way #{way.id} is still used/, result[1])
1145
1146       new_way = Way.find(way.id)
1147       assert_equal way.version, new_way.version
1148       assert new_way.visible
1149
1150       way.nds.each do |node_id|
1151         assert Node.find(node_id).visible
1152       end
1153     end
1154
1155     # check that we can create a relation
1156     def test_putrelation_create_valid
1157       changeset = create(:changeset)
1158       user = changeset.user
1159       cs_id = changeset.id
1160
1161       node = create(:node)
1162       way = create(:way_with_nodes, :nodes_count => 2)
1163       relation = create(:relation)
1164
1165       post amf_write_path, amf_content("putrelation", "/1", ["#{user.email}:test", cs_id, 0, -1, { "test" => "new" }, [["Node", node.id, "node"], ["Way", way.id, "way"], ["Relation", relation.id, "relation"]], true])
1166       assert_response :success
1167       amf_parse_response
1168       result = amf_result("/1")
1169       new_relation_id = result[3].to_i
1170
1171       assert_equal 5, result.size
1172       assert_equal 0, result[0]
1173       assert_equal "", result[1]
1174       assert_equal(-1, result[2])
1175       assert_not_equal(-1, result[3])
1176       assert_equal 1, result[4]
1177
1178       new_relation = Relation.find(new_relation_id)
1179       assert_equal 1, new_relation.version
1180       assert_equal [["Node", node.id, "node"], ["Way", way.id, "way"], ["Relation", relation.id, "relation"]], new_relation.members
1181       assert_equal({ "test" => "new" }, new_relation.tags)
1182       assert new_relation.visible
1183     end
1184
1185     # check that we can update a relation
1186     def test_putrelation_update_valid
1187       relation = create(:relation)
1188       create(:relation_member, :relation => relation)
1189       user = relation.changeset.user
1190       cs_id = relation.changeset.id
1191
1192       assert_not_equal({ "test" => "ok" }, relation.tags)
1193       post amf_write_path, amf_content("putrelation", "/1", ["#{user.email}:test", cs_id, relation.version, relation.id, { "test" => "ok" }, relation.members, true])
1194       assert_response :success
1195       amf_parse_response
1196       result = amf_result("/1")
1197
1198       assert_equal 5, result.size
1199       assert_equal 0, result[0]
1200       assert_equal "", result[1]
1201       assert_equal relation.id, result[2]
1202       assert_equal relation.id, result[3]
1203       assert_equal relation.version + 1, result[4]
1204
1205       new_relation = Relation.find(relation.id)
1206       assert_equal relation.version + 1, new_relation.version
1207       assert_equal relation.members, new_relation.members
1208       assert_equal({ "test" => "ok" }, new_relation.tags)
1209       assert new_relation.visible
1210     end
1211
1212     # check that we can delete a relation
1213     def test_putrelation_delete_valid
1214       relation = create(:relation)
1215       create(:relation_member, :relation => relation)
1216       create(:relation_tag, :relation => relation)
1217       cs_id = relation.changeset.id
1218       user = relation.changeset.user
1219
1220       post amf_write_path, amf_content("putrelation", "/1", ["#{user.email}:test", cs_id, relation.version, relation.id, relation.tags, relation.members, false])
1221       assert_response :success
1222       amf_parse_response
1223       result = amf_result("/1")
1224
1225       assert_equal 5, result.size
1226       assert_equal 0, result[0]
1227       assert_equal "", result[1]
1228       assert_equal relation.id, result[2]
1229       assert_equal relation.id, result[3]
1230       assert_equal relation.version + 1, result[4]
1231
1232       new_relation = Relation.find(relation.id)
1233       assert_equal relation.version + 1, new_relation.version
1234       assert_equal [], new_relation.members
1235       assert_equal({}, new_relation.tags)
1236       assert_not new_relation.visible
1237     end
1238
1239     # check that we can't delete a relation that is in use
1240     def test_putrelation_delete_inuse
1241       relation = create(:relation)
1242       super_relation = create(:relation)
1243       create(:relation_member, :relation => super_relation, :member => relation)
1244       cs_id = relation.changeset.id
1245       user = relation.changeset.user
1246
1247       post amf_write_path, amf_content("putrelation", "/1", ["#{user.email}:test", cs_id, relation.version, relation.id, relation.tags, relation.members, false])
1248       assert_response :success
1249       amf_parse_response
1250       result = amf_result("/1")
1251
1252       assert_equal 2, result.size
1253       assert_equal(-1, result[0])
1254       assert_match(/relation #{relation.id} is used in/, result[1])
1255
1256       new_relation = Relation.find(relation.id)
1257       assert_equal relation.version, new_relation.version
1258       assert_equal relation.members, new_relation.members
1259       assert_equal relation.tags, new_relation.tags
1260       assert new_relation.visible
1261     end
1262
1263     # check that we can open a changeset
1264     def test_startchangeset_valid
1265       user = create(:user)
1266
1267       post amf_write_path, amf_content("startchangeset", "/1", ["#{user.email}:test", { "source" => "new" }, nil, "new", 1])
1268       assert_response :success
1269       amf_parse_response
1270       result = amf_result("/1")
1271       new_cs_id = result[2].to_i
1272
1273       assert_equal 3, result.size
1274       assert_equal 0, result[0]
1275       assert_equal "", result[1]
1276
1277       cs = Changeset.find(new_cs_id)
1278       assert cs.is_open?
1279       assert_equal({ "comment" => "new", "source" => "new" }, cs.tags)
1280
1281       old_cs_id = new_cs_id
1282
1283       post amf_write_path, amf_content("startchangeset", "/1", ["#{user.email}:test", { "source" => "newer" }, old_cs_id, "newer", 1])
1284       assert_response :success
1285       amf_parse_response
1286       result = amf_result("/1")
1287       new_cs_id = result[2].to_i
1288
1289       assert_not_equal old_cs_id, new_cs_id
1290
1291       assert_equal 3, result.size
1292       assert_equal 0, result[0]
1293       assert_equal "", result[1]
1294
1295       cs = Changeset.find(old_cs_id)
1296       assert_not cs.is_open?
1297       assert_equal({ "comment" => "newer", "source" => "new" }, cs.tags)
1298
1299       cs = Changeset.find(new_cs_id)
1300       assert cs.is_open?
1301       assert_equal({ "comment" => "newer", "source" => "newer" }, cs.tags)
1302
1303       old_cs_id = new_cs_id
1304
1305       post amf_write_path, amf_content("startchangeset", "/1", ["#{user.email}:test", {}, old_cs_id, "", 0])
1306       assert_response :success
1307       amf_parse_response
1308       result = amf_result("/1")
1309
1310       assert_equal 3, result.size
1311       assert_equal 0, result[0]
1312       assert_equal "", result[1]
1313       assert_nil result[2]
1314
1315       cs = Changeset.find(old_cs_id)
1316       assert_not cs.is_open?
1317       assert_equal({ "comment" => "newer", "source" => "newer" }, cs.tags)
1318     end
1319
1320     # check that we can't close somebody elses changeset
1321     def test_startchangeset_invalid_wrong_user
1322       user = create(:user)
1323       user2 = create(:user)
1324
1325       post amf_write_path, amf_content("startchangeset", "/1", ["#{user.email}:test", { "source" => "new" }, nil, "new", 1])
1326       assert_response :success
1327       amf_parse_response
1328       result = amf_result("/1")
1329       cs_id = result[2].to_i
1330
1331       assert_equal 3, result.size
1332       assert_equal 0, result[0]
1333       assert_equal "", result[1]
1334
1335       cs = Changeset.find(cs_id)
1336       assert cs.is_open?
1337       assert_equal({ "comment" => "new", "source" => "new" }, cs.tags)
1338
1339       post amf_write_path, amf_content("startchangeset", "/1", ["#{user2.email}:test", {}, cs_id, "delete", 0])
1340       assert_response :success
1341       amf_parse_response
1342       result = amf_result("/1")
1343
1344       assert_equal 2, result.size
1345       assert_equal(-2, result[0])
1346       assert_equal "The user doesn't own that changeset", result[1]
1347
1348       cs = Changeset.find(cs_id)
1349       assert cs.is_open?
1350       assert_equal({ "comment" => "new", "source" => "new" }, cs.tags)
1351     end
1352
1353     # check that invalid characters are stripped from changeset tags
1354     def test_startchangeset_invalid_xmlchar_comment
1355       user = create(:user)
1356
1357       invalid = "\035\022"
1358       comment = "foo#{invalid}bar"
1359
1360       post amf_write_path, amf_content("startchangeset", "/1", ["#{user.email}:test", {}, nil, comment, 1])
1361       assert_response :success
1362       amf_parse_response
1363       result = amf_result("/1")
1364       new_cs_id = result[2].to_i
1365
1366       assert_equal 3, result.size
1367       assert_equal 0, result[0]
1368       assert_equal "", result[1]
1369
1370       cs = Changeset.find(new_cs_id)
1371       assert cs.is_open?
1372       assert_equal({ "comment" => "foobar" }, cs.tags)
1373     end
1374
1375     private
1376
1377     # ************************************************************
1378     # AMF Helper functions
1379
1380     # Get the result record for the specified ID
1381     # It's an assertion FAIL if the record does not exist
1382     def amf_result(ref)
1383       assert @amf_result.key?("#{ref}/onResult")
1384       @amf_result["#{ref}/onResult"]
1385     end
1386
1387     # Encode the AMF message to invoke "target" with parameters as
1388     # the passed data. The ref is used to retrieve the results.
1389     def amf_content(target, ref, data)
1390       a, b = 1.divmod(256)
1391       c = StringIO.new
1392       c.write 0.chr * 2       # version 0
1393       c.write 0.chr * 2       # n headers
1394       c.write a.chr + b.chr   # n bodies
1395       c.write AMF.encodestring(target)
1396       c.write AMF.encodestring(ref)
1397       c.write [-1].pack("N")
1398       c.write AMF.encodevalue(data)
1399
1400       { :params => c.string, :headers => { "Content-Type" => "application/x-amf" } }
1401     end
1402
1403     # Parses the @response object as an AMF messsage.
1404     # The result is a hash of message_ref => data.
1405     # The attribute @amf_result is initialised to this hash.
1406     def amf_parse_response
1407       req = StringIO.new(@response.body)
1408
1409       req.read(2) # version
1410
1411       # parse through any headers
1412       headers = AMF.getint(req)        # Read number of headers
1413       headers.times do                 # Read each header
1414         AMF.getstring(req)             #  |
1415         req.getc                       #  | skip boolean
1416         AMF.getvalue(req)              #  |
1417       end
1418
1419       # parse through responses
1420       results = {}
1421       bodies = AMF.getint(req)         # Read number of bodies
1422       bodies.times do                  # Read each body
1423         message = AMF.getstring(req)   #  | get message name
1424         AMF.getstring(req)             #  | get index in response sequence
1425         AMF.getlong(req)               #  | get total size in bytes
1426         args = AMF.getvalue(req)       #  | get response (probably an array)
1427         results[message] = args
1428       end
1429       @amf_result = results
1430       results
1431     end
1432
1433     ##
1434     # given an array of bounding boxes (each an array of 4 floats), call the
1435     # AMF "whichways" controller for each and pass the result back to the
1436     # caller's block for assertion testing.
1437     def check_bboxes_are_bad(bboxes)
1438       bboxes.each do |bbox|
1439         post amf_read_path, amf_content("whichways", "/1", bbox)
1440         assert_response :success
1441         amf_parse_response
1442
1443         # pass the response back to the caller's block to be tested
1444         # against what the caller expected.
1445         map = amf_result "/1"
1446         yield map, bbox
1447       end
1448     end
1449
1450     # this should be what AMF controller returns when the bbox of a
1451     # whichways request is invalid or too large.
1452     def assert_boundary_error(map, msg = nil, error_hint = nil)
1453       expected_map = [-2, "Sorry - I can't get the map for that area.#{msg}"]
1454       assert_equal expected_map, map, "AMF controller should have returned an error. (#{error_hint})"
1455     end
1456
1457     # this should be what AMF controller returns when the bbox of a
1458     # whichways_deleted request is invalid or too large.
1459     def assert_deleted_boundary_error(map, msg = nil, error_hint = nil)
1460       expected_map = [-2, "Sorry - I can't get the map for that area.#{msg}"]
1461       assert_equal expected_map, map, "AMF controller should have returned an error. (#{error_hint})"
1462     end
1463   end
1464 end