toxiproxy 0.0.2

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: f2f83e60344122fe413e11816f5c976e46de7d6e
4
+ data.tar.gz: 52de814ecc4b5c472329179daf349599c9a5d15a
5
+ SHA512:
6
+ metadata.gz: 1ae9818932feabbb5982eb525d7dcfd1a03d20047d0e99d2cbd07e3b62d474285e118a29505802571c8132f595a5c014e0bf9327e9a0a6f8358db2836e37f8cb
7
+ data.tar.gz: a58e9df0b31c788e9b927fdf7c399621dce64e4f9dcb83e9670ea87ddcfe230a05eb2f3f2be29cf83e23d56ef2e5675a62f6210d66c1006030712cc34a654d36
@@ -0,0 +1,3 @@
1
+ vendor/
2
+ .bundle
3
+ Gemfile.lock
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+ gemspec
3
+
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2014 Shopify
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,50 @@
1
+ # toxiproxy-ruby
2
+
3
+ [Toxiproxy](https://github.com/shopify/toxiproxy) is a proxy to simulate network
4
+ and system conditions. The Ruby API aims to make it simple to write tests that
5
+ assure your application behaves appropriate under harsh conditions. Please see
6
+ the Toxiproxy project for more details.
7
+
8
+ ```
9
+ gem install toxiproxy
10
+ ```
11
+
12
+ Make sure the Toxiproxy server is already running.
13
+
14
+ ## Usage
15
+
16
+ For example, to simulate 1000ms latency on a database server you can use the
17
+ `latency` toxic with the `latency` argument (see the Toxiproxy project for a
18
+ list of all toxics):
19
+
20
+ ```ruby
21
+ Toxiproxy[:mysql_master].downstream(:latency, latency: 1000) do
22
+ Shop.first # this took at least 1s
23
+ end
24
+ ```
25
+
26
+ You can also take an endpoint down for the duration of a block at the TCP level:
27
+
28
+ ```ruby
29
+ Toxiproxy[:mysql_master].down do
30
+ Shop.first # this'll raise
31
+ end
32
+ ```
33
+
34
+ If you want to simulate all your Redis instances being down:
35
+
36
+ ```ruby
37
+ Toxiproxy[/redis/].down do
38
+ # any redis call will fail
39
+ end
40
+ ```
41
+
42
+ If you want to simulate that your cache server is slow at incoming network
43
+ (upstream), but fast at outgoing (downstream), you can apply a toxic to just the
44
+ upstream:
45
+
46
+ ```ruby
47
+ Toxiproxy[:cache].upstream(:latency, latency: 1000) do
48
+ Cache.get(:omg) # will take at least a second
49
+ end
50
+ ```
@@ -0,0 +1,12 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ desc 'Default: run unit tests.'
5
+ task :default => :test
6
+
7
+ Rake::TestTask.new(:test) do |t|
8
+ t.libs << 'lib'
9
+ t.libs << 'test'
10
+ t.pattern = 'test/*_test.rb'
11
+ t.verbose = true
12
+ end
@@ -0,0 +1,8 @@
1
+ #!/bin/bash -e
2
+
3
+ VERSION='fad1365c087d6ad53944c8201a6131cb'
4
+
5
+ echo "[start toxiproxy]"
6
+ curl --silent http://shopify-vagrant.s3.amazonaws.com/toxiproxy/toxiproxy-$VERSION -o ./bin/toxiproxy
7
+ chmod +x ./bin/toxiproxy
8
+ nohup bash -c "./bin/toxiproxy > ${CIRCLE_ARTIFACTS}/toxiproxy.log 2>&1 &"
@@ -0,0 +1,7 @@
1
+ dependencies:
2
+ override:
3
+ - bundle install
4
+ - ./bin/start-toxiproxy.sh
5
+ test:
6
+ override:
7
+ - bundle exec rake test
@@ -0,0 +1,179 @@
1
+ require "json"
2
+ require "uri"
3
+ require "net/http"
4
+
5
+ require "toxiproxy/collection"
6
+ require "toxiproxy/toxic"
7
+ require "toxiproxy/toxic_collection"
8
+
9
+ class Toxiproxy
10
+ URI = ::URI.parse("http://127.0.0.1:8474")
11
+ VALID_DIRECTIONS = [:upstream, :downstream]
12
+
13
+ class NotFound < StandardError; end
14
+ class ProxyExists < StandardError; end
15
+ class InvalidToxic < StandardError; end
16
+
17
+ attr_reader :listen, :name
18
+
19
+ def initialize(options)
20
+ @upstream = options[:upstream]
21
+ @listen = options[:listen] || "localhost:0"
22
+ @name = options[:name]
23
+ end
24
+
25
+ # Forwardable doesn't support delegating class methods, so we resort to
26
+ # `define_method` to delegate from Toxiproxy to #all, and from there to the
27
+ # proxy collection.
28
+ class << self
29
+ Collection::METHODS.each do |method|
30
+ define_method(method) do |*args, &block|
31
+ self.all.send(method, *args, &block)
32
+ end
33
+ end
34
+ end
35
+
36
+ # Returns a collection of all currently active Toxiproxies.
37
+ def self.all
38
+ request = Net::HTTP::Get.new("/proxies")
39
+ response = http.request(request)
40
+ assert_response(response)
41
+
42
+ proxies = JSON.parse(response.body).map { |name, attrs|
43
+ self.new({
44
+ upstream: attrs["upstream"],
45
+ listen: attrs["listen"],
46
+ name: attrs["name"]
47
+ })
48
+ }
49
+
50
+ Collection.new(proxies)
51
+ end
52
+
53
+ # Convenience method to create a proxy.
54
+ def self.create(options)
55
+ self.new(options).create
56
+ end
57
+
58
+ # Find a single proxy by name.
59
+ def self.find_by_name(name = nil, &block)
60
+ proxy = self.all.find { |p| p.name == name.to_s }
61
+ raise NotFound, "#{name} not found in #{self.all.map(&:name).join(', ')}" unless proxy
62
+ proxy
63
+ end
64
+
65
+ # If given a regex, it'll use `grep` to return a Toxiproxy::Collection.
66
+ # Otherwise, it'll convert the passed object to a string and find the proxy by
67
+ # name.
68
+ def self.[](query)
69
+ return grep(query) if query.is_a?(Regexp)
70
+ find_by_name(query)
71
+ end
72
+
73
+ # Set an upstream toxic.
74
+ def upstream(toxic = nil, attrs = {})
75
+ return @upstream unless toxic
76
+
77
+ collection = ToxicCollection.new(self)
78
+ collection.upstream(toxic, attrs)
79
+ collection
80
+ end
81
+
82
+ # Set a downstream toxic.
83
+ def downstream(toxic, attrs = {})
84
+ collection = ToxicCollection.new(self)
85
+ collection.downstream(toxic, attrs)
86
+ collection
87
+ end
88
+
89
+ # Simulates the endpoint is down, by closing the connection and no
90
+ # longer accepting connections. This is useful to simulate critical system
91
+ # failure, such as a data store becoming completely unavailable.
92
+ def down(&block)
93
+ uptoxics = toxics(:upstream)
94
+ downtoxics = toxics(:downstream)
95
+ destroy
96
+ begin
97
+ yield
98
+ ensure
99
+ create
100
+ uptoxics.each(&:save)
101
+ downtoxics.each(&:save)
102
+ end
103
+ end
104
+
105
+ # Create a Toxiproxy, proxying traffic from `@listen` (optional argument to
106
+ # the constructor) to `@upstream`. `#down` `#upstream` or `#downstream` can at any time alter the health
107
+ # of this connection.
108
+ def create
109
+ request = Net::HTTP::Post.new("/proxies")
110
+
111
+ hash = {upstream: upstream, name: name, listen: listen}
112
+ request.body = hash.to_json
113
+
114
+ response = http.request(request)
115
+ assert_response(response)
116
+
117
+ new = JSON.parse(response.body)
118
+ @listen = new["listen"]
119
+
120
+ self
121
+ end
122
+
123
+ # Destroys a Toxiproxy.
124
+ def destroy
125
+ request = Net::HTTP::Delete.new("/proxies/#{name}")
126
+ response = http.request(request)
127
+ assert_response(response)
128
+ self
129
+ end
130
+
131
+ private
132
+
133
+ # Returns a collection of the current toxics for a direction.
134
+ def toxics(direction)
135
+ unless VALID_DIRECTIONS.include?(direction.to_sym)
136
+ raise InvalidToxic, "Toxic direction must be one of: [#{VALID_DIRECTIONS.join(', ')}], got: #{direction}"
137
+ end
138
+
139
+ request = Net::HTTP::Get.new("/proxies/#{name}/#{direction}/toxics")
140
+ response = http.request(request)
141
+ assert_response(response)
142
+
143
+ toxics = JSON.parse(response.body).map { |name, attrs|
144
+ Toxic.new({
145
+ name: name,
146
+ proxy: self,
147
+ direction: direction,
148
+ attrs: attrs
149
+ })
150
+ }
151
+
152
+ toxics
153
+ end
154
+
155
+ def self.http
156
+ @http ||= Net::HTTP.new(URI.host, URI.port)
157
+ end
158
+
159
+ def http
160
+ self.class.http
161
+ end
162
+
163
+ def self.assert_response(response)
164
+ case response
165
+ when Net::HTTPConflict
166
+ raise Toxiproxy::ProxyExists, response.body
167
+ when Net::HTTPNotFound
168
+ raise Toxiproxy::NotFound, response.body
169
+ when Net::HTTPBadRequest
170
+ raise Toxiproxy::InvalidToxic, response.body
171
+ else
172
+ response.value # raises if not OK
173
+ end
174
+ end
175
+
176
+ def assert_response(*args)
177
+ self.class.assert_response(*args)
178
+ end
179
+ end
@@ -0,0 +1,58 @@
1
+ require "forwardable"
2
+
3
+ class Toxiproxy
4
+ # ProxyCollection represents a set of proxies. This allows to easily perform
5
+ # actions on every proxy in the collection.
6
+ #
7
+ # Unfortunately, it doesn't implement all of Enumerable because there's no way
8
+ # to subclass an Array or include Enumerable for the methods to return a
9
+ # Collection instead of an Array (see MRI). Instead, we delegate methods where
10
+ # it doesn't matter and only allow the filtering methods that really make
11
+ # sense on a proxy collection.
12
+ class Collection
13
+ extend Forwardable
14
+
15
+ DELEGATED_METHODS = [:length, :size, :count, :find, :each, :map]
16
+ DEFINED_METHODS = [:select, :reject, :grep, :down]
17
+ METHODS = DEFINED_METHODS + DELEGATED_METHODS
18
+
19
+ def_delegators :@collection, *DELEGATED_METHODS
20
+
21
+ def initialize(collection)
22
+ @collection = collection
23
+ end
24
+
25
+ # Sets every proxy in the collection as down. For example:
26
+ #
27
+ # Toxiproxy.grep(/redis/).down { .. }
28
+ #
29
+ # Would simulate every Redis server being down for the duration of the
30
+ # block.
31
+ def down(*args, &block)
32
+ @collection.inject(block) { |nested, proxy|
33
+ -> { proxy.down(*args, &nested) }
34
+ }.call
35
+ end
36
+
37
+ # Destroys all toxiproxy's in the collection
38
+ def destroy
39
+ @collection.each(&:destroy)
40
+ end
41
+
42
+ def select(&block)
43
+ self.class.new(@collection.select(&block))
44
+ end
45
+
46
+ def reject(&block)
47
+ self.class.new(@collection.reject(&block))
48
+ end
49
+
50
+ # Grep allows easily selecting a subset of proxies, by returning a
51
+ # ProxyCollection with every proxy name matching the regex passed.
52
+ def grep(regex)
53
+ self.class.new(@collection.select { |proxy|
54
+ proxy.name =~ regex
55
+ })
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,47 @@
1
+ class Toxiproxy
2
+ class Toxic
3
+ attr_reader :name, :proxy, :direction
4
+ attr_reader :attrs
5
+
6
+ def initialize(options)
7
+ @proxy = options[:proxy]
8
+ @name = options[:name]
9
+ @direction = options[:direction]
10
+ @attrs = options[:attrs] || {}
11
+ end
12
+
13
+ def enabled?
14
+ attrs[:enabled]
15
+ end
16
+
17
+ def enable
18
+ attrs[:enabled] = true
19
+ save
20
+ end
21
+
22
+ def disable
23
+ attrs[:enabled] = false
24
+ save
25
+ end
26
+
27
+ def []=(name, value)
28
+ attrs[name] = value
29
+ end
30
+
31
+ def save
32
+ unless VALID_DIRECTIONS.include?(direction.to_sym)
33
+ raise InvalidToxic, "Toxic direction must be one of: [#{VALID_DIRECTIONS.join(', ')}], got: #{direction}"
34
+ end
35
+ request = Net::HTTP::Post.new("/proxies/#{proxy.name}/#{direction}/toxics/#{name}")
36
+
37
+ request.body = attrs.to_json
38
+
39
+ response = Toxiproxy.http.request(request)
40
+ Toxiproxy.assert_response(response)
41
+
42
+ @attrs = JSON.parse(response.body)
43
+
44
+ self
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,42 @@
1
+ class Toxiproxy
2
+ class ToxicCollection
3
+ extend Forwardable
4
+
5
+ attr_accessor :toxics
6
+ attr_reader :proxy
7
+
8
+ def_delegators :@toxics, :<<, :find
9
+
10
+ def initialize(proxy)
11
+ @proxy = proxy
12
+ @toxics = []
13
+ end
14
+
15
+ def apply(&block)
16
+ @toxics.each(&:enable)
17
+ yield
18
+ ensure
19
+ @toxics.each(&:disable)
20
+ end
21
+
22
+ def upstream(toxic_name, attrs = {})
23
+ toxics << Toxic.new(
24
+ name: toxic_name,
25
+ proxy: proxy,
26
+ direction: :upstream,
27
+ attrs: attrs
28
+ )
29
+ self
30
+ end
31
+
32
+ def downstream(toxic_name, attrs = {})
33
+ toxics << Toxic.new(
34
+ name: toxic_name,
35
+ proxy: proxy,
36
+ direction: :downstream,
37
+ attrs: attrs
38
+ )
39
+ self
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,3 @@
1
+ class Toxiproxy
2
+ VERSION = "0.0.2"
3
+ end
@@ -0,0 +1,2 @@
1
+ fetch:
2
+ - fetch-gem-version toxiproxy Shopify/toxiproxy-ruby
@@ -0,0 +1,3 @@
1
+ require 'minitest'
2
+ require 'minitest/autorun'
3
+ require_relative "../lib/toxiproxy"
@@ -0,0 +1,209 @@
1
+ require 'test_helper'
2
+
3
+ class ToxiproxyTest < MiniTest::Unit::TestCase
4
+ def teardown
5
+ Toxiproxy.grep(/\Atest_/).each(&:destroy)
6
+ end
7
+
8
+ def test_create_proxy
9
+ proxy = Toxiproxy.create(upstream: "localhost:3306", name: "test_mysql_master")
10
+
11
+ assert_equal "localhost:3306", proxy.upstream
12
+ assert_equal "test_mysql_master", proxy.name
13
+ end
14
+
15
+ def test_create_and_find_proxy
16
+ proxy = Toxiproxy.create(upstream: "localhost:3306", name: "test_mysql_master")
17
+
18
+ assert_equal "localhost:3306", proxy.upstream
19
+ assert_equal "test_mysql_master", proxy.name
20
+
21
+ proxy = Toxiproxy[:test_mysql_master]
22
+
23
+ assert_equal "localhost:3306", proxy.upstream
24
+ assert_equal "test_mysql_master", proxy.name
25
+ end
26
+
27
+ def test_take_endpoint_down
28
+ with_tcpserver do |port|
29
+ proxy = Toxiproxy.create(upstream: "localhost:#{port}", name: "test_rubby_server")
30
+ listen_addr = proxy.listen
31
+
32
+ proxy.down do
33
+ assert_proxy_unavailable proxy
34
+ end
35
+
36
+ assert_proxy_available proxy
37
+
38
+ assert_equal listen_addr, proxy.listen
39
+ end
40
+ end
41
+
42
+ def test_raises_when_proxy_doesnt_exist
43
+ assert_raises Toxiproxy::NotFound do
44
+ Toxiproxy[:does_not_exist]
45
+ end
46
+ end
47
+
48
+ def test_proxies_all_returns_proxy_collection
49
+ assert_instance_of Toxiproxy::Collection, Toxiproxy.all
50
+ end
51
+
52
+ def test_down_on_proxy_collection_disables_entire_collection
53
+ with_tcpserver do |port1|
54
+ with_tcpserver do |port2|
55
+ proxy1 = Toxiproxy.create(upstream: "localhost:#{port1}", name: "test_proxy1")
56
+ proxy2 = Toxiproxy.create(upstream: "localhost:#{port2}", name: "test_proxy2")
57
+
58
+ assert_proxy_available proxy2
59
+ assert_proxy_available proxy1
60
+
61
+ Toxiproxy.all.down do
62
+ assert_proxy_unavailable proxy1
63
+ assert_proxy_unavailable proxy2
64
+ end
65
+
66
+ assert_proxy_available proxy2
67
+ assert_proxy_available proxy1
68
+ end
69
+ end
70
+ end
71
+
72
+ def test_select_from_toxiproxy_collection
73
+ with_tcpserver do |port|
74
+ Toxiproxy.create(upstream: "localhost:#{port}", name: "test_proxy")
75
+
76
+ proxies = Toxiproxy.select { |p| p.upstream == "localhost:#{port}" }
77
+
78
+ assert_equal 1, proxies.size
79
+ assert_instance_of Toxiproxy::Collection, proxies
80
+ end
81
+ end
82
+
83
+ def test_grep_returns_toxiproxy_collection
84
+ with_tcpserver do |port|
85
+ Toxiproxy.create(upstream: "localhost:#{port}", name: "test_proxy")
86
+
87
+ proxies = Toxiproxy.grep(/\Atest/)
88
+
89
+ assert_equal 1, proxies.size
90
+ assert_instance_of Toxiproxy::Collection, proxies
91
+ end
92
+ end
93
+
94
+ def test_indexing_allows_regexp
95
+ with_tcpserver do |port|
96
+ Toxiproxy.create(upstream: "localhost:#{port}", name: "test_proxy")
97
+
98
+ proxies = Toxiproxy[/\Atest/]
99
+
100
+ assert_equal 1, proxies.size
101
+ assert_instance_of Toxiproxy::Collection, proxies
102
+ end
103
+ end
104
+
105
+ def test_apply_upstream_toxic
106
+ $before = Time.now
107
+
108
+ with_tcpserver(receive: true) do |port|
109
+ proxy = Toxiproxy.create(upstream: "localhost:#{port}", name: "test_proxy")
110
+
111
+ proxy.upstream(:latency, latency: 100).apply do
112
+ before = Time.now
113
+
114
+ socket = connect_to_proxy(proxy)
115
+ socket.write("omg\n")
116
+ socket.flush
117
+ socket.gets
118
+
119
+ passed = Time.now - before
120
+
121
+ assert_in_delta passed, 0.100, 0.01
122
+ end
123
+ end
124
+ end
125
+
126
+ def test_apply_downstream_toxic
127
+ with_tcpserver(receive: true) do |port|
128
+ proxy = Toxiproxy.create(upstream: "localhost:#{port}", name: "test_proxy")
129
+
130
+ proxy.downstream(:latency, latency: 100).apply do
131
+ before = Time.now
132
+
133
+ socket = connect_to_proxy(proxy)
134
+ socket.write("omg\n")
135
+ socket.flush
136
+ socket.gets
137
+
138
+ passed = Time.now - before
139
+
140
+ assert_in_delta passed, 0.100, 0.01
141
+ end
142
+ end
143
+ end
144
+
145
+ def test_apply_prolong_toxics
146
+ with_tcpserver(receive: true) do |port|
147
+ proxy = Toxiproxy.create(upstream: "localhost:#{port}", name: "test_proxy")
148
+
149
+ proxy.upstream(:latency, latency: 100).downstream(:latency, latency: 100).apply do
150
+ before = Time.now
151
+
152
+ socket = connect_to_proxy(proxy)
153
+ socket.write("omg\n")
154
+ socket.flush
155
+ socket.gets
156
+
157
+ passed = Time.now - before
158
+
159
+ assert_in_delta passed, 0.200, 0.01
160
+ end
161
+ end
162
+ end
163
+
164
+ private
165
+
166
+ def assert_proxy_available(proxy)
167
+ connect_to_proxy proxy
168
+ end
169
+
170
+ def assert_proxy_unavailable(proxy)
171
+ assert_raises Errno::ECONNREFUSED do
172
+ connect_to_proxy proxy
173
+ end
174
+ end
175
+
176
+ def connect_to_proxy(proxy)
177
+ TCPSocket.new(*proxy.listen.split(":".freeze))
178
+ end
179
+
180
+ def with_tcpserver(receive = false, &block)
181
+ mon = Monitor.new
182
+ cond = mon.new_cond
183
+ port = nil
184
+
185
+ thread = Thread.new {
186
+ server = TCPServer.new("127.0.0.1", 0)
187
+ port = server.addr[1]
188
+ mon.synchronize { cond.signal }
189
+ loop do
190
+ client = server.accept
191
+
192
+ if receive
193
+ client.gets
194
+ client.write("omgs\n")
195
+ client.flush
196
+ end
197
+
198
+ client.close
199
+ end
200
+ server.close
201
+ }
202
+
203
+ mon.synchronize { cond.wait }
204
+
205
+ yield(port)
206
+ ensure
207
+ thread.kill
208
+ end
209
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path("../lib/toxiproxy/version", __FILE__)
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "toxiproxy"
5
+ spec.version = Toxiproxy::VERSION
6
+ spec.authors = ["Simon Eskildsen", "Jacob Wirth"]
7
+ spec.email = "simon.eskildsen@shopify.com"
8
+ spec.summary = "Ruby library for Toxiproxy"
9
+ spec.description = "A Ruby library for controlling Toxiproxy. Can be used in resiliency testing."
10
+ spec.homepage = "https://github.com/Shopify/toxiproxy"
11
+ spec.license = "MIT"
12
+
13
+ spec.files = `git ls-files`.split("\n")
14
+ spec.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ spec.require_paths = ["lib"]
16
+
17
+ spec.add_development_dependency "bundler", "~> 1.3"
18
+ spec.add_development_dependency "minitest"
19
+ spec.add_development_dependency "rake"
20
+ end
metadata ADDED
@@ -0,0 +1,104 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: toxiproxy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.2
5
+ platform: ruby
6
+ authors:
7
+ - Simon Eskildsen
8
+ - Jacob Wirth
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2014-11-07 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: '1.3'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: '1.3'
28
+ - !ruby/object:Gem::Dependency
29
+ name: minitest
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: A Ruby library for controlling Toxiproxy. Can be used in resiliency testing.
57
+ email: simon.eskildsen@shopify.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - Gemfile
64
+ - LICENSE
65
+ - README.md
66
+ - Rakefile
67
+ - bin/start-toxiproxy.sh
68
+ - circle.yml
69
+ - lib/toxiproxy.rb
70
+ - lib/toxiproxy/collection.rb
71
+ - lib/toxiproxy/toxic.rb
72
+ - lib/toxiproxy/toxic_collection.rb
73
+ - lib/toxiproxy/version.rb
74
+ - shipit.rubygems.yml
75
+ - test/test_helper.rb
76
+ - test/toxiproxy_test.rb
77
+ - toxiproxy.gemspec
78
+ homepage: https://github.com/Shopify/toxiproxy
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.2.2
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Ruby library for Toxiproxy
102
+ test_files:
103
+ - test/test_helper.rb
104
+ - test/toxiproxy_test.rb