wurfl_cloud_client 1.0.1

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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +40 -0
  5. data/Rakefile +19 -0
  6. data/lib/wurfl_cloud.rb +49 -0
  7. data/lib/wurfl_cloud/cache/cookie.rb +43 -0
  8. data/lib/wurfl_cloud/cache/local_memory.rb +43 -0
  9. data/lib/wurfl_cloud/cache/memcached.rb +64 -0
  10. data/lib/wurfl_cloud/cache/null.rb +41 -0
  11. data/lib/wurfl_cloud/cache/rails.rb +56 -0
  12. data/lib/wurfl_cloud/client.rb +105 -0
  13. data/lib/wurfl_cloud/configuration.rb +88 -0
  14. data/lib/wurfl_cloud/device_capabilities.rb +78 -0
  15. data/lib/wurfl_cloud/environment.rb +48 -0
  16. data/lib/wurfl_cloud/errors.rb +23 -0
  17. data/lib/wurfl_cloud/helper.rb +21 -0
  18. data/lib/wurfl_cloud/rack/cache_manager.rb +54 -0
  19. data/lib/wurfl_cloud/rails.rb +34 -0
  20. data/lib/wurfl_cloud/version.rb +14 -0
  21. data/spec/files/generic.json +1 -0
  22. data/spec/files/generic_filtered.json +1 -0
  23. data/spec/files/lumia.json +1 -0
  24. data/spec/files/lumia_filtered.json +1 -0
  25. data/spec/files/strange_values.json +1 -0
  26. data/spec/spec_helper.rb +27 -0
  27. data/spec/support/rack_helpers.rb +79 -0
  28. data/spec/support/string_extensions.rb +33 -0
  29. data/spec/wurfl_cloud/client_spec.rb +207 -0
  30. data/spec/wurfl_cloud/configuration_spec.rb +118 -0
  31. data/spec/wurfl_cloud/cookie_cache_spec.rb +51 -0
  32. data/spec/wurfl_cloud/device_capabilities_spec.rb +143 -0
  33. data/spec/wurfl_cloud/environment_spec.rb +93 -0
  34. data/spec/wurfl_cloud/helper_spec.rb +35 -0
  35. data/spec/wurfl_cloud/memcached_cache_spec.rb +122 -0
  36. data/spec/wurfl_cloud/null_cache_spec.rb +37 -0
  37. data/spec/wurfl_cloud/rack_cache_manager_spec.rb +76 -0
  38. data/spec/wurfl_cloud/rails_cache_spec.rb +126 -0
  39. data/spec/wurfl_cloud/server_request_spec.rb +45 -0
  40. data/wurfl_cloud_client.gemspec +38 -0
  41. metadata +171 -0
