wurfl_cloud_client_light 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.gitignore +5 -0
  2. data/FOSS_THIRD_PARTY_LICENSES.txt +23 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +40 -0
  5. data/LICENSE.txt +75 -0
  6. data/Rakefile +14 -0
  7. data/lib/wurfl_cloud/cache/cookie.rb +36 -0
  8. data/lib/wurfl_cloud/cache/local_memory.rb +36 -0
  9. data/lib/wurfl_cloud/cache/null.rb +34 -0
  10. data/lib/wurfl_cloud/client.rb +98 -0
  11. data/lib/wurfl_cloud/configuration.rb +81 -0
  12. data/lib/wurfl_cloud/device_capabilities.rb +71 -0
  13. data/lib/wurfl_cloud/environment.rb +41 -0
  14. data/lib/wurfl_cloud/errors.rb +16 -0
  15. data/lib/wurfl_cloud/helper.rb +14 -0
  16. data/lib/wurfl_cloud/rack/cache_manager.rb +47 -0
  17. data/lib/wurfl_cloud/rails.rb +27 -0
  18. data/lib/wurfl_cloud/version.rb +7 -0
  19. data/lib/wurfl_cloud.rb +42 -0
  20. data/spec/files/generic.json +1 -0
  21. data/spec/files/generic_filtered.json +1 -0
  22. data/spec/files/lumia.json +1 -0
  23. data/spec/files/lumia_filtered.json +1 -0
  24. data/spec/files/strange_values.json +1 -0
  25. data/spec/spec_helper.rb +20 -0
  26. data/spec/support/rack_helpers.rb +79 -0
  27. data/spec/support/string_extensions.rb +26 -0
  28. data/spec/wurfl_cloud/client_spec.rb +200 -0
  29. data/spec/wurfl_cloud/configuration_spec.rb +111 -0
  30. data/spec/wurfl_cloud/cookie_cache_spec.rb +44 -0
  31. data/spec/wurfl_cloud/device_capabilities_spec.rb +136 -0
  32. data/spec/wurfl_cloud/environment_spec.rb +86 -0
  33. data/spec/wurfl_cloud/helper_spec.rb +28 -0
  34. data/spec/wurfl_cloud/null_cache_spec.rb +30 -0
  35. data/spec/wurfl_cloud/rack_cache_manager_spec.rb +69 -0
  36. data/spec/wurfl_cloud/server_request_spec.rb +38 -0
  37. data/wurfl_cloud_client_light.gemspec +31 -0
  38. metadata +161 -0
