sixpack-client 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- Njk3MGE1YTljNWIyZjA1MTNiYzY4ZjM0YjY2ODQ3NDU3NzVmNjhkMg==
4
+ NzUyMTk0MjllOGI1MGIyYmRiYmY4OTQxOGZjOWFjYjViODNiOGRhNQ==
5
5
  data.tar.gz: !binary |-
6
- ZmM2ZDcxZmY2MmNjOWEzNjZkZjVhMDU0YzFhNjM1Y2YzZTNjNGRlMA==
6
+ ZjM0MjFhYzlmNTAzYTE0MGJhNTIxZjgxMTZlMWEyZDY2MzUxNGI3OA==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- ZWVjNjJjODkzN2UyMjQ4M2I2ODg5Y2M1MzBmN2M5MzExZDAzODIzODhmOGFj
10
- ZTBlOTViNjFkNGFhMzU4OTFlM2EzMTNlNDU2OTgyYmU5ZDQyYmM1M2FhN2Rh
11
- ZTE5M2ZmMWE5MGJhMDQ0NDQ3Y2NjZTM5MjU2YTM2ZTRlYzk1NDM=
9
+ MDkzZTc0MzI5NTEwOTVmMWQ0NmIyMTJmMWQ0MjRkMGJkMTdjYWQ3NWQ0YWNm
10
+ MTQxZDVjYzVlODQ2ZGFiZmQ0YzRmNjIyMzI4YTA5NTdmODBmZTAyMDgwMWJi
11
+ MDg4YTZlZjhmOTk0YzVhNzdiNjRkN2IwNzYwNTk2MzE3ZDk0MGM=
12
12
  data.tar.gz: !binary |-
13
- YTg0YWEwYzEwNmM3NmE5YjZlZDE3M2I2NmE2YjlhYWJkMmEzMmZkNGY4YWY3
14
- YmQyNGRhOGM3MjQzMDdlNzM2NTQ3MjdmNDFiYWJkZGIxOTRiYTJiNmFkMWNj
15
- ZWQxNWI4ODE2YjQ3OWJmMDQyNjExNDVmYzU3Y2RmY2RkZGI4ZGI=
13
+ ZTE0ODFkODkxMDg3YTNlYWFjMTRiYmIzZTFkNGQ1MDg0ODYwYzAwM2M1Yzgy
14
+ YzMwYjk2MGY3MTg4YWVjZGRjNGYxZTQxNTA3MmEwNDhhZDZjZWUyMzc2OWNk
15
+ NTEyMjYxZDQzY2NjMzliMmViZDlmMWFhODM3ZDNkYTgxYjZmYzk=
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/.travis.yml CHANGED
@@ -1,3 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 1.9.3
4
+ - 2.2.2
5
+
6
+ services:
7
+ - redis-server
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Sixpack
2
2
 
