source: subversion/sites/rails_port_branches/api06/test/functional/amf_controller_test.rb @ 12284

Revision 12284, 16.1 KB checked in by zere, 5 years ago (diff)

Some fixes to the rails part of the AMF controller and associated test.

Line 
1require File.dirname(__FILE__) + '/../test_helper'
2require 'stringio'
3include Potlatch
4
5class AmfControllerTest < ActionController::TestCase
6  api_fixtures
7
8  # this should be what AMF controller returns when the bbox of a request
9  # is invalid or too large.
10  BOUNDARY_ERROR = [-2,"Sorry - I can't get the map for that area."]
11
12  def test_getway
13    # check a visible way
14    id = current_ways(:visible_way).id
15    amf_content "getway", "/1", [id]
16    post :amf_read
17    assert_response :success
18    amf_parse_response                                         
19    assert_equal amf_result("/1")[0], id
20  end
21
22  def test_getway_invisible
23    # check an invisible way
24    id = current_ways(:invisible_way).id
25    amf_content "getway", "/1", [id]
26    post :amf_read
27    assert_response :success
28    amf_parse_response
29    way = amf_result("/1")
30    assert_equal way[0], id
31    assert way[1].empty? and way[2].empty?
32  end
33
34  def test_getway_nonexistent
35    # check chat a non-existent way is not returned
36    amf_content "getway", "/1", [0]
37    post :amf_read
38    assert_response :success
39    amf_parse_response
40    way = amf_result("/1")
41    assert_equal way[0], 0
42    assert way[1].empty? and way[2].empty?
43  end
44
45  def test_whichways
46    node = current_nodes(:used_node_1)
47    minlon = node.lon-0.1
48    minlat = node.lat-0.1
49    maxlon = node.lon+0.1
50    maxlat = node.lat+0.1
51    amf_content "whichways", "/1", [minlon, minlat, maxlon, maxlat]
52    post :amf_read
53    assert_response :success
54    amf_parse_response
55
56    # check contents of message
57    map = amf_result "/1"
58    assert_equal 0, map[0], 'first map element should be 0'
59    assert_equal Array, map[1].class, 'second map element should be an array'
60    # TODO: looks like amf_controller changed since this test was written
61    # so someone who knows what they're doing should check this!
62    ways = map[1].collect { |x| x[0] }
63    assert ways.include?(current_ways(:used_way).id),
64      "map should include used way"
65    assert !ways.include?(current_ways(:invisible_way).id),
66      'map should not include deleted way'
67  end
68
69  ##
70  # checks that too-large a bounding box will not be served.
71  def test_whichways_toobig
72    bbox = [-0.1,-0.1,1.1,1.1]
73    check_bboxes_are_bad [bbox] do |map,bbox|
74      assert_equal BOUNDARY_ERROR, map, "AMF controller should have returned an error."
75    end
76  end
77
78  ##
79  # checks that an invalid bounding box will not be served. in this case
80  # one with max < min latitudes.
81  #
82  # NOTE: the controller expands the bbox by 0.01 in each direction!
83  def test_whichways_badlat
84    bboxes = [[0,0.1,0.1,0], [-0.1,80,0.1,70], [0.24,54.35,0.25,54.33]]
85    check_bboxes_are_bad bboxes do |map, bbox|
86      assert_equal BOUNDARY_ERROR, map, "AMF controller should have returned an error #{bbox.inspect}."
87    end
88  end
89
90  ##
91  # same as test_whichways_badlat, but for longitudes
92  #
93  # NOTE: the controller expands the bbox by 0.01 in each direction!
94  def test_whichways_badlon
95    bboxes = [[80,-0.1,70,0.1], [54.35,0.24,54.33,0.25]]
96    check_bboxes_are_bad bboxes do |map, bbox|
97      assert_equal BOUNDARY_ERROR, map, "AMF controller should have returned an error #{bbox.inspect}."
98    end
99  end
100
101  def test_whichways_deleted
102    node = current_nodes(:used_node_1)
103    minlon = node.lon-0.1
104    minlat = node.lat-0.1
105    maxlon = node.lon+0.1
106    maxlat = node.lat+0.1
107    amf_content "whichways_deleted", "/1", [minlon, minlat, maxlon, maxlat]
108    post :amf_read
109    assert_response :success
110    amf_parse_response
111
112    # check contents of message
113    map = amf_result "/1"
114    assert_equal 0, map[0], 'first map element should be 0'
115    assert_equal Array, map[1].class, 'second map element should be an array'
116    # TODO: looks like amf_controller changed since this test was written
117    # so someone who knows what they're doing should check this!
118    assert !map[1].include?(current_ways(:used_way).id),
119      "map should not include used way"
120    assert map[1].include?(current_ways(:invisible_way).id),
121      'map should include deleted way'
122  end
123
124  def test_whichways_deleted_toobig
125    bbox = [-0.1,-0.1,1.1,1.1]
126    amf_content "whichways_deleted", "/1", bbox
127    post :amf_read
128    assert_response :success
129    amf_parse_response
130
131    map = amf_result "/1"
132    assert_equal BOUNDARY_ERROR, map, "AMF controller should have returned an error."
133  end
134
135  def test_getrelation
136    id = current_relations(:visible_relation).id
137    amf_content "getrelation", "/1", [id]
138    post :amf_read
139    assert_response :success
140    amf_parse_response
141    assert_equal amf_result("/1")[0], id
142  end
143
144  def test_getrelation_invisible
145    id = current_relations(:invisible_relation).id
146    amf_content "getrelation", "/1", [id]
147    post :amf_read
148    assert_response :success
149    amf_parse_response
150    rel = amf_result("/1")
151    assert_equal rel[0], id
152    assert rel[1].empty? and rel[2].empty?
153  end
154
155  def test_getrelation_nonexistent
156    id = 0
157    amf_content "getrelation", "/1", [id]
158    post :amf_read
159    assert_response :success
160    amf_parse_response
161    rel = amf_result("/1")
162    assert_equal rel[0], id
163    assert rel[1].empty? and rel[2].empty?
164  end
165
166  def test_getway_old
167    # try to get the last visible version (specified by <0) (should be current version)
168    latest = current_ways(:way_with_versions)
169    # try to get version 1
170    v1 = ways(:way_with_versions_v1)
171    {latest => -1, v1 => v1.version}.each do |way, v|
172      amf_content "getway_old", "/1", [way.id, v]
173      post :amf_read
174      assert_response :success
175      amf_parse_response
176      returned_way = amf_result("/1")
177      assert_equal returned_way[1], way.id
178      assert_equal returned_way[4], way.version
179    end
180  end
181
182  def test_getway_old_nonexistent
183    # try to get the last version+10 (shoudn't exist)
184    latest = current_ways(:way_with_versions)
185    # try to get last visible version of non-existent way
186    # try to get specific version of non-existent way
187    {nil => -1, nil => 1, latest => latest.version + 10}.each do |way, v|
188      amf_content "getway_old", "/1", [way.nil? ? 0 : way.id, v]
189      post :amf_read
190      assert_response :success
191      amf_parse_response
192      returned_way = amf_result("/1")
193      assert returned_way[2].empty?
194      assert returned_way[3].empty?
195      assert returned_way[4] < 0
196    end
197  end
198
199  def test_getway_history
200    latest = current_ways(:way_with_versions)
201    amf_content "getway_history", "/1", [latest.id]
202    post :amf_read
203    assert_response :success
204    amf_parse_response
205    history = amf_result("/1")
206
207    # ['way',wayid,history]
208    assert_equal history[0], 'way'
209    assert_equal history[1], latest.id
210    assert_equal history[2].first[0], latest.version
211    assert_equal history[2].last[0], ways(:way_with_versions_v1).version
212  end
213
214  def test_getway_history_nonexistent
215    amf_content "getway_history", "/1", [0]
216    post :amf_read
217    assert_response :success
218    amf_parse_response
219    history = amf_result("/1")
220
221    # ['way',wayid,history]
222    assert_equal history[0], 'way'
223    assert_equal history[1], 0
224    assert history[2].empty?
225  end
226
227  def test_getnode_history
228    latest = current_nodes(:node_with_versions)
229    amf_content "getnode_history", "/1", [latest.id]
230    post :amf_read
231    assert_response :success
232    amf_parse_response
233    history = amf_result("/1")
234
235    # ['node',nodeid,history]
236    assert_equal history[0], 'node', 
237      'first element should be "node"'
238    assert_equal history[1], latest.id,
239      'second element should be the input node ID'
240    # NOTE: changed this test to match what amf_controller actually
241    # outputs - which may or may not be what potlatch is expecting.
242    # someone who knows potlatch (i.e: richard f) should review this.
243    assert_equal history[2].first[0], latest.version,
244      'first part of third element should be the latest version'
245    assert_equal history[2].last[0], 
246      nodes(:node_with_versions_v1).version,
247      'second part of third element should be the initial version'
248  end
249
250  def test_getnode_history_nonexistent
251    amf_content "getnode_history", "/1", [0]
252    post :amf_read
253    assert_response :success
254    amf_parse_response
255    history = amf_result("/1")
256
257    # ['node',nodeid,history]
258    assert_equal history[0], 'node'
259    assert_equal history[1], 0
260    assert history[2].empty?
261  end
262
263  # ************************************************************
264  # AMF Write tests
265  def test_putpoi_update_valid
266    nd = current_nodes(:visible_node)
267    amf_content "putpoi", "/1", ["test@openstreetmap.org:test", nd.changeset_id, nd.version, nd.id, nd.lon, nd.lat, nd.tags, nd.visible]
268    post :amf_write
269    assert_response :success
270    amf_parse_response
271    result = amf_result("/1")
272   
273    assert_equal 0, result[0]
274    assert_equal nd.id, result[1]
275    assert_equal nd.id, result[2]
276    assert_equal nd.version+1, result[3]
277   
278    # Now try to update again, with a different lat/lon, using the updated version number
279    lat = nd.lat+0.1
280    lon = nd.lon-0.1
281    amf_content "putpoi", "/2", ["test@openstreetmap.org:test", nd.changeset_id, nd.version+1, nd.id, lon, lat, nd.tags, nd.visible]
282    post :amf_write
283    assert_response :success
284    amf_parse_response
285    result = amf_result("/2")
286   
287    assert_equal 0, result[0]
288    assert_equal nd.id, result[1]
289    assert_equal nd.id, result[2]
290    assert_equal nd.version+2, result[3]
291  end
292 
293  # Check that we can create a no valid poi
294  # Using similar method for the node controller test
295  def test_putpoi_create_valid
296    # This node has no tags
297    nd = Node.new
298    # create a node with random lat/lon
299    lat = rand(100)-50 + rand
300    lon = rand(100)-50 + rand
301    # normal user has a changeset open
302    changeset = changesets(:normal_user_first_change)
303   
304    amf_content "putpoi", "/1", ["test@openstreetmap.org:test", changeset.id, nil, nil, lon, lat, {}, nil]
305    post :amf_write
306    assert_response :success
307    amf_parse_response
308    result = amf_result("/1")
309   
310    # check the array returned by the amf
311    assert_equal 4, result.size
312    assert_equal 0, result[0], "expected to get the status ok from the amf"
313    assert_equal 0, result[1], "The old id should be 0"
314    assert result[2] > 0, "The new id should be greater than 0"
315    assert_equal 1, result[3], "The new version should be 1"
316   
317    # Finally check that the node that was saved has saved the data correctly
318    # in both the current and history tables
319    # First check the current table
320    current_node = Node.find(result[2])
321    assert_in_delta lat, current_node.lat, 0.00001, "The latitude was not retreieved correctly"
322    assert_in_delta lon, current_node.lon, 0.00001, "The longitude was not retreived correctly"
323    assert_equal 0, current_node.tags.size, "There seems to be a tag that has been added to the node"
324    assert_equal result[3], current_node.version, "The version returned, is different to the one returned by the amf"
325    # Now check the history table
326    historic_nodes = Node.find(:all, :conditions => { :id => result[2] })
327    assert_equal 1, historic_nodes.size, "There should only be one historic node created"
328    first_historic_node = historic_nodes.first
329    assert_in_delta lat, first_historic_node.lat, 0.00001, "The latitude was not retreived correctly"
330    assert_in_delta lon, first_historic_node.lon, 0.00001, "The longitude was not retreuved correctly"
331    assert_equal 0, first_historic_node.tags.size, "There seems to be a tag that have been attached to this node"
332    assert_equal result[3], first_historic_node.version, "The version returned, is different to the one returned by the amf"
333   
334    ####
335    # This node has some tags
336    tnd = Node.new
337    # create a node with random lat/lon
338    lat = rand(100)-50 + rand
339    lon = rand(100)-50 + rand
340    # normal user has a changeset open
341    changeset = changesets(:normal_user_first_change)
342   
343    amf_content "putpoi", "/2", ["test@openstreetmap.org:test", changeset.id, nil, nil, lon, lat, { "key" => "value", "ping" => "pong" }, nil]
344    post :amf_write
345    assert_response :success
346    amf_parse_response
347    result = amf_result("/2")
348
349    # check the array returned by the amf
350    assert_equal 4, result.size
351    assert_equal 0, result[0], "Expected to get the status ok in the amf"
352    assert_equal 0, result[1], "The old id should be 0"
353    assert result[2] > 0, "The new id should be greater than 0"
354    assert_equal 1, result[3], "The new version should be 1"
355   
356    # Finally check that the node that was saved has saved the data correctly
357    # in both the current and history tables
358    # First check the current table
359    current_node = Node.find(result[2])
360    assert_in_delta lat, current_node.lat, 0.00001, "The latitude was not retreieved correctly"
361    assert_in_delta lon, current_node.lon, 0.00001, "The longitude was not retreived correctly"
362    assert_equal 2, current_node.tags.size, "There seems to be a tag that has been added to the node"
363    assert_equal({ "key" => "value", "ping" => "pong" }, current_node.tags, "tags are different")
364    assert_equal result[3], current_node.version, "The version returned, is different to the one returned by the amf"
365    # Now check the history table
366    historic_nodes = Node.find(:all, :conditions => { :id => result[2] })
367    assert_equal 1, historic_nodes.size, "There should only be one historic node created"
368    first_historic_node = historic_nodes.first
369    assert_in_delta lat, first_historic_node.lat, 0.00001, "The latitude was not retreived correctly"
370    assert_in_delta lon, first_historic_node.lon, 0.00001, "The longitude was not retreuved correctly"
371    assert_equal 2, first_historic_node.tags.size, "There seems to be a tag that have been attached to this node"
372    assert_equal({ "key" => "value", "ping" => "pong" }, first_historic_node.tags, "tags are different")
373    assert_equal result[3], first_historic_node.version, "The version returned, is different to the one returned by the amf"
374
375  end
376
377  # ************************************************************
378  # AMF Helper functions
379
380  # Get the result record for the specified ID
381  # It's an assertion FAIL if the record does not exist
382  def amf_result ref
383    assert @amf_result.has_key?("#{ref}/onResult")
384    @amf_result["#{ref}/onResult"]
385  end
386
387  # Encode the AMF message to invoke "target" with parameters as
388  # the passed data. The ref is used to retrieve the results.
389  def amf_content(target, ref, data)
390    a,b=1.divmod(256)
391    c = StringIO.new()
392    c.write 0.chr+0.chr   # version 0
393    c.write 0.chr+0.chr   # n headers
394    c.write a.chr+b.chr   # n bodies
395    c.write AMF.encodestring(target)
396    c.write AMF.encodestring(ref)
397    c.write [-1].pack("N")
398    c.write AMF.encodevalue(data)
399
400    @request.env["RAW_POST_DATA"] = c.string
401  end
402
403  # Parses the @response object as an AMF messsage.
404  # The result is a hash of message_ref => data.
405  # The attribute @amf_result is initialised to this hash.
406  def amf_parse_response
407    if @response.body.class.to_s == 'Proc'
408      res = StringIO.new()
409      @response.body.call @response, res
410      req = StringIO.new(res.string)
411    else
412      req = StringIO.new(@response.body)
413    end
414    req.read(2)   # version
415
416    # parse through any headers
417        headers=AMF.getint(req)                                 # Read number of headers
418        headers.times do                                                # Read each header
419          name=AMF.getstring(req)                               #  |
420          req.getc                                                              #  | skip boolean
421          value=AMF.getvalue(req)                               #  |
422        end
423
424    # parse through responses
425    results = {}
426    bodies=AMF.getint(req)                                      # Read number of bodies
427        bodies.times do                                                 # Read each body
428          message=AMF.getstring(req)                    #  | get message name
429          index=AMF.getstring(req)                              #  | get index in response sequence
430          bytes=AMF.getlong(req)                                #  | get total size in bytes
431          args=AMF.getvalue(req)                                #  | get response (probably an array)
432      results[message] = args
433    end
434    @amf_result = results
435    results
436  end
437
438  ##
439  # given an array of bounding boxes (each an array of 4 floats), call the
440  # AMF "whichways" controller for each and pass the result back to the
441  # caller's block for assertion testing.
442  def check_bboxes_are_bad(bboxes)
443    bboxes.each do |bbox|
444      amf_content "whichways", "/1", bbox
445      post :amf_read
446      assert_response :success
447      amf_parse_response
448
449      # pass the response back to the caller's block to be tested
450      # against what the caller expected.
451      map = amf_result "/1"
452      yield map, bbox
453    end
454  end
455end
Note: See TracBrowser for help on using the repository browser.