sixpack-client 1.1.0 → 1.2.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.
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