3
+ [![Build Status](https://travis-ci.org/seatgeek/sixpack-rb.svg?branch=master)](https://travis-ci.org/seatgeek/sixpack-rb)
4
+
3
5
  Ruby client library for SeatGeek's Sixpack ab testing framework.
4
6
 
5
7
  ## Installation
@@ -47,14 +49,14 @@ For future requests, create the `Session` using the `client_id` stored in the co
47
49
 
48
50
  ```ruby
49
51
  client_id = get_cookie_from_web_framework("sixpack-id")
50
- session = Sixpack::Session.new client_id
52
+ session = Sixpack::Session.new(client_id)
51
53
  session.convert("new-test")
52
54
  ```
53
55
 
54
56
  Sessions can take an optional `options` hash that takes `:base_url`, and a params hash that takes `:ip_address`, and `:user_agent` a keys. If you would like to instantiate a session with a known client id, you can do that here. IP address and user agent can be passed to assist in bot detection.
55
57
 
56
58
  options = {
57
- :host => 'http://mysixpacklocation.com',
59
+ :base_url => 'http://mysixpacklocation.com'
58
60
  }
59
61
  params = {
60
62
  :ip_address => '1.2.3.4'
@@ -63,6 +65,36 @@ Sessions can take an optional `options` hash that takes `:base_url`, and a param
63
65
 
64
66
  If Sixpack is unreachable or other errors occur, sixpack-rb will provide the control alternative object.
65
67
 
68
+ ## Configuration
69
+
70
+ You can configure the Sixpack in the configure block:
71
+
72
+ ```ruby
73
+ Sixpack.configure do |config|
74
+ config.base_url = 'http://10.20.30.40:5000'
75
+ end
76
+ ```
77
+
78
+ You can use the `configure` block when initializing your app, for instance in a
79
+ Rails initializer.
80
+
81
+ Note that options, passed directly into `Session` constructor override the configuration options.
82
+
83
+ ```ruby
84
+ Sixpack.configure do |config|
85
+ config.base_url = 'http://foo:5000'
86
+ end
87
+
88
+ s = Sixpack::Session.new(id, base_url: 'http://bar:6000')
89
+
90
+ expect(s.base_url).to eq 'http://bar:6000' #=> true
91
+ ```
92
+ ### Configuration options
93
+
94
+ * base_url - to set the base_url for the sixpack API server (can be
95
+ overriden in the Session constructor)
96
+ * user - set http basic authentication user
97
+ * password - set http basic authentication password
66
98
 
67
99
  ## Contributing
68
100
 
@@ -0,0 +1,16 @@
1
+ module Sixpack
2
+ class Configuration
3
+ attr_accessor :base_url, :user, :password
4
+
5
+ def initialize
6
+ @base_url = 'http://localhost:5000'
7
+ end
8
+
9
+ def to_hash
10
+ config = {base_url: @base_url}
11
+ config[:user] = @user unless @user.nil?
12
+ config[:password] = @password unless @password.nil?
13
+ config
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module Sixpack
2
- VERSION = "1.1.0"
2
+ VERSION = "1.2.0"
3
3
  end
data/lib/sixpack.rb CHANGED
@@ -1,30 +1,40 @@
1
1
  require "addressable/uri"
2
2
  require "net/http"
3
3
  require "json"
4
- require "uuid"
5
4
  require "uri"
6
5
 
7
6
  require "sixpack/version"
7
+ require "sixpack/configuration"
8
8
 
9
9
  module Sixpack
10
- extend self
11
10
 
12
- attr_accessor :base_url
11
+ class << self
13
12
 
14
- @base_url = "http://localhost:5000"
13
+ def configuration
14
+ @configuration ||= Configuration.new
15
+ end
16
+
17
+ def configure
18
+ yield(configuration)
19
+ end
15
20
 
16
- def generate_client_id
17
- uuid = UUID.new
18
- uuid.generate
21
+ def generate_client_id
22
+ SecureRandom.uuid
23
+ end
19
24
  end
20
25
 
26
+
21
27
  class Session
22
- attr_accessor :base_url, :client_id, :ip_address, :user_agent
28
+ attr_reader :base_url
29
+ attr_accessor :client_id, :ip_address, :user_agent
23
30
 
24
31
  def initialize(client_id=nil, options={}, params={})
25
- default_options = {:base_url => Sixpack.base_url}
26
- options = default_options.merge(options)
32
+ # options supplied directly will override the configured options
33
+ options = Sixpack.configuration.to_hash.merge(options)
34
+
27
35
  @base_url = options[:base_url]
36
+ @user = options[:user]
37
+ @password = options[:password]
28
38
 
29
39
  default_params = {:ip_address => nil, :user_agent => :nil}
30
40
  params = default_params.merge(params)
@@ -39,32 +49,26 @@ module Sixpack
39
49
  end
40
50
  end
41
51
 
42
- def participate(experiment_name, alternatives, force=nil, traffic_fraction=1)
52
+ def participate(experiment_name, alternatives, force=nil)
43
53
  if !(experiment_name =~ /^[a-z0-9][a-z0-9\-_ ]*$/)
44
- raise ArgumentError, "Bad experiment_name"
54
+ raise ArgumentError, "Bad experiment_name, must be lowercase, start with an alphanumeric and contain alphanumerics, dashes and underscores"
45
55
  end
46
56
 
47
57
  if alternatives.length < 2
48
58
  raise ArgumentError, "Must specify at least 2 alternatives"
49
59
  end
50
60
 
51
- if traffic_fraction.to_f < 0 || traffic_fraction > 1
52
- raise ArgumentError, "Invalid Traffic Fraction"
53
- end
54
-
55
61
  alternatives.each { |alt|
56
62
  if !(alt =~ /^[a-z0-9][a-z0-9\-_ ]*$/)
57
- raise ArgumentError, "Bad alternative name: #{alt}"
63
+ raise ArgumentError, "Bad alternative name: #{alt}, must be lowercase, start with an alphanumeric and contain alphanumerics, dashes and underscores"
58
64
  end
59
65
  }
60
66
 
61
67
  params = {
62
68
  :client_id => @client_id,
63
69
  :experiment => experiment_name,
64
- :alternatives => alternatives,
65
- :traffic_fraction => traffic_fraction
70
+ :alternatives => alternatives
66
71
  }
67
-
68
72
  if !force.nil? && alternatives.include?(force)
69
73
  return {"status" => "ok", "alternative" => {"name" => force}, "experiment" => {"version" => 0, "name" => experiment_name}, "client_id" => @client_id}
70
74
  end
@@ -96,7 +100,7 @@ module Sixpack
96
100
  end
97
101
 
98
102
  def get_response(endpoint, params)
99
- uri = URI.parse(@base_url)
103
+ uri = URI.parse(@base_url)
100
104
  http = Net::HTTP.new(uri.host, uri.port)
101
105
 
102
106
  if uri.scheme == "https"
@@ -109,17 +113,26 @@ module Sixpack
109
113
  query = Addressable::URI.form_encode(self.build_params(params))
110
114
 
111
115
  begin
112
- res = http.start do |http|
113
- http.get(uri.path + endpoint + "?" + query)
116
+ req = Net::HTTP::Get.new(uri.path + endpoint + "?" + query)
117
+ # basic auth
118
+ if @user && @password
119
+ req.basic_auth(@user, @password)
114
120
  end
121
+ res = http.request(req)
115
122
  rescue
116
123
  return {"status" => "failed", "error" => "http error"}
117
124
  end
118
125
  if res.code == "500"
119
126
  {"status" => "failed", "response" => res.body}
120
127
  else
121
- JSON.parse(res.body)
128
+ parse_response(res)
122
129
  end
123
130
  end
131
+
132
+ def parse_response(res)
133
+ JSON.parse(res.body)
134
+ rescue JSON::ParserError
135
+ {"status" => "failed", "response" => res.body}
136
+ end
124
137
  end
125
138
  end
data/sixpack.gemspec CHANGED
@@ -20,6 +20,5 @@ Gem::Specification.new do |gem|
20
20
  gem.add_development_dependency 'redis'
21
21
 
22
22
  gem.add_runtime_dependency 'json'
23
- gem.add_runtime_dependency 'uuid'
24
23
  gem.add_runtime_dependency 'addressable'
25
24
  end
@@ -2,62 +2,65 @@ require 'redis'
2
2
 
3
3
  require 'spec_helper'
4
4
 
5
- describe Sixpack do
5
+ RSpec.describe Sixpack do
6
6
  before(:each) do
7
7
  redis = Redis.new
8
- redis.keys("*").each do |k|
9
- redis.del(k)
8
+ redis.flushdb
9
+ end
10
+
11
+ context 'configuration' do
12
+ it 'should contain default base_url' do
13
+ s = Sixpack::Session.new("foo")
14
+ expect(s.base_url).to eq 'http://localhost:5000'
15
+ end
16
+
17
+ it 'should allow specifying the base_url in Session options' do
18
+ s = Sixpack::Session.new("foo", base_url: 'http://0.0.0.0:5555')
19
+ expect(s.base_url).to eq 'http://0.0.0.0:5555'
20
+ end
21
+
22
+ it 'should allow specifying the base_url in configuration block' do
23
+ Sixpack.configure do |config|
24
+ config.base_url = 'http://4.4.4.4'
25
+ end
26
+ s = Sixpack::Session.new("foo")
27
+ expect(s.base_url).to eq 'http://4.4.4.4'
28
+ end
29
+
30
+ it 'session base_url should override configuration base_url' do
31
+ Sixpack.configure do |config|
32
+ config.base_url = 'http://4.4.4.4'
33
+ end
34
+ s = Sixpack::Session.new("foo", base_url: 'http://5.5.5.5')
35
+ expect(s.base_url).to eq 'http://5.5.5.5'
10
36
  end
11
37
  end
12
38
 
13
39
  it "should return an alternative for participate" do
14
40
  sess = Sixpack::Session.new("mike")
15
41
  resp = sess.participate('show-bieber', ['trolled', 'not-trolled'])
16
- ['trolled', 'not-trolled'].should include(resp["alternative"]["name"])
42
+ expect(['trolled', 'not-trolled']).to include(resp["alternative"]["name"])
17
43
  end
18
44
 
19
45
  it "should return the correct alternative for participate with force" do
20
46
  sess = Sixpack::Session.new("mike")
21
47
  alt = sess.participate('show-bieber', ['trolled', 'not-trolled'], "trolled")["alternative"]["name"]
22
- alt.should == "trolled"
48
+ expect(alt).to eq "trolled"
23
49
 
24
- alternative = sess.participate('show-bieber', ['trolled', 'not-trolled'], "not-trolled")["alternative"]["name"]
25
- alternative.should == "not-trolled"
50
+ alt = sess.participate('show-bieber', ['trolled', 'not-trolled'], "not-trolled")["alternative"]["name"]
51
+ expect(alt).to eq "not-trolled"
26
52
  end
27
53
 
28
54
  it "should allow ip and user agent to be passed to a session" do
29
55
  params = {:ip_address => '8.8.8.8', :user_agent => 'FirChromari'}
30
56
  session = Sixpack::Session.new('client_id', {}, params)
31
- session.ip_address.should == '8.8.8.8'
32
- session.user_agent.should == 'FirChromari'
57
+ expect(session.ip_address).to eq '8.8.8.8'
58
+ expect(session.user_agent).to eq'FirChromari'
33
59
  end
34
60
 
35
61
  it "should auto generate a client_id" do
36
62
  sess = Sixpack::Session.new
37
- sess.client_id.length.should == 36
38
- end
39
-
40
- it "should return ok for convert" do
41
- sess = Sixpack::Session.new("mike")
42
- alternative = sess.participate('show-bieber', ['trolled', 'not-trolled'])
43
- sess.convert("show-bieber")["status"].should == "ok"
44
- end
45
-
46
- it "should return ok for multiple_converts" do
47
- sess = Sixpack::Session.new("mike")
48
- sess.participate('show-bieber', ['trolled', 'not-trolled'])
49
- sess.convert("show-bieber")["status"].should == "ok"
50
- sess.convert("show-bieber")["status"].should == "ok"
51
- end
52
-
53
- it "should not return ok for convert with new id" do
54
- sess = Sixpack::Session.new("unknown_id")
55
- sess.convert("show-bieber")["status"].should == "failed"
56
- end
57
-
58
- it "should not return ok for convert with new experiment" do
59
- sess = Sixpack::Session.new
60
- sess.convert("show-blieber")['status'].should == "failed"
63
+ expect(sess.client_id.length).to eq 36
61
64
  end
62
65
 
63
66
  it "should not allow bad experiment names" do
@@ -67,11 +70,12 @@ describe Sixpack do
67
70
  }.to raise_error
68
71
  end
69
72
 
70
- it "should not allow bad traffic tractions" do
71
- expect {
72
- sess = Sixpack::Session.new
73
- sess.participate('testing', ['trolled', 'not-trolled'], nil, 2)
74
- }.to raise_error
73
+ it "should not try parse bad response body data" do
74
+ sess = Sixpack::Session.new
75
+ response = double(body: 'something unexpected', code: 200)
76
+ allow_any_instance_of(Net::HTTP).to receive(:get).and_return(response)
77
+ res = sess.participate('show-bieber', ['trolled', 'not-trolled'])
78
+ expect(res["status"]).to eq('failed')
75
79
  end
76
80
 
77
81
  it "should not allow bad alternatives names" do
@@ -86,27 +90,4 @@ describe Sixpack do
86
90
  }.to raise_error
87
91
  end
88
92
 
89
- it "should work" do
90
- session = Sixpack::Session.new
91
- session.convert("testing")["status"].should == "failed"
92
- alt_one = session.participate("testing", ["one", "two"])["alternative"]
93
- 3.times do |n|
94
- session.participate("testing", ["one", "two"])["alternative"].should == alt_one
95
- end
96
- session.convert("testing")["status"].should == "ok"
97
-
98
- old_client_id = session.client_id
99
- session.client_id = Sixpack::generate_client_id()
100
- session.convert("testing")["status"].should == "failed"
101
- alt_two = session.participate("testing", ["one", "two"])["alternative"]
102
- 3.times do |n|
103
- session.participate("testing", ["one", "two"])["alternative"].should == alt_two
104
- end
105
- session.convert("testing")["status"].should == "ok"
106
-
107
- session = Sixpack::Session.new old_client_id
108
- 3.times do |n|
109
- session.participate("testing", ["one", "two"])["alternative"].should == alt_one
110
- end
111
- end
112
93
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sixpack-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.0
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - SeatGeek
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-02-03 00:00:00.000000000 Z
11
+ date: 2015-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -66,20 +66,6 @@ dependencies:
66
66
  - - ! '>='
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
- - !ruby/object:Gem::Dependency
70
- name: uuid
71
- requirement: !ruby/object:Gem::Requirement
72
- requirements:
73
- - - ! '>='
74
- - !ruby/object:Gem::Version
75
- version: '0'
76
- type: :runtime
77
- prerelease: false
78
- version_requirements: !ruby/object:Gem::Requirement
79
- requirements:
80
- - - ! '>='
81
- - !ruby/object:Gem::Version
82
- version: '0'
83
69
  - !ruby/object:Gem::Dependency
84
70
  name: addressable
85
71
  requirement: !ruby/object:Gem::Requirement
@@ -102,12 +88,14 @@ extensions: []
102
88
  extra_rdoc_files: []
103
89
  files:
104
90
  - .gitignore
91
+ - .rspec
105
92
  - .travis.yml
106
93
  - Gemfile
107
94
  - LICENSE
108
95
  - README.md
109
96
  - Rakefile
110
97
  - lib/sixpack.rb
98
+ - lib/sixpack/configuration.rb
111
99
  - lib/sixpack/version.rb
112
100
  - sixpack.gemspec
113
101
  - spec/lib/sixpack_spec.rb