Skip to content

Commit 678e6a5

Browse files
committed
use toxiproxy for network failure testing
1 parent 08f6bed commit 678e6a5

File tree

6 files changed

+82
-23
lines changed

6 files changed

+82
-23
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@ rvm:
1414
- 2.7.0
1515
before_install:
1616
- docker info
17+
- docker-compose up -d
1718
- sudo ./test/bin/install-openssl.sh
1819
- sudo ./test/bin/install-freetds.sh
19-
- sudo ./test/bin/setup.sh
2020
install:
2121
- gem install bundler
2222
- bundle --version

README.md

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -423,17 +423,20 @@ First, clone the repo using the command line or your Git GUI of choice.
423423
$ git clone [email protected]:rails-sqlserver/tiny_tds.git
424424
```
425425

426-
After that, the quickest way to get setup for development is to use [Docker](https://www.docker.com/). Assuming you have [downloaded docker](https://www.docker.com/products/docker) for your platform and you have , you can run our test setup script.
426+
After that, the quickest way to get setup for development is to use [Docker](https://www.docker.com/). Assuming you have [downloaded docker](https://www.docker.com/products/docker) for your platform, you can use [docker-compose](https://docs.docker.com/compose/install/) to run the necessary containers for testing.
427427

428428
```shell
429-
$ ./test/bin/setup.sh
429+
$ docker-compose up -d
430430
```
431431

432-
This will download our SQL Server for Linux Docker image based from [microsoft/mssql-server-linux/](https://hub.docker.com/r/microsoft/mssql-server-linux/). Our image already has the `[tinytdstest]` DB and `tinytds` users created. Basically, it does the following.
432+
This will download our SQL Server for Linux Docker image based from [microsoft/mssql-server-linux/](https://hub.docker.com/r/microsoft/mssql-server-linux/). Our image already has the `[tinytdstest]` DB and `tinytds` users created. This will also download a [toxiproxy](https://github.com/shopify/toxiproxy) Docker image which we can use to simulate network failures for tests. Basically, it does the following.
433433

434434
```shell
435+
$ docker network create main-network
435436
$ docker pull metaskills/mssql-server-linux-tinytds
436-
$ docker run -p 1433:1433 -d metaskills/mssql-server-linux-tinytds
437+
$ docker run -p 1433:1433 -d --name sqlserver --network main-network metaskills/mssql-server-linux-tinytds
438+
$ docker pull shopify/toxiproxy
439+
$ docker run -p 8474:8474 -p 1234:1234 -d --name toxiproxy --network main-network shopify/toxiproxy
437440
```
438441

439442
If you are using your own database. Make sure to run these SQL commands as SA to get the test database and user installed.

docker-compose.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
version: '3'
2+
3+
networks:
4+
main-network:
5+
6+
services:
7+
mssql:
8+
image: metaskills/mssql-server-linux-tinytds:2017-GA
9+
container_name: sqlserver
10+
ports:
11+
- "1433:1433"
12+
networks:
13+
- main-network
14+
15+
toxiproxy:
16+
image: shopify/toxiproxy
17+
container_name: toxiproxy
18+
ports:
19+
- "8474:8474"
20+
- "1234:1234"
21+
networks:
22+
- main-network

test/client_test.rb

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,9 @@ class ClientTest < TinyTds::TestCase
6868
end
6969

7070
describe 'With in-valid options' do
71+
before(:all) do
72+
init_toxiproxy
73+
end
7174

7275
it 'raises an argument error when no :host given and :dataserver is blank' do
7376
assert_raises(ArgumentError) { new_connection :dataserver => nil, :host => nil }
@@ -129,27 +132,40 @@ class ClientTest < TinyTds::TestCase
129132
end
130133
end
131134

132-
it 'raises TinyTds exception with sql batch timeout due to network failure' do
135+
it 'raises TinyTds exception with tcp socket network failure' do
133136
skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
134137
begin
135-
client = new_connection timeout: 2
138+
client = new_connection timeout: 1, port: 1234
136139
assert_client_works(client)
137-
docker_container('pause', wait_for: 1)
138-
action = lambda { client.execute('SELECT 1 as [one]').each }
139-
assert_raise_tinytds_error(action) do |e|
140-
assert_equal 20003, e.db_error_number
141-
assert_equal 6, e.severity
142-
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
140+
action = lambda { client.execute("waitfor delay '00:00:02'").do }
141+
# Delay the TCP socket from closing until delay has elapsed.
142+
Toxiproxy[:sqlserver_test].toxic(:slow_close, delay: 500).apply do
143+
assert_raise_tinytds_error(action) do |e|
144+
assert_equal 20003, e.db_error_number
145+
assert_equal 6, e.severity
146+
assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
147+
end
143148
end
144149
ensure
145-
docker_container('unpause', wait_for: 1)
146-
action = lambda { client.execute('SELECT 1 as [one]').each }
147-
assert_raise_tinytds_error(action) do |e|
148-
assert_equal 20047, e.db_error_number
149-
assert_includes [1,9], e.severity
150-
assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
150+
assert_new_connections_work
151+
end
152+
end
153+
154+
it 'raises TinyTds exception with dead connection network failure' do
155+
skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
156+
begin
157+
client = new_connection timeout: 1, port: 1234
158+
assert_client_works(client)
159+
action = lambda { client.execute("waitfor delay '00:00:02'").do }
160+
# Stops all data from getting through, and closes the connection after timeout
161+
Toxiproxy[:sqlserver_test].toxic(:timeout, timeout: 500).apply do
162+
assert_raise_tinytds_error(action) do |e|
163+
assert_equal 20047, e.db_error_number
164+
assert_includes [1,9], e.severity
165+
assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
166+
end
151167
end
152-
close_client(client)
168+
ensure
153169
assert_new_connections_work
154170
end
155171
end

test/test_helper.rb

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require 'bundler' ; Bundler.require :development, :test
33
require 'tiny_tds'
44
require 'minitest/autorun'
5+
require 'toxiproxy'
56

67
TINYTDS_SCHEMAS = ['sqlserver_2000', 'sqlserver_2005', 'sqlserver_2008', 'sqlserver_2014', 'sqlserver_azure', 'sybase_ase'].freeze
78

@@ -212,9 +213,25 @@ def rollback_transaction(client)
212213
client.execute("ROLLBACK TRANSACTION").do
213214
end
214215

215-
def docker_container(cmd, wait_for: 0)
216-
system("docker #{cmd} $(docker ps --format '{{.Names}}' --filter 'ancestor=metaskills/mssql-server-linux-tinytds:2017-GA') > /dev/null")
217-
sleep(wait_for) if wait_for > 0
216+
def init_toxiproxy
217+
return if ENV['APPVEYOR_BUILD_FOLDER'] # only for CI using docker
218+
219+
# In order for toxiproxy to work for local docker instances of mssql, the containers must be on the same network
220+
# and the host used below must match the mssql container name so toxiproxy knows where to proxy to.
221+
# localhost from the perspective of toxiproxy's container is its own container an *not* the mssql container it needs to proxy to.
222+
# docker-compose.yml handles this automatically for us. In instances where someone is using their own local mssql container they'll
223+
# need to set up the networks manually and set TINYTDS_UNIT_HOST to their mssql container name
224+
# For anything other than localhost just use the environment config
225+
env_host = ENV['TINYTDS_UNIT_HOST_TEST'] || ENV['TINYTDS_UNIT_HOST'] || 'localhost'
226+
host = ['localhost', '127.0.0.1', '0.0.0.0'].include?(env_host) ? 'sqlserver' : env_host
227+
port = ENV['TINYTDS_UNIT_PORT'] || 1433
228+
Toxiproxy.populate([
229+
{
230+
name: "sqlserver_test",
231+
listen: "0.0.0.0:1234",
232+
upstream: "#{host}:#{port}"
233+
}
234+
])
218235
end
219236
end
220237
end

tiny_tds.gemspec

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,4 +26,5 @@ Gem::Specification.new do |s|
2626
s.add_development_dependency 'rake-compiler-dock', '~> 1.0'
2727
s.add_development_dependency 'minitest', '~> 5.6'
2828
s.add_development_dependency 'connection_pool', '~> 2.2'
29+
s.add_development_dependency 'toxiproxy'
2930
end

0 commit comments

Comments
 (0)