wurfl_cloud_client 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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