@@ -0,0 +1,71 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ require 'wurfl_cloud/errors'
6
+ require 'json'
7
+
8
+ module WurflCloud
9
+ class DeviceCapabilities
10
+ attr_accessor :mtime, :id, :user_agent
11
+
12
+ def initialize(ua = nil)
13
+ @capabilities = {}
14
+ @mtime = Time.at(0)
15
+ @id = nil
16
+ @user_agent = ua
17
+ end
18
+
19
+ def [](key)
20
+ @capabilities[key]
21
+ end
22
+
23
+ def []=(key, value)
24
+ @capabilities[key] = value
25
+ end
26
+
27
+ def merge(newvalues)
28
+ @capabilities.merge!(newvalues)
29
+ end
30
+
31
+ def empty?
32
+ @capabilities.empty?
33
+ end
34
+
35
+ def has_key?(key)
36
+ @capabilities.has_key?(key)
37
+ end
38
+
39
+ def to_hash
40
+ @capabilities.clone
41
+ end
42
+ class << self
43
+ def parse(json)
44
+ object = JSON.parse(json)
45
+ new.tap do |device_capabilities|
46
+ object["capabilities"].each do |key,value|
47
+ device_capabilities[key] = cast_value(value)
48
+ end
49
+
50
+ device_capabilities.id = object["id"]
51
+ device_capabilities["id"] = object["id"]
52
+ device_capabilities.mtime = Time.at(object["mtime"].to_i)
53
+ end
54
+ rescue
55
+ raise WurflCloud::Errors::MalformedResponseError.new
56
+ end
57
+
58
+ private
59
+
60
+ def cast_value(value)
61
+ case value.to_s
62
+ when "true" then true ;
63
+ when "false" then false ;
64
+ when /^[1-9][0-9]*$/ then value.to_s.to_i ;
65
+ when /^[1-9][0-9]*\.[0-9]+$/ then value.to_s.to_f ;
66
+ else value
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,41 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ require 'wurfl_cloud/errors'
6
+
7
+ module WurflCloud
8
+ class Environment
9
+
10
+ USER_AGENT_FIELDS = [
11
+ 'HTTP_X_DEVICE_USER_AGENT',
12
+ 'HTTP_X_ORIGINAL_USER_AGENT',
13
+ 'HTTP_X_OPERAMINI_PHONE_UA',
14
+ 'HTTP_X_SKYFIRE_PHONE',
15
+ 'HTTP_X_BOLT_PHONE_UA',
16
+ 'HTTP_USER_AGENT'
17
+ ]
18
+
19
+ attr_reader :user_agent, :x_forwarded_for, :x_accept, :x_wap_profile
20
+
21
+ # Extracts the http headers that are relevant
22
+ # to the library. They are used by the client
23
+ # when communicating with the API server.
24
+ def initialize(http_env={})
25
+ USER_AGENT_FIELDS.each do |ua_field|
26
+ @user_agent ||= http_env[ua_field]
27
+ end
28
+
29
+ @x_accept = http_env["HTTP_ACCEPT"]
30
+
31
+ if !(@x_wap_profile = http_env["HTTP_X_WAP_PROFILE"])
32
+ @x_wap_profile = http_env["HTTP_PROFILE"]
33
+ end
34
+
35
+ if http_env["REMOTE_ADDR"]
36
+ @x_forwarded_for = http_env["REMOTE_ADDR"]
37
+ @x_forwarded_for = "#{x_forwarded_for}, #{http_env["HTTP_X_FORWARDED_FOR"]}" if http_env["HTTP_X_FORWARDED_FOR"]
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,16 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ module WurflCloud
6
+ module Errors
7
+ class GenericError < StandardError
8
+ end
9
+ class MalformedResponseError < GenericError
10
+ end
11
+ class ConfigurationError < GenericError
12
+ end
13
+ class ConnectionError < GenericError
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ module WurflCloud
6
+ module Helper
7
+
8
+ def wurfl_detect_device(env)
9
+ wurfl_env = WurflCloud::Environment.new(env)
10
+ wurfl_cache = WurflCloud.configuration.cache(env)
11
+ @device ||= WurflCloud::Client.detect_device(wurfl_env, wurfl_cache)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,47 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ module WurflCloud::Rack
6
+ class CacheManager
7
+ # to be refactored: make configurable
8
+ COOKIE_NAME = 'WurflCloud_Client'
9
+ EXPIRY = 86400
10
+
11
+ def initialize(app, options={})
12
+ @app = app
13
+ end
14
+ def call(env)
15
+ # extract cookie
16
+ request = Rack::Request.new(env)
17
+ env['wurfl.cookie.device_cache'] = extract_wurfl_cookie(request.cookies)
18
+
19
+ # execute upstream request
20
+ status, headers, body = @app.call(env)
21
+
22
+ # store cookie
23
+ response = Rack::Response.new body, status, headers
24
+ response.set_cookie(COOKIE_NAME, {:value => {'date_set'=>Time.now.to_i, 'capabilities'=>env['wurfl.cookie.device_cache']}.to_json, :path => "/", :expires => Time.now+EXPIRY})
25
+ response.finish
26
+ end
27
+
28
+ private
29
+
30
+ def extract_wurfl_cookie(cookies)
31
+ # read the cookie and try to parse it
32
+ raw_cookie = cookies[COOKIE_NAME]
33
+ parsed_cookie = JSON.parse(raw_cookie)
34
+
35
+ # if parsed then check the expiry
36
+ return nil if !parsed_cookie.has_key?('date_set') || (parsed_cookie['date_set'].to_i+EXPIRY < Time.now.to_i)
37
+
38
+ # check if the capabilities params are present
39
+ return nil if !parsed_cookie.has_key?('capabilities') || !parsed_cookie['capabilities'].is_a?(Hash) || parsed_cookie['capabilities'].empty?
40
+
41
+ parsed_cookie['capabilities']
42
+
43
+ rescue Exception=>e
44
+ nil
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,27 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ require 'wurfl_cloud/helper'
6
+ require 'wurfl_cloud/rack/cache_manager'
7
+
8
+ module WurflCloud
9
+ class Engine < ::Rails::Engine
10
+
11
+ # # Initialize the cache manager rack middleware
12
+ # config.app_middleware.use WurflCloud::Rack::CacheManager
13
+
14
+ # adds the moethods to the controller and views
15
+ initializer "wurf_cloud.helpers" do
16
+ ActiveSupport.on_load(:action_controller) do
17
+ include WurflCloud::Helper
18
+ helper_method :wurfl_detect_device
19
+ end
20
+
21
+ ActiveSupport.on_load(:action_view) do
22
+ include WurflCloud::Helper
23
+ end
24
+ end
25
+
26
+ end
27
+ end
@@ -0,0 +1,7 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ module WurflCloud
6
+ VERSION = "1.0.0"
7
+ end
@@ -0,0 +1,42 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ require 'wurfl_cloud/configuration'
6
+ require 'wurfl_cloud/cache/null'
7
+ require 'wurfl_cloud/cache/cookie'
8
+ require 'wurfl_cloud/version'
9
+ require 'wurfl_cloud/client'
10
+ require 'wurfl_cloud/environment'
11
+ require 'wurfl_cloud/device_capabilities'
12
+ require 'wurfl_cloud/errors'
13
+
14
+ module WurflCloud
15
+
16
+ class << self
17
+
18
+ # A configuration object. See WurflCloud::Configuration.
19
+ attr_writer :configuration
20
+
21
+ # Call this method to modify defaults in your initializers.
22
+ #
23
+ # @example
24
+ # WurflCloud.configure do |config|
25
+ # config.api_key = '00000000:xxxxxxxxxxxxxxxxxxxxxxxxxxx'
26
+ # config.host = 'staging.wurflcloud.com'
27
+ # end
28
+ def configure(silent = false)
29
+ yield(configuration)
30
+ end
31
+
32
+ # The configuration object.
33
+ # @see WurflCloud.configure
34
+ def configuration
35
+ @configuration ||= WurflCloud::Configuration.new
36
+ end
37
+
38
+ end
39
+
40
+ end
41
+
42
+ require 'wurfl_cloud/rails' if defined?(Rails)
@@ -0,0 +1 @@
1
+ {"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"id":"generic","user_agent":"","fall_back":"root","browser_id":"browser_root","mobile_browser":"","nokia_feature_pack":0,"device_os":"","nokia_series":0,"has_qwerty_keyboard":false,"pointing_method":"mouse","mobile_browser_version":"","is_tablet":false,"nokia_edition":0,"uaprof":"","can_skip_aligned_link_row":false,"device_claims_web_support":false,"ununiqueness_handler":"","model_name":"","device_os_version":"","uaprof2":"","is_wireless_device":false,"uaprof3":"","brand_name":"generic web browser","model_extra_info":"","marketing_name":"","can_assign_phone_number":true,"release_date":"2002_january","unique":true,"icons_on_menu_items_support":false,"opwv_wml_extensions_support":false,"built_in_back_button_support":false,"proportional_font":false,"insert_br_element_after_widget_recommended":false,"wizards_recommended":false,"wml_can_display_images_and_text_on_same_line":false,"softkey_support":false,"wml_make_phone_call_string":"wtai:\/\/wp\/mc;","deck_prefetch_support":false,"menu_with_select_element_recommended":false,"numbered_menus":false,"card_title_support":true,"image_as_link_support":false,"wrap_mode_support":false,"table_support":true,"access_key_support":false,"wml_displays_image_in_center":false,"elective_forms_recommended":true,"times_square_mode_support":false,"break_list_of_links_with_br_element_recommended":true,"menu_with_list_of_links_recommended":true,"imode_region":"none","chtml_can_display_images_and_text_on_same_line":false,"chtml_displays_image_in_center":false,"chtml_make_phone_call_string":"tel:","chtml_table_support":false,"chtml_display_accesskey":false,"emoji":false,"xhtml_preferred_charset":"utf8","xhtml_supports_css_cell_table_coloring":false,"xhtml_select_as_radiobutton":false,"xhtml_autoexpand_select":false,"xhtml_avoid_accesskeys":false,"accept_third_party_cookie":true,"xhtml_make_phone_call_string":"tel:","xhtml_allows_disabled_form_elements":false,"xhtml_supports_invisible_text":false,"xhtml_select_as_dropdown":false,"cookie_support":true,"xhtml_send_mms_string":"none","xhtml_table_support":false,"xhtml_display_accesskey":false,"xhtml_can_embed_video":"none","xhtml_supports_iframe":"none","xhtmlmp_preferred_mime_type":"application\/vnd.wap.xhtml+xml","xhtml_supports_monospace_font":false,"xhtml_supports_inline_input":false,"xhtml_supports_forms_in_table":false,"xhtml_document_title_support":true,"xhtml_support_wml2_namespace":false,"xhtml_readable_background_color1":"#FFFFFF","xhtml_format_as_attribute":false,"xhtml_supports_table_for_layout":false,"xhtml_readable_background_color2":"#FFFFFF","xhtml_select_as_popup":false,"xhtml_send_sms_string":"none","xhtml_format_as_css_property":false,"xhtml_file_upload":"not_supported","xhtml_honors_bgcolor":false,"opwv_xhtml_extensions_support":false,"xhtml_marquee_as_css_property":false,"xhtml_nowrap_mode":false,"ajax_preferred_geoloc_api":"none","ajax_xhr_type":"none","ajax_support_getelementbyid":false,"ajax_support_event_listener":false,"ajax_manipulate_dom":false,"ajax_support_javascript":false,"ajax_support_inner_html":false,"ajax_manipulate_css":false,"ajax_support_events":false,"html_web_3_2":false,"html_wi_imode_htmlx_1":false,"html_wi_imode_html_1":false,"html_wi_oma_xhtmlmp_1_0":true,"html_wi_imode_html_2":false,"html_wi_w3_xhtmlbasic":true,"html_wi_imode_compact_generic":false,"html_wi_imode_html_3":false,"wml_1_1":true,"html_wi_imode_html_4":false,"wml_1_2":false,"html_wi_imode_html_5":false,"wml_1_3":false,"preferred_markup":"html_wi_oma_xhtmlmp_1_0","xhtml_support_level":1,"voicexml":false,"html_wi_imode_htmlx_1_1":false,"multipart_support":false,"html_web_4_0":false,"time_to_live_support":false,"total_cache_disable_support":false,"physical_screen_height":27,"columns":11,"dual_orientation":false,"physical_screen_width":27,"rows":6,"max_image_width":90,"resolution_height":40,"resolution_width":90,"max_image_height":35,"greyscale":false,"jpg":false,"gif":true,"transparent_png_index":false,"epoc_bmp":false,"bmp":false,"wbmp":true,"gif_animated":false,"colors":256,"svgt_1_1_plus":false,"svgt_1_1":false,"transparent_png_alpha":false,"png":false,"tiff":false,"emptyok":false,"empty_option_value_support":true,"basic_authentication_support":true,"post_method_support":true,"nokia_voice_call":false,"wta_pdc":false,"wta_voice_call":false,"wta_misc":false,"wta_phonebook":false,"phone_id_provided":false,"https_support":true,"sdio":false,"wifi":false,"has_cellular_radio":true,"max_data_rate":9,"vpn":false,"max_length_of_username":0,"max_url_length_bookmark":0,"max_no_of_bookmarks":0,"max_deck_size":4000,"max_url_length_cached_page":0,"max_length_of_password":0,"max_no_of_connection_settings":0,"max_url_length_in_requests":128,"max_object_size":0,"max_url_length_homepage":0,"video":false,"picture_bmp":false,"picture":false,"wallpaper_df_size_limit":0,"picture_preferred_width":0,"wallpaper_oma_size_limit":0,"picture_greyscale":false,"inline_support":false,"ringtone_qcelp":false,"screensaver_oma_size_limit":0,"screensaver_wbmp":false,"picture_resize":"none","picture_preferred_height":0,"ringtone_rmf":false,"wallpaper_wbmp":false,"wallpaper_jpg":false,"screensaver_bmp":false,"screensaver_max_width":0,"picture_inline_size_limit":0,"picture_colors":2,"ringtone_midi_polyphonic":false,"ringtone_midi_monophonic":false,"screensaver_preferred_height":0,"ringtone_voices":1,"ringtone_3gpp":false,"oma_support":false,"ringtone_inline_size_limit":0,"wallpaper_preferred_width":0,"wallpaper_greyscale":false,"screensaver_preferred_width":0,"wallpaper_preferred_height":0,"picture_max_width":0,"picture_jpg":false,"ringtone_aac":false,"ringtone_oma_size_limit":0,"wallpaper_directdownload_size_limit":0,"screensaver_inline_size_limit":0,"ringtone_xmf":false,"picture_max_height":0,"screensaver_max_height":0,"ringtone_mp3":false,"wallpaper_png":false,"screensaver_jpg":false,"ringtone_directdownload_size_limit":0,"wallpaper_max_width":0,"wallpaper_max_height":0,"screensaver":false,"ringtone_wav":false,"wallpaper_gif":false,"screensaver_directdownload_size_limit":0,"picture_df_size_limit":0,"wallpaper_tiff":false,"screensaver_df_size_limit":0,"ringtone_awb":false,"ringtone":false,"wallpaper_inline_size_limit":0,"picture_directdownload_size_limit":0,"picture_png":false,"wallpaper_bmp":false,"picture_wbmp":false,"ringtone_df_size_limit":0,"picture_oma_size_limit":0,"picture_gif":false,"screensaver_png":false,"wallpaper_resize":"none","screensaver_greyscale":false,"ringtone_mmf":false,"ringtone_amr":false,"wallpaper":false,"ringtone_digiplug":false,"ringtone_spmidi":false,"ringtone_compactmidi":false,"ringtone_imelody":false,"screensaver_resize":"none","wallpaper_colors":2,"directdownload_support":false,"downloadfun_support":false,"screensaver_colors":2,"screensaver_gif":false,"oma_v_1_0_combined_delivery":false,"oma_v_1_0_separate_delivery":false,"oma_v_1_0_forwardlock":false,"streaming_vcodec_mpeg4_asp":-1,"streaming_video_size_limit":0,"streaming_mov":false,"streaming_wmv":"none","streaming_acodec_aac":"none","streaming_vcodec_h263_0":-1,"streaming_real_media":"none","streaming_3g2":false,"streaming_3gpp":false,"streaming_acodec_amr":"none","streaming_vcodec_h264_bp":-1,"streaming_vcodec_h263_3":-1,"streaming_preferred_protocol":"rtsp","streaming_vcodec_mpeg4_sp":-1,"streaming_flv":false,"streaming_video":false,"streaming_preferred_http_protocol":"none","streaming_mp4":false,"expiration_date":false,"utf8_support":false,"connectionless_cache_operation":false,"connectionless_service_load":false,"iso8859_support":false,"connectionoriented_confirmed_service_indication":false,"connectionless_service_indication":false,"ascii_support":false,"connectionoriented_confirmed_cache_operation":false,"connectionoriented_confirmed_service_load":false,"wap_push_support":false,"connectionoriented_unconfirmed_cache_operation":false,"connectionoriented_unconfirmed_service_load":false,"connectionoriented_unconfirmed_service_indication":false,"doja_1_5":false,"j2me_datefield_broken":false,"j2me_clear_key_code":0,"j2me_right_softkey_code":0,"j2me_heap_size":0,"j2me_canvas_width":0,"j2me_motorola_lwt":false,"doja_3_5":false,"j2me_wbmp":false,"j2me_rmf":false,"j2me_wma":false,"j2me_left_softkey_code":0,"j2me_jtwi":false,"j2me_jpg":false,"j2me_return_key_code":0,"j2me_real8":false,"j2me_max_record_store_size":0,"j2me_realmedia":false,"j2me_midp_1_0":false,"j2me_bmp3":false,"j2me_midi":false,"j2me_btapi":false,"j2me_locapi":false,"j2me_siemens_extension":false,"j2me_h263":false,"j2me_audio_capture_enabled":false,"j2me_midp_2_0":false,"j2me_datefield_no_accepts_null_date":false,"j2me_aac":false,"j2me_capture_image_formats":"none","j2me_select_key_code":0,"j2me_xmf":false,"j2me_photo_capture_enabled":false,"j2me_realaudio":false,"j2me_realvideo":false,"j2me_mp3":false,"j2me_png":false,"j2me_au":false,"j2me_screen_width":0,"j2me_mp4":false,"j2me_mmapi_1_0":false,"j2me_http":false,"j2me_imelody":false,"j2me_socket":false,"j2me_3dapi":false,"j2me_bits_per_pixel":0,"j2me_mmapi_1_1":false,"j2me_udp":false,"j2me_wav":false,"j2me_middle_softkey_code":0,"j2me_svgt":false,"j2me_gif":false,"j2me_siemens_color_game":false,"j2me_max_jar_size":0,"j2me_wmapi_1_0":false,"j2me_nokia_ui":false,"j2me_screen_height":0,"j2me_wmapi_1_1":false,"j2me_wmapi_2_0":false,"doja_1_0":false,"j2me_serial":false,"doja_2_0":false,"j2me_bmp":false,"j2me_amr":false,"j2me_gif89a":false,"j2me_cldc_1_0":false,"doja_2_1":false,"doja_3_0":false,"j2me_cldc_1_1":false,"doja_2_2":false,"doja_4_0":false,"j2me_3gpp":false,"j2me_video_capture_enabled":false,"j2me_canvas_height":0,"j2me_https":false,"j2me_mpeg4":false,"j2me_storage_size":0,"mms_3gpp":false,"mms_wbxml":false,"mms_symbian_install":false,"mms_png":false,"mms_max_size":0,"mms_rmf":false,"mms_nokia_operatorlogo":false,"mms_max_width":0,"mms_max_frame_rate":0,"mms_wml":false,"mms_evrc":false,"mms_spmidi":false,"mms_gif_static":false,"mms_max_height":0,"sender":false,"mms_video":false,"mms_vcard":false,"mms_nokia_3dscreensaver":false,"mms_qcelp":false,"mms_midi_polyphonic":false,"mms_wav":false,"mms_jpeg_progressive":false,"mms_jad":false,"mms_nokia_ringingtone":false,"built_in_recorder":false,"mms_midi_monophonic":false,"mms_3gpp2":false,"mms_wmlc":false,"mms_nokia_wallpaper":false,"mms_bmp":false,"mms_vcalendar":false,"mms_jar":false,"mms_ota_bitmap":false,"mms_mp3":false,"mms_mmf":false,"mms_amr":false,"mms_wbmp":false,"built_in_camera":false,"receiver":false,"mms_mp4":false,"mms_xmf":false,"mms_jpeg_baseline":false,"mms_midi_polyphonic_voices":0,"mms_gif_animated":false,"ems":false,"text_imelody":false,"nokiaring":false,"siemens_logo_height":29,"ems_variablesizedpictures":false,"sckl_groupgraphic":false,"siemens_ota":false,"sagem_v1":false,"largeoperatorlogo":false,"sagem_v2":false,"ems_version":0,"ems_odi":false,"nokiavcal":false,"operatorlogo":false,"siemens_logo_width":101,"ems_imelody":false,"sckl_vcard":false,"siemens_screensaver_width":101,"sckl_operatorlogo":false,"panasonic":false,"ems_upi":false,"nokiavcard":false,"callericon":false,"sms_enabled":true,"gprtf":false,"siemens_screensaver_height":50,"sckl_ringtone":false,"picturemessage":false,"sckl_vcalendar":false,"rmf":false,"qcelp":false,"awb":false,"smf":false,"wav":false,"nokia_ringtone":false,"aac":false,"digiplug":false,"sp_midi":false,"compactmidi":false,"voices":1,"mp3":false,"mld":false,"evrc":false,"amr":false,"xmf":false,"mmf":false,"imelody":false,"midi_monophonic":false,"au":false,"midi_polyphonic":false,"flash_lite_version":"","fl_wallpaper":false,"fl_browser":false,"fl_screensaver":false,"fl_standalone":false,"full_flash_support":false,"fl_sub_lcd":false,"css_gradient":"none","css_border_image":"none","css_rounded_corners":"none","css_spriting":false,"css_supports_width_as_percentage":true,"is_transcoder":false,"transcoder_ua_header":"user-agent","rss_support":false,"pdf_support":false,"playback_oma_size_limit":0,"playback_acodec_aac":"none","playback_vcodec_h263_3":-1,"playback_vcodec_mpeg4_asp":-1,"playback_mp4":false,"playback_3gpp":false,"playback_df_size_limit":0,"playback_acodec_amr":"none","playback_mov":false,"playback_wmv":"none","playback_acodec_qcelp":false,"progressive_download":false,"playback_directdownload_size_limit":0,"playback_real_media":"none","playback_3g2":false,"playback_vcodec_mpeg4_sp":-1,"playback_vcodec_h263_0":-1,"playback_inline_size_limit":0,"hinted_progressive_download":false,"playback_vcodec_h264_bp":-1,"streaming_video_acodec_amr":false,"streaming_video_vcodec_h263_0":false,"streaming_video_max_video_bit_rate":0,"video_acodec_amr":false,"video_vcodec_h263_3":false,"video_directdownload_size_limit":0,"video_max_width":0,"streaming_video_sqcif":false,"streaming_real_media_10":false,"has_pointing_device":false,"streaming_video_sqcif_max_width":0,"video_vcodec_mpeg4":false,"video_inline_size_limit":0,"streaming_video_vcodec_h263_3":false,"streaming_video_max_bit_rate":0,"video_vcodec_h264":"none","streaming_video_sqcif_max_height":0,"video_df_size_limit":0,"video_3gpp2":false,"video_real_media_8":false,"streaming_video_max_audio_bit_rate":0,"video_real_media_10":false,"video_real_media_9":false,"xhtml_supports_file_upload":false,"streaming_video_vcodec_mpeg4":false,"video_acodec_qcelp":false,"video_acodec_awb":false,"video_max_height":0,"video_mp4":false,"video_3gpp":false,"streaming_video_acodec_aac_ltp":false,"streaming_video_acodec_awb":false,"streaming_video_max_frame_rate":0,"streaming_real_media_8":false,"video_acodec_aac":false,"video_oma_size_limit":0,"streaming_video_acodec_aac":false,"streaming_video_min_video_bit_rate":0,"streaming_real_media_9":false,"video_vcodec_h263_0":false,"video_preferred_width":0,"video_sqcif":false,"video_qcif":false,"streaming_video_qcif":false,"video_preferred_height":0,"video_mov":false,"streaming_prefered_http_protocol":"none","streaming_video_vcodec_h264":"none","streaming_video_qcif_max_height":0,"streaming_video_qcif_max_width":0,"video_acodec_aac_ltp":false,"video_max_frame_rate":0,"video_wmv":false,"https_detectable":false,"canvas_support":"none","viewport_width":"","html_preferred_dtd":"html4","viewport_supported":false,"viewport_minimum_scale":"","viewport_initial_scale":"","mobileoptimized":false,"viewport_maximum_scale":"","viewport_userscalable":"","image_inlining":false,"handheldfriendly":false,"is_smarttv":false,"fm_tuner_support":false,"nfc_support":false,"ux_full_desktop":false,"ux_full_web_usability_index":-100,"num_queries":3,"match_type":"none","matcher":"none","match":false,"lookup_time":0.0031659603118896,"matcher_history":"CatchAllUserAgentMatcher(exact),CatchAllUserAgentMatcher(conclusive),CatchAllUserAgentMatcher(recovery),http_accept","actual_root_device":"","fall_back_tree":"generic"},"errors":{}}
@@ -0,0 +1 @@
1
+ {"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"is_wireless_device":false,"browser_id":"browser_root","fall_back":"root","user_agent":"","resolution_width": 800,"device_os_version":10.5},"errors":{}}
@@ -0,0 +1 @@
1
+ {"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"nokia_lumia_800_ver1","capabilities":{"id":"nokia_lumia_800_ver1","user_agent":"Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800)","fall_back":"generic_ms_nokia_phone_os7_5","actual_device_root":1,"browser_id":"browser_winmo_iemobile9","mobile_browser":"IEMobile","nokia_feature_pack":0,"device_os":"Windows Phone OS","nokia_series":0,"has_qwerty_keyboard":true,"pointing_method":"touchscreen","mobile_browser_version":"9.0","is_tablet":false,"nokia_edition":0,"uaprof":"http:\/\/nds1.nds.nokia.com\/uaprof\/Nokia800r100.xml","can_skip_aligned_link_row":true,"device_claims_web_support":true,"ununiqueness_handler":"","model_name":"Lumia 800","device_os_version":7.5,"uaprof2":"","is_wireless_device":true,"uaprof3":"","brand_name":"Nokia","model_extra_info":"","marketing_name":"","can_assign_phone_number":true,"release_date":"2011_october","unique":true,"icons_on_menu_items_support":false,"opwv_wml_extensions_support":false,"built_in_back_button_support":false,"proportional_font":false,"insert_br_element_after_widget_recommended":false,"wizards_recommended":false,"wml_can_display_images_and_text_on_same_line":false,"softkey_support":false,"wml_make_phone_call_string":"wtai:\/\/wp\/mc;","deck_prefetch_support":false,"menu_with_select_element_recommended":false,"numbered_menus":false,"card_title_support":true,"image_as_link_support":false,"wrap_mode_support":false,"table_support":true,"access_key_support":false,"wml_displays_image_in_center":false,"elective_forms_recommended":true,"times_square_mode_support":false,"break_list_of_links_with_br_element_recommended":true,"menu_with_list_of_links_recommended":true,"imode_region":"none","chtml_can_display_images_and_text_on_same_line":false,"chtml_displays_image_in_center":false,"chtml_make_phone_call_string":"tel:","chtml_table_support":false,"chtml_display_accesskey":false,"emoji":false,"xhtml_preferred_charset":"utf8","xhtml_supports_css_cell_table_coloring":false,"xhtml_select_as_radiobutton":false,"xhtml_autoexpand_select":false,"xhtml_avoid_accesskeys":false,"accept_third_party_cookie":true,"xhtml_make_phone_call_string":"tel:","xhtml_allows_disabled_form_elements":false,"xhtml_supports_invisible_text":false,"xhtml_select_as_dropdown":false,"cookie_support":true,"xhtml_send_mms_string":"none","xhtml_table_support":true,"xhtml_display_accesskey":false,"xhtml_can_embed_video":"none","xhtml_supports_iframe":"full","xhtmlmp_preferred_mime_type":"application\/vnd.wap.xhtml+xml","xhtml_supports_monospace_font":false,"xhtml_supports_inline_input":false,"xhtml_supports_forms_in_table":false,"xhtml_document_title_support":true,"xhtml_support_wml2_namespace":false,"xhtml_readable_background_color1":"#FFFFFF","xhtml_format_as_attribute":false,"xhtml_supports_table_for_layout":false,"xhtml_readable_background_color2":"#FFFFFF","xhtml_select_as_popup":false,"xhtml_send_sms_string":"none","xhtml_format_as_css_property":false,"xhtml_file_upload":"not_supported","xhtml_honors_bgcolor":false,"opwv_xhtml_extensions_support":false,"xhtml_marquee_as_css_property":false,"xhtml_nowrap_mode":false,"ajax_preferred_geoloc_api":"none","ajax_xhr_type":"standard","ajax_support_getelementbyid":true,"ajax_support_event_listener":true,"ajax_manipulate_dom":true,"ajax_support_javascript":true,"ajax_support_inner_html":true,"ajax_manipulate_css":true,"ajax_support_events":true,"html_web_3_2":false,"html_wi_imode_htmlx_1":false,"html_wi_imode_html_1":false,"html_wi_oma_xhtmlmp_1_0":true,"html_wi_imode_html_2":false,"html_wi_w3_xhtmlbasic":true,"html_wi_imode_compact_generic":false,"html_wi_imode_html_3":false,"wml_1_1":false,"html_wi_imode_html_4":false,"wml_1_2":false,"html_wi_imode_html_5":false,"wml_1_3":false,"preferred_markup":"html_web_4_0","xhtml_support_level":4,"voicexml":false,"html_wi_imode_htmlx_1_1":false,"multipart_support":false,"html_web_4_0":true,"time_to_live_support":false,"total_cache_disable_support":false,"physical_screen_height":161,"columns":16,"dual_orientation":true,"physical_screen_width":97,"rows":12,"max_image_width":320,"resolution_height":800,"resolution_width":480,"max_image_height":480,"greyscale":false,"jpg":true,"gif":true,"transparent_png_index":false,"epoc_bmp":false,"bmp":false,"wbmp":false,"gif_animated":true,"colors":65536,"svgt_1_1_plus":false,"svgt_1_1":false,"transparent_png_alpha":false,"png":true,"tiff":false,"emptyok":false,"empty_option_value_support":true,"basic_authentication_support":true,"post_method_support":true,"nokia_voice_call":false,"wta_pdc":false,"wta_voice_call":false,"wta_misc":false,"wta_phonebook":false,"phone_id_provided":false,"https_support":true,"sdio":false,"wifi":true,"has_cellular_radio":true,"max_data_rate":384,"vpn":false,"max_length_of_username":0,"max_url_length_bookmark":0,"max_no_of_bookmarks":0,"max_deck_size":100000,"max_url_length_cached_page":0,"max_length_of_password":0,"max_no_of_connection_settings":0,"max_url_length_in_requests":512,"max_object_size":0,"max_url_length_homepage":0,"video":false,"picture_bmp":false,"picture":false,"wallpaper_df_size_limit":0,"picture_preferred_width":0,"wallpaper_oma_size_limit":0,"picture_greyscale":false,"inline_support":false,"ringtone_qcelp":false,"screensaver_oma_size_limit":0,"screensaver_wbmp":false,"picture_resize":"none","picture_preferred_height":0,"ringtone_rmf":false,"wallpaper_wbmp":false,"wallpaper_jpg":false,"screensaver_bmp":false,"screensaver_max_width":0,"picture_inline_size_limit":0,"picture_colors":2,"ringtone_midi_polyphonic":false,"ringtone_midi_monophonic":false,"screensaver_preferred_height":0,"ringtone_voices":1,"ringtone_3gpp":false,"oma_support":false,"ringtone_inline_size_limit":0,"wallpaper_preferred_width":0,"wallpaper_greyscale":false,"screensaver_preferred_width":0,"wallpaper_preferred_height":0,"picture_max_width":0,"picture_jpg":false,"ringtone_aac":false,"ringtone_oma_size_limit":0,"wallpaper_directdownload_size_limit":0,"screensaver_inline_size_limit":0,"ringtone_xmf":false,"picture_max_height":0,"screensaver_max_height":0,"ringtone_mp3":false,"wallpaper_png":false,"screensaver_jpg":false,"ringtone_directdownload_size_limit":0,"wallpaper_max_width":0,"wallpaper_max_height":0,"screensaver":false,"ringtone_wav":false,"wallpaper_gif":false,"screensaver_directdownload_size_limit":0,"picture_df_size_limit":0,"wallpaper_tiff":false,"screensaver_df_size_limit":0,"ringtone_awb":false,"ringtone":false,"wallpaper_inline_size_limit":0,"picture_directdownload_size_limit":0,"picture_png":false,"wallpaper_bmp":false,"picture_wbmp":false,"ringtone_df_size_limit":0,"picture_oma_size_limit":0,"picture_gif":false,"screensaver_png":false,"wallpaper_resize":"none","screensaver_greyscale":false,"ringtone_mmf":false,"ringtone_amr":false,"wallpaper":false,"ringtone_digiplug":false,"ringtone_spmidi":false,"ringtone_compactmidi":false,"ringtone_imelody":false,"screensaver_resize":"none","wallpaper_colors":2,"directdownload_support":false,"downloadfun_support":false,"screensaver_colors":2,"screensaver_gif":false,"oma_v_1_0_combined_delivery":false,"oma_v_1_0_separate_delivery":false,"oma_v_1_0_forwardlock":false,"streaming_vcodec_mpeg4_asp":-1,"streaming_video_size_limit":0,"streaming_mov":false,"streaming_wmv":9,"streaming_acodec_aac":"lc","streaming_vcodec_h263_0":10,"streaming_real_media":"none","streaming_3g2":true,"streaming_3gpp":true,"streaming_acodec_amr":"nb","streaming_vcodec_h264_bp":0,"streaming_vcodec_h263_3":-1,"streaming_preferred_protocol":"http","streaming_vcodec_mpeg4_sp":0,"streaming_flv":false,"streaming_video":true,"streaming_preferred_http_protocol":"microsoft_smooth_streaming","streaming_mp4":true,"expiration_date":false,"utf8_support":false,"connectionless_cache_operation":false,"connectionless_service_load":true,"iso8859_support":false,"connectionoriented_confirmed_service_indication":false,"connectionless_service_indication":true,"ascii_support":false,"connectionoriented_confirmed_cache_operation":false,"connectionoriented_confirmed_service_load":false,"wap_push_support":true,"connectionoriented_unconfirmed_cache_operation":false,"connectionoriented_unconfirmed_service_load":false,"connectionoriented_unconfirmed_service_indication":false,"doja_1_5":false,"j2me_datefield_broken":false,"j2me_clear_key_code":0,"j2me_right_softkey_code":0,"j2me_heap_size":0,"j2me_canvas_width":0,"j2me_motorola_lwt":false,"doja_3_5":false,"j2me_wbmp":false,"j2me_rmf":false,"j2me_wma":false,"j2me_left_softkey_code":0,"j2me_jtwi":false,"j2me_jpg":false,"j2me_return_key_code":0,"j2me_real8":false,"j2me_max_record_store_size":0,"j2me_realmedia":false,"j2me_midp_1_0":false,"j2me_bmp3":false,"j2me_midi":false,"j2me_btapi":false,"j2me_locapi":false,"j2me_siemens_extension":false,"j2me_h263":false,"j2me_audio_capture_enabled":false,"j2me_midp_2_0":false,"j2me_datefield_no_accepts_null_date":false,"j2me_aac":false,"j2me_capture_image_formats":"none","j2me_select_key_code":0,"j2me_xmf":false,"j2me_photo_capture_enabled":false,"j2me_realaudio":false,"j2me_realvideo":false,"j2me_mp3":false,"j2me_png":false,"j2me_au":false,"j2me_screen_width":0,"j2me_mp4":false,"j2me_mmapi_1_0":false,"j2me_http":false,"j2me_imelody":false,"j2me_socket":false,"j2me_3dapi":false,"j2me_bits_per_pixel":0,"j2me_mmapi_1_1":false,"j2me_udp":false,"j2me_wav":false,"j2me_middle_softkey_code":0,"j2me_svgt":false,"j2me_gif":false,"j2me_siemens_color_game":false,"j2me_max_jar_size":0,"j2me_wmapi_1_0":false,"j2me_nokia_ui":false,"j2me_screen_height":0,"j2me_wmapi_1_1":false,"j2me_wmapi_2_0":false,"doja_1_0":false,"j2me_serial":false,"doja_2_0":false,"j2me_bmp":false,"j2me_amr":false,"j2me_gif89a":false,"j2me_cldc_1_0":false,"doja_2_1":false,"doja_3_0":false,"j2me_cldc_1_1":false,"doja_2_2":false,"doja_4_0":false,"j2me_3gpp":false,"j2me_video_capture_enabled":false,"j2me_canvas_height":0,"j2me_https":false,"j2me_mpeg4":false,"j2me_storage_size":0,"mms_3gpp":true,"mms_wbxml":false,"mms_symbian_install":false,"mms_png":true,"mms_max_size":614400,"mms_rmf":false,"mms_nokia_operatorlogo":false,"mms_max_width":1600,"mms_max_frame_rate":0,"mms_wml":false,"mms_evrc":false,"mms_spmidi":false,"mms_gif_static":true,"mms_max_height":1600,"sender":true,"mms_video":true,"mms_vcard":false,"mms_nokia_3dscreensaver":false,"mms_qcelp":false,"mms_midi_polyphonic":false,"mms_wav":true,"mms_jpeg_progressive":false,"mms_jad":false,"mms_nokia_ringingtone":false,"built_in_recorder":false,"mms_midi_monophonic":false,"mms_3gpp2":true,"mms_wmlc":false,"mms_nokia_wallpaper":false,"mms_bmp":true,"mms_vcalendar":false,"mms_jar":false,"mms_ota_bitmap":false,"mms_mp3":true,"mms_mmf":false,"mms_amr":false,"mms_wbmp":false,"built_in_camera":false,"receiver":true,"mms_mp4":true,"mms_xmf":false,"mms_jpeg_baseline":true,"mms_midi_polyphonic_voices":0,"mms_gif_animated":true,"ems":false,"text_imelody":false,"nokiaring":false,"siemens_logo_height":29,"ems_variablesizedpictures":false,"sckl_groupgraphic":false,"siemens_ota":false,"sagem_v1":false,"largeoperatorlogo":false,"sagem_v2":false,"ems_version":0,"ems_odi":false,"nokiavcal":false,"operatorlogo":false,"siemens_logo_width":101,"ems_imelody":false,"sckl_vcard":false,"siemens_screensaver_width":101,"sckl_operatorlogo":false,"panasonic":false,"ems_upi":false,"nokiavcard":false,"callericon":false,"sms_enabled":true,"gprtf":false,"siemens_screensaver_height":50,"sckl_ringtone":false,"picturemessage":false,"sckl_vcalendar":false,"rmf":false,"qcelp":false,"awb":false,"smf":false,"wav":true,"nokia_ringtone":false,"aac":true,"digiplug":false,"sp_midi":false,"compactmidi":false,"voices":1,"mp3":true,"mld":false,"evrc":false,"amr":false,"xmf":false,"mmf":false,"imelody":false,"midi_monophonic":false,"au":false,"midi_polyphonic":false,"flash_lite_version":"","fl_wallpaper":false,"fl_browser":false,"fl_screensaver":false,"fl_standalone":false,"full_flash_support":false,"fl_sub_lcd":false,"css_gradient":"none","css_border_image":"none","css_rounded_corners":"none","css_spriting":true,"css_supports_width_as_percentage":true,"is_transcoder":false,"transcoder_ua_header":"user-agent","rss_support":true,"pdf_support":true,"playback_oma_size_limit":0,"playback_acodec_aac":"lc","playback_vcodec_h263_3":-1,"playback_vcodec_mpeg4_asp":-1,"playback_mp4":true,"playback_3gpp":true,"playback_df_size_limit":0,"playback_acodec_amr":"nb","playback_mov":false,"playback_wmv":9,"playback_acodec_qcelp":false,"progressive_download":true,"playback_directdownload_size_limit":0,"playback_real_media":"none","playback_3g2":true,"playback_vcodec_mpeg4_sp":0,"playback_vcodec_h263_0":10,"playback_inline_size_limit":0,"hinted_progressive_download":false,"playback_vcodec_h264_bp":0,"streaming_video_acodec_amr":false,"streaming_video_vcodec_h263_0":false,"streaming_video_max_video_bit_rate":0,"video_acodec_amr":false,"video_vcodec_h263_3":false,"video_directdownload_size_limit":0,"video_max_width":0,"streaming_video_sqcif":false,"streaming_real_media_10":false,"has_pointing_device":false,"streaming_video_sqcif_max_width":0,"video_vcodec_mpeg4":false,"video_inline_size_limit":0,"streaming_video_vcodec_h263_3":false,"streaming_video_max_bit_rate":0,"video_vcodec_h264":"none","streaming_video_sqcif_max_height":0,"video_df_size_limit":0,"video_3gpp2":false,"video_real_media_8":false,"streaming_video_max_audio_bit_rate":0,"video_real_media_10":false,"video_real_media_9":false,"xhtml_supports_file_upload":false,"streaming_video_vcodec_mpeg4":false,"video_acodec_qcelp":false,"video_acodec_awb":false,"video_max_height":0,"video_mp4":false,"video_3gpp":false,"streaming_video_acodec_aac_ltp":false,"streaming_video_acodec_awb":false,"streaming_video_max_frame_rate":0,"streaming_real_media_8":false,"video_acodec_aac":false,"video_oma_size_limit":0,"streaming_video_acodec_aac":false,"streaming_video_min_video_bit_rate":0,"streaming_real_media_9":false,"video_vcodec_h263_0":false,"video_preferred_width":0,"video_sqcif":false,"video_qcif":false,"streaming_video_qcif":false,"video_preferred_height":0,"video_mov":false,"streaming_prefered_http_protocol":"microsoft_smooth_streaming","streaming_video_vcodec_h264":"none","streaming_video_qcif_max_height":0,"streaming_video_qcif_max_width":0,"video_acodec_aac_ltp":false,"video_max_frame_rate":0,"video_wmv":false,"https_detectable":false,"canvas_support":"none","viewport_width":"device_width_token","html_preferred_dtd":"html4","viewport_supported":true,"viewport_minimum_scale":"","viewport_initial_scale":"","mobileoptimized":false,"viewport_maximum_scale":"","viewport_userscalable":"no","image_inlining":true,"handheldfriendly":false,"is_smarttv":false,"fm_tuner_support":false,"nfc_support":false,"ux_full_desktop":false,"ux_full_web_usability_index":-50,"num_queries":2,"match_type":"exact","matcher":"WindowsPhoneUserAgentMatcher","match":true,"lookup_time":0.0045168399810791,"matcher_history":"WindowsPhoneUserAgentMatcher(exact)","actual_root_device":"nokia_lumia_800_ver1","fall_back_tree":"nokia_lumia_800_ver1,generic_ms_nokia_phone_os7_5,generic_ms_phone_os7_5,generic_ms_phone_os7,generic_xhtml,generic_mobile,generic"},"errors":{}}
@@ -0,0 +1 @@
1
+ {"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"nokia_lumia_800_ver1","capabilities":{"is_wireless_device":true,"browser_id":"browser_winmo_iemobile9","fall_back":"generic_ms_nokia_phone_os7_5","user_agent":"Mozilla\/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident\/5.0; IEMobile\/9.0; NOKIA; Lumia 800)"},"errors":{}}
@@ -0,0 +1 @@
1
+ {"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"release_date": "1994_january","is_wireless_device":"true","is_tablet":"false","resolution_width": "800"},"errors":{}}
@@ -0,0 +1,20 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ require 'simplecov'
6
+ SimpleCov.start do
7
+ add_filter "/spec/"
8
+ end
9
+
10
+
11
+ require 'wurfl_cloud'
12
+ require 'webmock/rspec'
13
+ require 'rack'
14
+
15
+ # Load support files
16
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
17
+
18
+ RSpec.configure do |config|
19
+ config.include(WurflCloud::Spec::RackHelpers)
20
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+ # adapted from warden
3
+ #
4
+ # Copyright (c) 2009 Daniel Neighman
5
+ #
6
+ # Permission is hereby granted, free of charge, to any person obtaining
7
+ # a copy of this software and associated documentation files (the
8
+ # "Software"), to deal in the Software without restriction, including
9
+ # without limitation the rights to use, copy, modify, merge, publish,
10
+ # distribute, sublicense, and/or sell copies of the Software, and to
11
+ # permit persons to whom the Software is furnished to do so, subject to
12
+ # the following conditions:
13
+ #
14
+ # The above copyright notice and this permission notice shall be
15
+ # included in all copies or substantial portions of the Software.
16
+ #
17
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
+ #
25
+ require 'wurfl_cloud/rack/cache_manager'
26
+
27
+ module WurflCloud::Spec
28
+ module RackHelpers
29
+ FAILURE_APP = lambda{|e|[401, {"Content-Type" => "text/plain"}, ["You Fail!"]] }
30
+
31
+ def env_with_params(path = "/", params = {}, env = {})
32
+ method = params.delete(:method) || "GET"
33
+ env = { 'HTTP_VERSION' => '1.1', 'REQUEST_METHOD' => "#{method}" }.merge(env)
34
+ Rack::MockRequest.env_for("#{path}?#{Rack::Utils.build_query(params)}", env)
35
+ end
36
+
37
+ def setup_rack(app = nil, opts = {}, &block)
38
+ app ||= block if block_given?
39
+
40
+ opts[:failure_app] ||= failure_app
41
+
42
+ Rack::Builder.new do
43
+ use opts[:session] || WurflCloud::Spec::RackHelpers::Session
44
+ use WurflCloud::Rack::CacheManager, opts
45
+ run app
46
+ end
47
+ end
48
+
49
+ def valid_response
50
+ Rack::Response.new("OK").finish
51
+ end
52
+
53
+ def failure_app
54
+ WurflCloud::Spec::RackHelpers::FAILURE_APP
55
+ end
56
+
57
+ def success_app
58
+ lambda{|e| [200, {"Content-Type" => "text/plain"}, ["You Win"]]}
59
+ end
60
+
61
+ class Session
62
+ attr_accessor :app
63
+ def initialize(app,configs = {})
64
+ @app = app
65
+ end
66
+
67
+ def call(e)
68
+ e['rack.session'] ||= {}
69
+ @app.call(e)
70
+ end
71
+ end # session
72
+
73
+
74
+ def authenticated_uri
75
+ c = WurflCloud.configuration
76
+ "#{c.schema}://#{c.api_user}:#{c.api_password}@#{c.host}:#{c.port}#{c.path}"
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,26 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ class String
6
+ class << self
7
+ def random(length=20)
8
+ self.generic_random(length, ("0".."z"))
9
+ end
10
+ def az_random(length=20)
11
+ self.generic_random(length, ("a".."z"))
12
+ end
13
+ def aznum_random(length=20)
14
+ self.generic_random(length, ("a".."z").to_a + ("0".."9").to_a)
15
+ end
16
+ def az_random_with_num(length=20, num_lenght=20)
17
+ self.generic_random(length, ("a".."z").to_a)+self.generic_random(length, ("0".."9").to_a)
18
+ end
19
+ def generic_random(length,char_range)
20
+ chars = char_range.to_a
21
+ Array.new.tap do |a|
22
+ 1.upto(length) { |i| a << chars[rand(chars.size-1)]}
23
+ end.join
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,200 @@
1
+ #
2
+ # This software is the Copyright of ScientiaMobile, Inc.
3
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
4
+ #
5
+ require 'spec_helper'
6
+ require 'wurfl_cloud/cache/local_memory'
7
+
8
+ describe WurflCloud::Client do
9
+ subject { WurflCloud::Client.new(WurflCloud::Environment.new, nil) }
10
+
11
+ it "should contain a device_capabilities object" do
12
+ subject.device_capabilities.should be_instance_of(WurflCloud::DeviceCapabilities)
13
+ end
14
+
15
+ it "should delegate the [] method to the device_capabilities object" do
16
+ capability_name = String.random
17
+ subject.device_capabilities.should_receive(:[]).with(capability_name)
18
+ subject[capability_name]
19
+ end
20
+
21
+ it "should have a read_from_cache method" do
22
+ subject.should respond_to(:read_from_cache)
23
+ end
24
+
25
+ context "the detect_device method" do
26
+ it "should be defined with 2 parameters" do
27
+ WurflCloud::Client.should respond_to(:detect_device).with(2).arguments
28
+ end
29
+
30
+ end
31
+
32
+ context "when using with the default null cache" do
33
+ before(:each) do
34
+ @http_env = {
35
+ "HTTP_USER_AGENT"=>String.random,
36
+ "HTTP_ACCEPT"=>String.random,
37
+ "HTTP_X_WAP_PROFILE"=>String.random,
38
+ "REMOTE_ADDR"=>String.random
39
+ }
40
+ @environment = WurflCloud::Environment.new(@http_env)
41
+ @cache = WurflCloud.configuration.cache(nil)
42
+
43
+ @device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
44
+
45
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => @device_data)
46
+
47
+ @wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
48
+
49
+ end
50
+
51
+ it "should validate the cache when loading from server" do
52
+ @cache.should_receive(:validate).with(1330016154)
53
+ @wurfl_client.load_from_server!
54
+ end
55
+
56
+ it "should return an instance of the client class" do
57
+ @wurfl_client.should be_instance_of(WurflCloud::Client)
58
+ end
59
+
60
+ it "should call the remote webservice" do
61
+ WebMock.should have_requested(:get, authenticated_uri)
62
+ end
63
+
64
+ it "should call the remote webservice each time detect_device is called" do
65
+ WurflCloud::Client.detect_device(@environment, @cache)
66
+ WebMock.should have_requested(:get, authenticated_uri).times(2)
67
+ end
68
+
69
+
70
+ it "should pass the correct headers" do
71
+ headers = {
72
+ 'User-Agent' => @http_env["HTTP_USER_AGENT"],
73
+ 'X-Cloud-Client' => "WurflCloudClient/Ruby_#{WurflCloud::VERSION}",
74
+ 'X-Forwarded-For' => @http_env["REMOTE_ADDR"],
75
+ 'X-Accept' => @http_env["HTTP_ACCEPT"],
76
+ 'X-Wap-Profile' => @http_env["HTTP_X_WAP_PROFILE"],
77
+ }
78
+ stub_request(:any, authenticated_uri).with(:headers=>headers).to_return(:status=>200, :body => @device_data)
79
+ WurflCloud::Client.detect_device(@environment, @cache)
80
+ end
81
+
82
+ { "is_wireless_device"=>false,
83
+ "browser_id"=>"browser_root",
84
+ "fall_back"=>"root",
85
+ "user_agent"=>"",
86
+ "resolution_width"=>90
87
+ }.each do |key, value|
88
+ it "should return the right values for the capability #{key}" do
89
+ @wurfl_client[key].should ==value
90
+ end
91
+ it "should not call the webservice to read a capability that's present in the answer" do
92
+ value = @wurfl_client[key]
93
+ WebMock.should have_requested(:get, authenticated_uri).times(1)
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ context "when using with a simple local memory cache" do
100
+
101
+ before(:each) do
102
+ @http_env = {
103
+ "HTTP_USER_AGENT"=>String.random,
104
+ "HTTP_ACCEPT"=>String.random,
105
+ "HTTP_X_WAP_PROFILE"=>String.random,
106
+ "REMOTE_ADDR"=>String.random
107
+ }
108
+ @environment = WurflCloud::Environment.new(@http_env)
109
+ @cache = WurflCloud::Cache::LocalMemory.new
110
+
111
+ @device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
112
+
113
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => @device_data)
114
+ @wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
115
+ end
116
+
117
+
118
+ it "should call the remote webservice once if the same agent is detected twice" do
119
+ WurflCloud::Client.detect_device(@environment, @cache)
120
+ WebMock.should have_requested(:get, authenticated_uri).times(1)
121
+ end
122
+
123
+ context "requesting a non existent capability" do
124
+ context "just after the capabilities have been read from the server" do
125
+ it "should not call again the webservice" do
126
+ value = @wurfl_client['my_non_existent_capability']
127
+ WebMock.should have_requested(:get, authenticated_uri).times(1)
128
+ end
129
+ it "should return nil" do
130
+ @wurfl_client['my_non_existent_capability'].should be_nil
131
+ end
132
+ end
133
+
134
+ context "detecting the device from the cache" do
135
+ before(:each) do
136
+ @wurfl_client = WurflCloud::Client.detect_device(@environment, @cache)
137
+ end
138
+
139
+ it "should call again the webservice" do
140
+ value = @wurfl_client['my_non_existent_capability']
141
+ WebMock.should have_requested(:get, authenticated_uri).times(2)
142
+ end
143
+
144
+ it "should return nil if it doesn't exist" do
145
+ @wurfl_client['my_non_existent_capability'].should be_nil
146
+ end
147
+
148
+ it "should return the right value if exists" do
149
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"my_non_existent_capability":"OK"},"errors":{}}})
150
+ @wurfl_client['my_non_existent_capability'].should =="OK"
151
+ end
152
+
153
+ it "should call the webservice only once for each access to the capability value" do
154
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{"my_non_existent_capability":"OK"},"errors":{}}})
155
+ value = @wurfl_client['my_non_existent_capability']
156
+ value = @wurfl_client['my_non_existent_capability']
157
+ WebMock.should have_requested(:get, authenticated_uri).times(2)
158
+ end
159
+ end
160
+ end
161
+ end
162
+
163
+ context "when the webservice has errors" do
164
+ before(:each) do
165
+ @http_env = {
166
+ "HTTP_USER_AGENT"=>String.random,
167
+ "HTTP_ACCEPT"=>String.random,
168
+ "HTTP_X_WAP_PROFILE"=>String.random,
169
+ "REMOTE_ADDR"=>String.random
170
+ }
171
+ @environment = WurflCloud::Environment.new(@http_env)
172
+ @cache = WurflCloud.configuration.cache(nil)
173
+
174
+ @device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
175
+ end
176
+
177
+ it "should raise WurflCloud::Errors::ConnectionError if there are connection timeouts" do
178
+ stub_request(:any, authenticated_uri).to_timeout
179
+
180
+ expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
181
+ end
182
+ it "should raise WurflCloud::Errors::ConnectionError if there are connection errors" do
183
+ stub_request(:any, authenticated_uri).to_raise("some error")
184
+
185
+ expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
186
+ end
187
+ it "should raise WurflCloud::Errors::ConnectionError if there are server errors" do
188
+ stub_request(:any, authenticated_uri).to_return(:status=>500)
189
+
190
+ expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::ConnectionError)
191
+ end
192
+ it "should raise WurflCloud::Errors::MalformedResponseError if there are unparsable responses" do
193
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => %{badjson})
194
+
195
+ expect { WurflCloud::Client.detect_device(@environment, @cache) }.to raise_error(WurflCloud::Errors::MalformedResponseError)
196
+ end
197
+
198
+ end
199
+
200
+ end