wurfl_cloud_client_light 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,111 @@
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
+ describe WurflCloud::Configuration do
7
+ after(:all) do
8
+ WurflCloud.configuration = WurflCloud::Configuration.new
9
+ end
10
+
11
+ it "should give a new instance if non defined" do
12
+ WurflCloud.configuration = nil
13
+ WurflCloud.configuration.should be_a(WurflCloud::Configuration)
14
+ end
15
+
16
+ context "the configure method" do
17
+ it "should yield an instance of the configuration" do
18
+ WurflCloud.configure do |config|
19
+ config.should be_a(WurflCloud::Configuration)
20
+ end
21
+ end
22
+
23
+ it "should allow writing of the configuration" do
24
+ str = String.random
25
+ WurflCloud.configure do |config|
26
+ config.host = str
27
+ end
28
+ WurflCloud.configuration.host.should ==str
29
+ end
30
+ end
31
+
32
+ {
33
+ :host => 'api.wurflcloud.com',
34
+ :path => '/v1/json',
35
+ :port => 80,
36
+ :schema => 'http',
37
+ :api_type => 'http',
38
+ :search_parameter => 'search:(%{capabilities})',
39
+ :search_parameter_separator => ',',
40
+ :cache_class => WurflCloud::Cache::Null,
41
+ :cache_options => {}
42
+ }.each do |key, value|
43
+
44
+ it "should have the right default for #{key}" do
45
+ subject.send(key).should ==value
46
+ end
47
+
48
+ it "should allow overriding default of #{key}" do
49
+ v = String.random
50
+ subject.send(:"#{key}=", v)
51
+ subject.send(key).should ==v
52
+ end
53
+
54
+ end
55
+
56
+ it "should return the correct api_uri" do
57
+ c = WurflCloud.configuration
58
+ c.schema = String.random
59
+ c.host = String.random
60
+ c.path = String.random
61
+ c.port = String.random
62
+ c.api_uri.should == "#{c.schema}://#{c.host}:#{c.port}#{c.path}"
63
+ end
64
+
65
+ context "the cache method" do
66
+
67
+ it "should return a @cache_class object " do
68
+ subject.cache(Object.new).should be_a(subject.cache_class)
69
+ end
70
+
71
+ it "should call the initialize method of the cache class " do
72
+ env = Object.new
73
+ subject.cache_class.should_receive(:new).with(subject.cache_options, env)
74
+ cache = subject.cache(env)
75
+ end
76
+
77
+ end
78
+ context "the api_key method" do
79
+
80
+ it "should have the right default" do
81
+ subject.api_key.should =='100000:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
82
+ end
83
+
84
+ it "should allow overriding the default" do
85
+ u = 100000+rand(99999)
86
+ p = String.az_random(32)
87
+ subject.api_key = "#{u}:#{p}"
88
+ subject.api_key.should =="#{u}:#{p}"
89
+ end
90
+
91
+ it "should throw an exception if called with a key with the worng format" do
92
+ expect { subject.api_key = "a wrong api key" }.to raise_error(WurflCloud::Errors::ConfigurationError)
93
+ end
94
+
95
+ it "should have set the api_user value" do
96
+ u = 100000+rand(99999)
97
+ p = String.az_random(32)
98
+ subject.api_key = "#{u}:#{p}"
99
+ subject.api_user.should ==u
100
+ end
101
+
102
+ it "should set the api_password value" do
103
+ u = 100000+rand(99999)
104
+ p = String.az_random(32)
105
+ subject.api_key = "#{u}:#{p}"
106
+ subject.api_password.should ==p
107
+ end
108
+
109
+ end
110
+ end
111
+
@@ -0,0 +1,44 @@
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
+ describe WurflCloud::Cache::Cookie do
7
+ subject { WurflCloud::Cache::Cookie.new({}, {}) }
8
+
9
+ context "the object" do
10
+ it { should respond_to(:[]).with(1).argument }
11
+ it { should respond_to(:[]=).with(2).arguments }
12
+ it { should respond_to(:mtime).with(0).arguments }
13
+ it { should respond_to(:mtime=).with(1).argument }
14
+
15
+ it "should not throw errors calling []=" do
16
+ expect { subject[String.random] = String.random }.to_not raise_error
17
+ end
18
+
19
+ it "should store values" do
20
+ key = String.random
21
+ subject[key] = String.random
22
+ subject[key].should_not be_nil
23
+ end
24
+
25
+ end
26
+
27
+ context "for the environment" do
28
+ before(:each) do
29
+ @env = Hash.new
30
+ @cache = WurflCloud::Cache::Cookie.new({}, @env)
31
+ end
32
+
33
+ it "should read the value from the wurfl.cookie.device_cache env variable" do
34
+ @env['wurfl.cookie.device_cache'] = String.random
35
+ @cache[String.random].should ==@env['wurfl.cookie.device_cache']
36
+ end
37
+
38
+ it "should set the value into the wurfl.cookie.device_cache env variable" do
39
+ value = String.random
40
+ @cache[String.random] = value
41
+ @env['wurfl.cookie.device_cache'].should ==value
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,136 @@
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
+ describe WurflCloud::DeviceCapabilities do
7
+
8
+ context "the object" do
9
+ it { should respond_to(:[]).with(1).argument }
10
+ it { should respond_to(:[]=).with(2).arguments }
11
+ it { should respond_to(:has_key?).with(1).argument }
12
+ it { should respond_to(:merge).with(1).argument }
13
+ it { should respond_to(:empty?).with(0).arguments }
14
+ it { should respond_to(:mtime).with(0).arguments }
15
+ it { should respond_to(:id).with(0).arguments }
16
+ it { should respond_to(:user_agent).with(0).arguments }
17
+
18
+ it "should store a value by key" do
19
+ key = String.random
20
+ val = String.random
21
+ subject[key] = val
22
+ subject[key].should ==val
23
+ end
24
+
25
+ it "should return true from has_key? if the key is set" do
26
+ key = String.random
27
+ subject[key] = nil
28
+ subject.has_key?(key).should be_true
29
+ end
30
+
31
+ context "when merging" do
32
+ before(:each) do
33
+ subject = WurflCloud::DeviceCapabilities.new
34
+ @old_key = String.random
35
+ @old_val = String.random
36
+ subject[@old_key] = @old_val
37
+
38
+ @new_key = String.random
39
+ @new_val = String.random
40
+ end
41
+
42
+
43
+ context "another DeviceCapabilities object" do
44
+ it "should store a value when merged" do
45
+ subject_2 = WurflCloud::DeviceCapabilities.new
46
+ subject_2[@new_key] = @new_val
47
+ subject.merge(subject_2)
48
+ subject[@new_key].should ==@new_val
49
+ end
50
+
51
+ it "should overwrite a value when merged" do
52
+ subject_2 = WurflCloud::DeviceCapabilities.new
53
+ subject_2[@old_key] = @new_val
54
+ subject.merge(subject_2)
55
+ subject[@old_key].should ==@new_val
56
+ end
57
+ end
58
+
59
+ end
60
+
61
+ context "the empty? method" do
62
+ it "should return true if there are no capabilities defined" do
63
+ WurflCloud::DeviceCapabilities.new.empty?.should be_true
64
+ end
65
+
66
+ it "should return false if there are capabilities defined" do
67
+ subject[String.random] = String.random
68
+ subject.empty?.should be_false
69
+ end
70
+ end
71
+ end
72
+
73
+ context "the parse class method" do
74
+ subject { WurflCloud::DeviceCapabilities }
75
+
76
+ before(:each) do
77
+ @generic_filtered_json = File.new("#{File.dirname(__FILE__)}/../files/generic_filtered.json").read
78
+ end
79
+ it "should exist" do
80
+ WurflCloud::DeviceCapabilities.should respond_to(:parse).with(1).argument
81
+ end
82
+
83
+ it "shuould return a DeviceCapabilities object" do
84
+ WurflCloud::DeviceCapabilities.parse(@generic_filtered_json).should be_a(WurflCloud::DeviceCapabilities)
85
+ end
86
+
87
+ context "the parse result" do
88
+ before(:each) do
89
+ @parsed = WurflCloud::DeviceCapabilities.parse(@generic_filtered_json)
90
+ end
91
+ { "is_wireless_device"=>false,
92
+ "browser_id"=>"browser_root",
93
+ "fall_back"=>"root",
94
+ "user_agent"=>"",
95
+ "device_os_version"=>10.5,
96
+ "resolution_width"=>800
97
+ }.each do |key, value|
98
+ it "should populate the DeviceCapabilities key #{key} with the value #{value.to_s.empty? ? "''" : value} from the json pased in" do
99
+ @parsed[key].should ==value
100
+ end
101
+ end
102
+
103
+ it "should have the mtime set to a Time object" do
104
+ @parsed.mtime.should ==Time.at(1330016154)
105
+ end
106
+
107
+ it "should return the correct wurfl id calling its is method" do
108
+ @parsed.id.should =="generic"
109
+ end
110
+ end
111
+
112
+ context "parsing capabilities with boolean and numeric casted to strings" do
113
+ before(:each) do
114
+ @parsed = WurflCloud::DeviceCapabilities.parse(File.new("#{File.dirname(__FILE__)}/../files/strange_values.json").read)
115
+ end
116
+ { "is_tablet"=>false,
117
+ "is_wireless_device"=>true,
118
+ "resolution_width"=>800,
119
+ "release_date"=>"1994_january"
120
+ }.each do |key, value|
121
+ it "should populate the DeviceCapabilities key #{key} with the correct value #{value.to_s.empty? ? "''" : value} from the json pased in" do
122
+ @parsed[key].should ==value
123
+ end
124
+ end
125
+ end
126
+
127
+ it "should be empty if no capabilities defined in the json" do
128
+ @parsed = WurflCloud::DeviceCapabilities.parse(%{{"apiVersion":"WurflCloud 1.3.2","mtime":1330016154,"id":"generic","capabilities":{},"errors":{}}})
129
+ end
130
+
131
+ it "should raise and error if the json is not in the correct format" do
132
+ expect { WurflCloud::DeviceCapabilities.parse(%{}) }.to raise_error(WurflCloud::Errors::MalformedResponseError)
133
+ end
134
+
135
+ end
136
+ end
@@ -0,0 +1,86 @@
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
+ describe WurflCloud::Environment do
7
+
8
+ context "the class" do
9
+ it "should respond to new with 1 argument" do
10
+ WurflCloud::Environment.should respond_to(:new).with(1).argument
11
+ end
12
+ end
13
+
14
+ context "the object" do
15
+ [
16
+ :user_agent,
17
+ :x_forwarded_for,
18
+ :x_accept,
19
+ :x_wap_profile
20
+ ].each do |header|
21
+ it { should respond_to(header) }
22
+ it "should return nil if not set in the constructor" do
23
+ subject.send(header).should be_nil
24
+ end
25
+ end
26
+
27
+ context "the user_agent" do
28
+ [
29
+ 'HTTP_X_DEVICE_USER_AGENT',
30
+ 'HTTP_X_ORIGINAL_USER_AGENT',
31
+ 'HTTP_X_OPERAMINI_PHONE_UA',
32
+ 'HTTP_X_SKYFIRE_PHONE',
33
+ 'HTTP_X_BOLT_PHONE_UA',
34
+ 'HTTP_USER_AGENT'
35
+ ].each do |user_agent_param|
36
+ it "should be read from #{user_agent_param} " do
37
+ env = {user_agent_param=>String.random}
38
+ WurflCloud::Environment.new(env).user_agent.should ==env[user_agent_param]
39
+ end
40
+ end
41
+
42
+ end
43
+
44
+ context "the x_accept" do
45
+ it "should be read from HTTP_ACCEPT " do
46
+ env = {"HTTP_ACCEPT"=>String.random}
47
+ WurflCloud::Environment.new(env).x_accept.should ==env["HTTP_ACCEPT"]
48
+ end
49
+ end
50
+
51
+ context "the x_wap_profile" do
52
+ it "should be read from HTTP_X_WAP_PROFILE if present and HTTP_PROFILE is null" do
53
+ env = {"HTTP_X_WAP_PROFILE"=>String.random}
54
+ WurflCloud::Environment.new(env).x_wap_profile.should ==env["HTTP_X_WAP_PROFILE"]
55
+ end
56
+
57
+ it "should be read from HTTP_X_WAP_PROFILE if present and HTTP_PROFILE is present" do
58
+ env = {"HTTP_X_WAP_PROFILE"=>String.random, "HTTP_PROFILE"=>String.random}
59
+ WurflCloud::Environment.new(env).x_wap_profile.should ==env["HTTP_X_WAP_PROFILE"]
60
+ end
61
+
62
+ it "should be read from HTTP_PROFILE if present and HTTP_X_WAP_PROFILE is nil" do
63
+ env = {"HTTP_PROFILE"=>String.random}
64
+ WurflCloud::Environment.new(env).x_wap_profile.should ==env["HTTP_PROFILE"]
65
+ end
66
+ end
67
+
68
+ context "the x_forwarded_for" do
69
+ it "should be the REMOTE_ADDR if present and HTTP_X_FORWARDED_FOR is absent" do
70
+ env = {"REMOTE_ADDR"=>String.random}
71
+ WurflCloud::Environment.new(env).x_forwarded_for.should ==env["REMOTE_ADDR"]
72
+ end
73
+
74
+ it "should be the REMOTE_ADDR, HTTP_X_FORWARDED_FOR if both are present" do
75
+ env = {"REMOTE_ADDR"=>String.random, "HTTP_X_FORWARDED_FOR"=>String.random}
76
+ WurflCloud::Environment.new(env).x_forwarded_for.should =="#{env["REMOTE_ADDR"]}, #{env["HTTP_X_FORWARDED_FOR"]}"
77
+ end
78
+
79
+ it "should be nil if REMOTE_ADDR and HTTP_X_FORWARDED_FOR is present" do
80
+ env = {"HTTP_X_FORWARDED_FOR"=>String.random}
81
+ WurflCloud::Environment.new(env).x_forwarded_for.should be_nil
82
+ end
83
+ end
84
+
85
+ end
86
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This software is the Copyright of ScientiaMobile, Inc.
4
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
5
+ #
6
+ require 'spec_helper'
7
+ require 'wurfl_cloud/helper'
8
+
9
+ describe WurflCloud::Helper do
10
+ include WurflCloud::Helper
11
+
12
+ context "the wurfl_detect_device method" do
13
+
14
+ it "should return a WurflCloud::Client object" do
15
+
16
+ cookie = {'date_set' => Time.now.to_i, 'capabilities' => {'name'=>'example'}}
17
+ env = env_with_params("/", {}, {"HTTP_USER_AGENT"=>String.random, "HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
18
+
19
+ @device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
20
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => @device_data)
21
+
22
+ @wurfl_device = wurfl_detect_device(env)
23
+ @wurfl_device.should be_instance_of(WurflCloud::Client)
24
+
25
+ end
26
+ end
27
+
28
+ end
@@ -0,0 +1,30 @@
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
+ describe WurflCloud::Cache::Null do
7
+ subject { WurflCloud::Cache::Null.new({}, Object.new) }
8
+
9
+ context "the object" do
10
+ it { should respond_to(:[]).with(1).argument }
11
+ it { should respond_to(:[]=).with(2).arguments }
12
+ it { should respond_to(:mtime).with(0).arguments }
13
+ it { should respond_to(:mtime=).with(1).argument }
14
+
15
+ it "should not throw errors calling []=" do
16
+ expect { subject[String.random] = String.random }.to_not raise_error
17
+ end
18
+
19
+ it "should not store values" do
20
+ key = String.random
21
+ subject[key] = String.random
22
+ subject[key].should be_nil
23
+ end
24
+
25
+ it "should not store the mtime" do
26
+ subject.mtime = rand
27
+ subject.mtime.should be_nil
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This software is the Copyright of ScientiaMobile, Inc.
4
+ # Please refer to the LICENSE.txt file distributed with the software for licensing information
5
+ #
6
+ require 'spec_helper'
7
+
8
+ describe WurflCloud::Rack::CacheManager do
9
+
10
+ context "the wurfl.cookie.device_cache env parameter" do
11
+
12
+ it "should be inserted if the cookie exists" do
13
+ cookie = {'date_set' => Time.now.to_i, 'capabilities' => {'name'=>'example'}}
14
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
15
+ setup_rack(success_app).call(env)
16
+ env["wurfl.cookie.device_cache"].should_not be_nil
17
+ end
18
+
19
+ it "should be decoded from json" do
20
+ cookie = {'date_set' => Time.now.to_i, 'capabilities' => {'name'=>'example'}}
21
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
22
+ setup_rack(success_app).call(env)
23
+ env["wurfl.cookie.device_cache"].should =={'name'=>'example'}
24
+ end
25
+
26
+ it "should be nil if it doesn't exist" do
27
+ env = env_with_params("/", {}, {})
28
+ setup_rack(success_app).call(env)
29
+ env["wurfl.cookie.device_cache"].should be_nil
30
+ end
31
+
32
+ it "should be nil if not a valid json object" do
33
+ cookie = {}
34
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape("{}")}"})
35
+ setup_rack(success_app).call(env)
36
+ env["wurfl.cookie.device_cache"].should be_nil
37
+ end
38
+
39
+ it "should be nil if it lacks the date_set field" do
40
+ cookie = {'capabilities' => {}}
41
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
42
+ setup_rack(success_app).call(env)
43
+ env["wurfl.cookie.device_cache"].should be_nil
44
+ end
45
+
46
+ it "should be nil if it lacks the capabilities field" do
47
+ cookie = {'date_set' => Time.now.to_i}
48
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
49
+ setup_rack(success_app).call(env)
50
+ env["wurfl.cookie.device_cache"].should be_nil
51
+ end
52
+
53
+ it "should be nil if the capabilities field is empty" do
54
+ cookie = {'date_set' => (Time.now-WurflCloud::Rack::CacheManager::EXPIRY-1).to_i, 'capabilities' => {}}
55
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
56
+ setup_rack(success_app).call(env)
57
+ env["wurfl.cookie.device_cache"].should be_nil
58
+ end
59
+
60
+ it "should be nil if the cookie was expired" do
61
+ cookie = {'date_set' => (Time.now-WurflCloud::Rack::CacheManager::EXPIRY-1).to_i, 'capabilities' => {'name'=>'example'}}
62
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
63
+ setup_rack(success_app).call(env)
64
+ env["wurfl.cookie.device_cache"].should be_nil
65
+ end
66
+
67
+ end
68
+
69
+ end