@@ -0,0 +1,93 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'spec_helper'
13
+ describe WurflCloud::Environment do
14
+
15
+ context "the class" do
16
+ it "should respond to new with 1 argument" do
17
+ WurflCloud::Environment.should respond_to(:new).with(1).argument
18
+ end
19
+ end
20
+
21
+ context "the object" do
22
+ [
23
+ :user_agent,
24
+ :x_forwarded_for,
25
+ :x_accept,
26
+ :x_wap_profile
27
+ ].each do |header|
28
+ it { should respond_to(header) }
29
+ it "should return nil if not set in the constructor" do
30
+ subject.send(header).should be_nil
31
+ end
32
+ end
33
+
34
+ context "the user_agent" do
35
+ [
36
+ 'HTTP_X_DEVICE_USER_AGENT',
37
+ 'HTTP_X_ORIGINAL_USER_AGENT',
38
+ 'HTTP_X_OPERAMINI_PHONE_UA',
39
+ 'HTTP_X_SKYFIRE_PHONE',
40
+ 'HTTP_X_BOLT_PHONE_UA',
41
+ 'HTTP_USER_AGENT'
42
+ ].each do |user_agent_param|
43
+ it "should be read from #{user_agent_param} " do
44
+ env = {user_agent_param=>String.random}
45
+ WurflCloud::Environment.new(env).user_agent.should ==env[user_agent_param]
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ context "the x_accept" do
52
+ it "should be read from HTTP_ACCEPT " do
53
+ env = {"HTTP_ACCEPT"=>String.random}
54
+ WurflCloud::Environment.new(env).x_accept.should ==env["HTTP_ACCEPT"]
55
+ end
56
+ end
57
+
58
+ context "the x_wap_profile" do
59
+ it "should be read from HTTP_X_WAP_PROFILE if present and HTTP_PROFILE is null" do
60
+ env = {"HTTP_X_WAP_PROFILE"=>String.random}
61
+ WurflCloud::Environment.new(env).x_wap_profile.should ==env["HTTP_X_WAP_PROFILE"]
62
+ end
63
+
64
+ it "should be read from HTTP_X_WAP_PROFILE if present and HTTP_PROFILE is present" do
65
+ env = {"HTTP_X_WAP_PROFILE"=>String.random, "HTTP_PROFILE"=>String.random}
66
+ WurflCloud::Environment.new(env).x_wap_profile.should ==env["HTTP_X_WAP_PROFILE"]
67
+ end
68
+
69
+ it "should be read from HTTP_PROFILE if present and HTTP_X_WAP_PROFILE is nil" do
70
+ env = {"HTTP_PROFILE"=>String.random}
71
+ WurflCloud::Environment.new(env).x_wap_profile.should ==env["HTTP_PROFILE"]
72
+ end
73
+ end
74
+
75
+ context "the x_forwarded_for" do
76
+ it "should be the REMOTE_ADDR if present and HTTP_X_FORWARDED_FOR is absent" do
77
+ env = {"REMOTE_ADDR"=>String.random}
78
+ WurflCloud::Environment.new(env).x_forwarded_for.should ==env["REMOTE_ADDR"]
79
+ end
80
+
81
+ it "should be the REMOTE_ADDR, HTTP_X_FORWARDED_FOR if both are present" do
82
+ env = {"REMOTE_ADDR"=>String.random, "HTTP_X_FORWARDED_FOR"=>String.random}
83
+ WurflCloud::Environment.new(env).x_forwarded_for.should =="#{env["REMOTE_ADDR"]}, #{env["HTTP_X_FORWARDED_FOR"]}"
84
+ end
85
+
86
+ it "should be nil if REMOTE_ADDR and HTTP_X_FORWARDED_FOR is present" do
87
+ env = {"HTTP_X_FORWARDED_FOR"=>String.random}
88
+ WurflCloud::Environment.new(env).x_forwarded_for.should be_nil
89
+ end
90
+ end
91
+
92
+ end
93
+ end
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2015 ScientiaMobile Inc.
4
+ #
5
+ # The WURFL Cloud Client is intended to be used in both open-source and
6
+ # commercial environments. To allow its use in as many situations as possible,
7
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
8
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
9
+ # the MIT License.
10
+ #
11
+ # Refer to the COPYING.txt file distributed with this package.
12
+ #
13
+ require 'spec_helper'
14
+ require 'wurfl_cloud/helper'
15
+
16
+ describe WurflCloud::Helper do
17
+ include WurflCloud::Helper
18
+
19
+ context "the wurfl_detect_device method" do
20
+
21
+ it "should return a WurflCloud::Client object" do
22
+
23
+ cookie = {'date_set' => Time.now.to_i, 'capabilities' => {'name'=>'example'}}
24
+ env = env_with_params("/", {}, {"HTTP_USER_AGENT"=>String.random, "HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
25
+
26
+ @device_data = File.new("#{File.dirname(__FILE__)}/../files/generic.json").read
27
+ stub_request(:any, authenticated_uri).to_return(:status=>200, :body => @device_data)
28
+
29
+ @wurfl_device = wurfl_detect_device(env)
30
+ @wurfl_device.should be_instance_of(WurflCloud::Client)
31
+
32
+ end
33
+ end
34
+
35
+ end
@@ -0,0 +1,122 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'spec_helper'
13
+ require 'wurfl_cloud/cache/memcached'
14
+ require 'digest/md5'
15
+ require 'dalli'
16
+
17
+ describe WurflCloud::Cache::Memcached do
18
+ subject { WurflCloud::Cache::Memcached.new({:server=>'localhost:11211'}, {}) }
19
+
20
+ before(:each) do
21
+ @memcached = Dalli::Client.new('localhost:11211')
22
+ @memcached.flush()
23
+ @key = String.random
24
+ @value = String.random
25
+ end
26
+
27
+ context "the object" do
28
+
29
+ it { should respond_to(:[]).with(1).argument }
30
+ it { should respond_to(:[]=).with(2).arguments }
31
+ it { should respond_to(:mtime).with(0).arguments }
32
+ it { should respond_to(:mtime=).with(1).argument }
33
+ it { should respond_to(:prefix).with(0).arguments }
34
+ it { should respond_to(:key_prefix).with(0).arguments }
35
+
36
+ it "should not throw errors calling []=" do
37
+ expect { subject[String.random] = String.random }.to_not raise_error
38
+ end
39
+
40
+ it "should have an empty prefix" do
41
+ subject.prefix.should ==""
42
+ end
43
+
44
+ it "should have the key_prefix contain the mtime" do
45
+ mtime = Time.now.to_i
46
+ subject.mtime = mtime
47
+ subject.key_prefix.should include("#{mtime}:")
48
+ end
49
+
50
+ it "should store values" do
51
+ key = String.random
52
+ subject[key] = String.random
53
+ subject[key].should_not be_nil
54
+ end
55
+
56
+ it "should read the value from the memcache" do
57
+ @memcached.set("#{subject.key_prefix}#{Digest::MD5.hexdigest(@key)}", @value)
58
+ subject[@key].should ==@value
59
+ end
60
+
61
+ it "should set the value into memcache" do
62
+ subject[@key] = @value
63
+ @memcached.get("#{subject.key_prefix}#{Digest::MD5.hexdigest(@key)}").should ==@value
64
+ end
65
+
66
+ it "should read the mtime value from memcache" do
67
+ mtime = Time.now.to_i
68
+ @memcached.set("mtime", mtime)
69
+ subject.mtime.should ==mtime
70
+ end
71
+
72
+ it "should store the mtime value into memcache" do
73
+ mtime = Time.now.to_i
74
+ subject.mtime = mtime
75
+ @memcached.get("mtime").should ==mtime
76
+ end
77
+
78
+ it "should store the mtime value into memcache when validating the cache" do
79
+ mtime = Time.now.to_i
80
+ subject.validate(mtime)
81
+ @memcached.get("mtime").should ==mtime
82
+ end
83
+ end
84
+
85
+ context "with a prefix" do
86
+ before(:each) do
87
+ @cache = WurflCloud::Cache::Memcached.new({:server=>'localhost:11211', :prefix=>"a_prefix"}, {})
88
+ end
89
+
90
+ it "should not have an empty prefix" do
91
+ @cache.prefix.should =="a_prefix:"
92
+ end
93
+
94
+ it "should have the key_prefix start with the prefix" do
95
+ @cache.key_prefix.should =~/^a_prefix:/
96
+ end
97
+
98
+ it "should have the key_prefix contain the mtime" do
99
+ mtime = Time.now.to_i
100
+ @cache.mtime = mtime
101
+ @cache.key_prefix.should include("#{mtime}:")
102
+ end
103
+
104
+ it "should read the mtime value from memcache" do
105
+ mtime = Time.now.to_i
106
+ @memcached.set("a_prefix:mtime", mtime)
107
+ @cache.mtime.should ==mtime
108
+ end
109
+
110
+ it "should store the mtime value into memcache" do
111
+ mtime = Time.now.to_i
112
+ @cache.mtime = mtime
113
+ @memcached.get("a_prefix:mtime").should ==mtime
114
+ end
115
+
116
+ it "should store the mtime value into memcache when validating the cache" do
117
+ mtime = Time.now.to_i
118
+ @cache.validate(mtime)
119
+ @memcached.get("a_prefix:mtime").should ==mtime
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,37 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'spec_helper'
13
+ describe WurflCloud::Cache::Null do
14
+ subject { WurflCloud::Cache::Null.new({}, Object.new) }
15
+
16
+ context "the object" do
17
+ it { should respond_to(:[]).with(1).argument }
18
+ it { should respond_to(:[]=).with(2).arguments }
19
+ it { should respond_to(:mtime).with(0).arguments }
20
+ it { should respond_to(:mtime=).with(1).argument }
21
+
22
+ it "should not throw errors calling []=" do
23
+ expect { subject[String.random] = String.random }.to_not raise_error
24
+ end
25
+
26
+ it "should not store values" do
27
+ key = String.random
28
+ subject[key] = String.random
29
+ subject[key].should be_nil
30
+ end
31
+
32
+ it "should not store the mtime" do
33
+ subject.mtime = rand
34
+ subject.mtime.should be_nil
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Copyright (c) 2015 ScientiaMobile Inc.
4
+ #
5
+ # The WURFL Cloud Client is intended to be used in both open-source and
6
+ # commercial environments. To allow its use in as many situations as possible,
7
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
8
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
9
+ # the MIT License.
10
+ #
11
+ # Refer to the COPYING.txt file distributed with this package.
12
+ #
13
+ require 'spec_helper'
14
+
15
+ describe WurflCloud::Rack::CacheManager do
16
+
17
+ context "the wurfl.cookie.device_cache env parameter" do
18
+
19
+ it "should be inserted if the cookie exists" 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_not be_nil
24
+ end
25
+
26
+ it "should be decoded from json" do
27
+ cookie = {'date_set' => Time.now.to_i, 'capabilities' => {'name'=>'example'}}
28
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
29
+ setup_rack(success_app).call(env)
30
+ env["wurfl.cookie.device_cache"].should =={'name'=>'example'}
31
+ end
32
+
33
+ it "should be nil if it doesn't exist" do
34
+ env = env_with_params("/", {}, {})
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 not a valid json object" do
40
+ cookie = {}
41
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape("{}")}"})
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 date_set field" do
47
+ cookie = {'capabilities' => {}}
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 it lacks the capabilities field" do
54
+ cookie = {'date_set' => Time.now.to_i}
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 capabilities field is empty" do
61
+ cookie = {'date_set' => (Time.now-WurflCloud::Rack::CacheManager::EXPIRY-1).to_i, 'capabilities' => {}}
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
+ it "should be nil if the cookie was expired" do
68
+ cookie = {'date_set' => (Time.now-WurflCloud::Rack::CacheManager::EXPIRY-1).to_i, 'capabilities' => {'name'=>'example'}}
69
+ env = env_with_params("/", {}, {"HTTP_COOKIE" => "#{WurflCloud::Rack::CacheManager::COOKIE_NAME}=#{::Rack::Utils.escape(cookie.to_json)}"})
70
+ setup_rack(success_app).call(env)
71
+ env["wurfl.cookie.device_cache"].should be_nil
72
+ end
73
+
74
+ end
75
+
76
+ end
@@ -0,0 +1,126 @@
1
+ #
2
+ # Copyright (c) 2015 ScientiaMobile Inc.
3
+ #
4
+ # The WURFL Cloud Client is intended to be used in both open-source and
5
+ # commercial environments. To allow its use in as many situations as possible,
6
+ # the WURFL Cloud Client is dual-licensed. You may choose to use the WURFL
7
+ # Cloud Client under either the GNU GENERAL PUBLIC LICENSE, Version 2.0, or
8
+ # the MIT License.
9
+ #
10
+ # Refer to the COPYING.txt file distributed with this package.
11
+ #
12
+ require 'spec_helper'
13
+ require 'digest/md5'
14
+ require 'wurfl_cloud/cache/rails'
15
+
16
+ # fake rails cache
17
+ module Rails
18
+ class Cache
19
+ def initialize
20
+ @store = Hash.new
21
+ end
22
+ def write(key, value)
23
+ @store[key] = value
24
+ end
25
+ def read(key)
26
+ @store[key]
27
+ end
28
+ end
29
+
30
+ class << self
31
+ def cache
32
+ @cache ||= Rails::Cache.new
33
+ end
34
+ end
35
+ end
36
+
37
+ describe WurflCloud::Cache::Rails do
38
+ subject { WurflCloud::Cache::Rails.new({}, {}) }
39
+
40
+ context "the object" do
41
+ it { should respond_to(:[]).with(1).argument }
42
+ it { should respond_to(:[]=).with(2).arguments }
43
+ it { should respond_to(:mtime).with(0).arguments }
44
+ it { should respond_to(:mtime=).with(1).argument }
45
+ it { should respond_to(:prefix).with(0).arguments }
46
+ it { should respond_to(:key_prefix).with(0).arguments }
47
+
48
+ it "should not throw errors calling []=" do
49
+ expect { subject[String.random] = String.random }.to_not raise_error
50
+ end
51
+
52
+ it "should store values" do
53
+ key = String.random
54
+ subject[key] = String.random
55
+ subject[key].should_not be_nil
56
+ end
57
+
58
+ it "should have an empty prefix" do
59
+ subject.prefix.should ==""
60
+ end
61
+
62
+ it "should have the key_prefix contain the mtime" do
63
+ mtime = Time.now.to_i
64
+ subject.mtime = mtime
65
+ subject.key_prefix.should include("#{mtime}:")
66
+ end
67
+
68
+ end
69
+
70
+ context "given Rails.cache" do
71
+ before(:each) do
72
+ @cache = WurflCloud::Cache::Rails.new({}, {})
73
+ @key = String.random
74
+ @value = String.random
75
+ end
76
+
77
+ it "should read the value from the Rails.cache" do
78
+ Rails.cache.write("#{@cache.key_prefix}#{Digest::MD5.hexdigest(@key)}", @value)
79
+ @cache[@key].should ==@value
80
+ end
81
+
82
+ it "should set the value into the Rails.cache" do
83
+ @cache[@key] = @value
84
+ Rails.cache.read("#{@cache.key_prefix}#{Digest::MD5.hexdigest(@key)}").should ==@value
85
+ end
86
+
87
+ context "with a prefix" do
88
+ before(:each) do
89
+ @cache = WurflCloud::Cache::Rails.new({:prefix=>"a_prefix"}, {})
90
+ end
91
+
92
+ it "should not have an empty prefix" do
93
+ @cache.prefix.should =="a_prefix:"
94
+ end
95
+
96
+ it "should have the key_prefix start with the prefix" do
97
+ @cache.key_prefix.should =~/^a_prefix:/
98
+ end
99
+
100
+ it "should have the key_prefix contain the mtime" do
101
+ mtime = Time.now.to_i
102
+ @cache.mtime = mtime
103
+ @cache.key_prefix.should include("#{mtime}:")
104
+ end
105
+
106
+ it "should read the mtime value from Rails.cache" do
107
+ mtime = Time.now.to_i
108
+ Rails.cache.write("a_prefix:mtime", mtime)
109
+ @cache.mtime.should ==mtime
110
+ end
111
+
112
+ it "should store the mtime value into Rails.cache" do
113
+ mtime = Time.now.to_i
114
+ @cache.mtime = mtime
115
+ Rails.cache.read("a_prefix:mtime").should ==mtime
116
+ end
117
+
118
+ it "should store the mtime value into Rails.cache when validating the cache" do
119
+ mtime = Time.now.to_i
120
+ @cache.validate(mtime)
121
+ Rails.cache.read("a_prefix:mtime").should ==mtime
122
+ end
123
+ end
124
+ end
125
+
126
+ end