tiny_tds 2.1.0-x64-mingw32 → 2.1.4.pre-x64-mingw32

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.
@@ -5,9 +5,9 @@
5
5
  void init_tinytds_client();
6
6
 
7
7
  #define ERROR_MSG_SIZE 1024
8
+ #define ERRORS_STACK_INIT_SIZE 2
8
9
 
9
10
  typedef struct {
10
- short int is_set;
11
11
  int is_message;
12
12
  int cancel;
13
13
  char error[ERROR_MSG_SIZE];
@@ -25,7 +25,10 @@ typedef struct {
25
25
  RETCODE dbsqlok_retcode;
26
26
  short int dbcancel_sent;
27
27
  short int nonblocking;
28
- tinytds_errordata nonblocking_error;
28
+ short int nonblocking_errors_length;
29
+ short int nonblocking_errors_size;
30
+ tinytds_errordata *nonblocking_errors;
31
+ VALUE message_handler;
29
32
  } tinytds_client_userdata;
30
33
 
31
34
  typedef struct {
@@ -22,35 +22,39 @@ do_help if arg_config('--help')
22
22
 
23
23
  # Make sure to check the ports path for the configured host
24
24
  host = RbConfig::CONFIG['host']
25
- project_dir = File.join(['..']*4)
25
+ project_dir = File.expand_path("../../..", __FILE__)
26
26
  freetds_ports_dir = File.join(project_dir, 'ports', host, 'freetds', FREETDS_VERSION)
27
27
  freetds_ports_dir = File.expand_path(freetds_ports_dir)
28
28
 
29
29
  # Add all the special path searching from the original tiny_tds build
30
- # order is important here! First in, last searched.
30
+ # order is important here! First in, first searched.
31
31
  DIRS = %w(
32
- /usr/local
33
32
  /opt/local
33
+ /usr/local
34
34
  )
35
35
 
36
+ # Add the ports directory if it exists for local developer builds
37
+ DIRS.unshift(freetds_ports_dir) if File.directory?(freetds_ports_dir)
38
+
36
39
  # Grab freetds environment variable for use by people on services like
37
40
  # Heroku who they can't easily use bundler config to set directories
38
- DIRS.push(ENV['FREETDS_DIR']) if ENV.has_key?('FREETDS_DIR')
39
-
40
- # Add the ports directory if it exists for local developer builds
41
- DIRS.push(freetds_ports_dir) if File.directory?(freetds_ports_dir)
41
+ DIRS.unshift(ENV['FREETDS_DIR']) if ENV.has_key?('FREETDS_DIR')
42
42
 
43
43
  # Add the search paths for freetds configured above
44
- DIRS.each do |path|
45
- idir = "#{path}/include"
44
+ ldirs = DIRS.flat_map do |path|
46
45
  ldir = "#{path}/lib"
46
+ [ldir, "#{ldir}/freetds"]
47
+ end
47
48
 
48
- dir_config('freetds',
49
- [idir, "#{idir}/freetds"],
50
- [ldir, "#{ldir}/freetds"]
51
- )
49
+ idirs = DIRS.flat_map do |path|
50
+ idir = "#{path}/include"
51
+ [idir, "#{idir}/freetds"]
52
52
  end
53
53
 
54
+ puts "looking for freetds headers in the following directories:\n#{idirs.map{|a| " - #{a}\n"}.join}"
55
+ puts "looking for freetds library in the following directories:\n#{ldirs.map{|a| " - #{a}\n"}.join}"
56
+ dir_config('freetds', idirs, ldirs)
57
+
54
58
  have_dependencies = [
55
59
  find_header('sybfront.h'),
56
60
  find_header('sybdb.h'),
@@ -2,10 +2,10 @@
2
2
  ICONV_VERSION = ENV['TINYTDS_ICONV_VERSION'] || "1.15"
3
3
  ICONV_SOURCE_URI = "http://ftp.gnu.org/pub/gnu/libiconv/libiconv-#{ICONV_VERSION}.tar.gz"
4
4
 
5
- OPENSSL_VERSION = ENV['TINYTDS_OPENSSL_VERSION'] || '1.1.0e'
5
+ OPENSSL_VERSION = ENV['TINYTDS_OPENSSL_VERSION'] || '1.1.1d'
6
6
  OPENSSL_SOURCE_URI = "https://www.openssl.org/source/openssl-#{OPENSSL_VERSION}.tar.gz"
7
7
 
8
- FREETDS_VERSION = ENV['TINYTDS_FREETDS_VERSION'] || "1.00.27"
8
+ FREETDS_VERSION = ENV['TINYTDS_FREETDS_VERSION'] || "1.1.24"
9
9
  FREETDS_VERSION_INFO = Hash.new { |h,k|
10
10
  h[k] = {files: "http://www.freetds.org/files/stable/freetds-#{k}.tar.bz2"}
11
11
  }
@@ -6,10 +6,10 @@
6
6
 
7
7
  VALUE cTinyTdsResult;
8
8
  extern VALUE mTinyTds, cTinyTdsClient, cTinyTdsError;
9
- VALUE cBigDecimal, cDate;
9
+ VALUE cKernel, cDate;
10
10
  VALUE opt_decimal_zero, opt_float_zero, opt_one, opt_zero, opt_four, opt_19hdr, opt_onek, opt_tenk, opt_onemil, opt_onebil;
11
11
  static ID intern_new, intern_utc, intern_local, intern_localtime, intern_merge,
12
- intern_civil, intern_new_offset, intern_plus, intern_divide;
12
+ intern_civil, intern_new_offset, intern_plus, intern_divide, intern_bigd;
13
13
  static ID sym_symbolize_keys, sym_as, sym_array, sym_cache_rows, sym_first, sym_timezone, sym_local, sym_utc, sym_empty_sets;
14
14
 
15
15
 
@@ -86,26 +86,35 @@ static void dbcancel_ubf(DBPROCESS *client) {
86
86
  static void nogvl_setup(DBPROCESS *client) {
87
87
  GET_CLIENT_USERDATA(client);
88
88
  userdata->nonblocking = 1;
89
+ userdata->nonblocking_errors_length = 0;
90
+ userdata->nonblocking_errors = malloc(ERRORS_STACK_INIT_SIZE * sizeof(tinytds_errordata));
91
+ userdata->nonblocking_errors_size = ERRORS_STACK_INIT_SIZE;
89
92
  }
90
93
 
91
94
  static void nogvl_cleanup(DBPROCESS *client) {
92
95
  GET_CLIENT_USERDATA(client);
93
96
  userdata->nonblocking = 0;
97
+ userdata->timing_out = 0;
94
98
  /*
95
99
  Now that the blocking operation is done, we can finally throw any
96
100
  exceptions based on errors from SQL Server.
97
101
  */
98
- if (userdata->nonblocking_error.is_set) {
99
- userdata->nonblocking_error.is_set = 0;
102
+ for (short int i = 0; i < userdata->nonblocking_errors_length; i++) {
103
+ tinytds_errordata error = userdata->nonblocking_errors[i];
100
104
  rb_tinytds_raise_error(client,
101
- userdata->nonblocking_error.is_message,
102
- userdata->nonblocking_error.cancel,
103
- userdata->nonblocking_error.error,
104
- userdata->nonblocking_error.source,
105
- userdata->nonblocking_error.severity,
106
- userdata->nonblocking_error.dberr,
107
- userdata->nonblocking_error.oserr);
105
+ error.is_message,
106
+ error.cancel,
107
+ error.error,
108
+ error.source,
109
+ error.severity,
110
+ error.dberr,
111
+ error.oserr
112
+ );
108
113
  }
114
+
115
+ free(userdata->nonblocking_errors);
116
+ userdata->nonblocking_errors_length = 0;
117
+ userdata->nonblocking_errors_size = 0;
109
118
  }
110
119
 
111
120
  static RETCODE nogvl_dbsqlok(DBPROCESS *client) {
@@ -228,7 +237,7 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
228
237
  int data_slength = (int)data_info->precision + (int)data_info->scale + 1;
229
238
  char converted_decimal[data_slength];
230
239
  dbconvert(rwrap->client, coltype, data, data_len, SYBVARCHAR, (BYTE *)converted_decimal, -1);
231
- val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new2((char *)converted_decimal));
240
+ val = rb_funcall(cKernel, intern_bigd, 1, rb_str_new2((char *)converted_decimal));
232
241
  break;
233
242
  }
234
243
  case SYBFLT8: {
@@ -246,7 +255,7 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
246
255
  char converted_money[25];
247
256
  long long money_value = ((long long)money->mnyhigh << 32) | money->mnylow;
248
257
  sprintf(converted_money, "%" LONG_LONG_FORMAT, money_value);
249
- val = rb_funcall(cBigDecimal, intern_new, 2, rb_str_new2(converted_money), opt_four);
258
+ val = rb_funcall(cKernel, intern_bigd, 2, rb_str_new2(converted_money), opt_four);
250
259
  val = rb_funcall(val, intern_divide, 1, opt_tenk);
251
260
  break;
252
261
  }
@@ -254,7 +263,7 @@ static VALUE rb_tinytds_result_fetch_row(VALUE self, ID timezone, int symbolize_
254
263
  DBMONEY4 *money = (DBMONEY4 *)data;
255
264
  char converted_money[20];
256
265
  sprintf(converted_money, "%f", money->mny4 / 10000.0);
257
- val = rb_funcall(cBigDecimal, intern_new, 1, rb_str_new2(converted_money));
266
+ val = rb_funcall(cKernel, intern_bigd, 1, rb_str_new2(converted_money));
258
267
  break;
259
268
  }
260
269
  case SYBBINARY:
@@ -566,7 +575,7 @@ static VALUE rb_tinytds_result_insert(VALUE self) {
566
575
 
567
576
  void init_tinytds_result() {
568
577
  /* Data Classes */
569
- cBigDecimal = rb_const_get(rb_cObject, rb_intern("BigDecimal"));
578
+ cKernel = rb_const_get(rb_cObject, rb_intern("Kernel"));
570
579
  cDate = rb_const_get(rb_cObject, rb_intern("Date"));
571
580
  /* Define TinyTds::Result */
572
581
  cTinyTdsResult = rb_define_class_under(mTinyTds, "Result", rb_cObject);
@@ -588,6 +597,7 @@ void init_tinytds_result() {
588
597
  intern_new_offset = rb_intern("new_offset");
589
598
  intern_plus = rb_intern("+");
590
599
  intern_divide = rb_intern("/");
600
+ intern_bigd = rb_intern("BigDecimal");
591
601
  /* Symbol Helpers */
592
602
  sym_symbolize_keys = ID2SYM(rb_intern("symbolize_keys"));
593
603
  sym_as = ID2SYM(rb_intern("as"));
@@ -8,7 +8,7 @@ task 'gem:windows' => ['ports:cross'] do
8
8
  build = ['bundle']
9
9
 
10
10
  # and finally build the native gem
11
- build << 'rake cross native gem RUBY_CC_VERSION=2.4.0:2.3.0:2.2.2:2.1.6:2.0.0 CFLAGS="-Wall"'
11
+ build << 'rake cross native gem RUBY_CC_VERSION=2.7.0:2.6.0:2.5.0:2.4.0 CFLAGS="-Wall" MAKE="make -j`nproc`"'
12
12
 
13
13
  RakeCompilerDock.sh build.join(' && ')
14
14
  end
@@ -6,14 +6,14 @@ require_relative 'ports/openssl'
6
6
  require_relative 'ports/freetds'
7
7
  require_relative '../ext/tiny_tds/extconsts'
8
8
 
9
- OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE if defined? OpenSSL
10
-
11
9
  namespace :ports do
12
10
  openssl = Ports::Openssl.new(OPENSSL_VERSION)
13
11
  libiconv = Ports::Libiconv.new(ICONV_VERSION)
14
12
  freetds = Ports::Freetds.new(FREETDS_VERSION)
15
13
 
16
14
  directory "ports"
15
+ CLEAN.include "ports/*mingw32*"
16
+ CLEAN.include "ports/*.installed"
17
17
 
18
18
  task :openssl, [:host] do |task, args|
19
19
  args.with_defaults(host: RbConfig::CONFIG['host'])
@@ -71,15 +71,13 @@ namespace :ports do
71
71
  task 'cross' do
72
72
  require 'rake_compiler_dock'
73
73
 
74
- # make sure to install our bundle
75
- build = ['bundle']
76
-
77
74
  # build the ports for all our cross compile hosts
78
75
  GEM_PLATFORM_HOSTS.each do |gem_platform, host|
79
- build << "rake ports:compile[#{host}]"
76
+ # make sure to install our bundle
77
+ build = ['bundle']
78
+ build << "rake ports:compile[#{host}] MAKE='make -j`nproc`'"
79
+ RakeCompilerDock.sh build.join(' && '), platform: gem_platform
80
80
  end
81
-
82
- RakeCompilerDock.sh build.join(' && ')
83
81
  end
84
82
  end
85
83
 
@@ -27,27 +27,11 @@ module Ports
27
27
 
28
28
  private
29
29
 
30
- def execute(action, command, options={})
31
- # OpenSSL Requires Perl >= 5.10, while the Ruby devkit uses MSYS1 with Perl 5.8.8.
32
- # To overcome this, prepend Git's usr/bin to the PATH.
33
- # It has MSYS2 with a recent version of perl.
34
- prev_path = ENV['PATH']
35
- if host =~ /mingw/ && IO.popen(["perl", "-e", "print($])"], &:read).to_f < 5.010
36
- git_perl = 'C:/Program Files/Git/usr/bin'
37
- if File.directory?(git_perl)
38
- ENV['PATH'] = "#{git_perl}#{File::PATH_SEPARATOR}#{ENV['PATH']}"
39
- ENV['PERL'] = 'perl'
40
- end
41
- end
42
-
43
- super
44
- ENV['PATH'] = prev_path
45
- end
46
-
47
30
  def configure_defaults
48
31
  opts = [
49
32
  'shared',
50
- target_arch
33
+ target_arch,
34
+ "--openssldir=#{path}",
51
35
  ]
52
36
 
53
37
  if cross_build?
@@ -3,7 +3,7 @@
3
3
  set -x
4
4
  set -e
5
5
 
6
- tag=2.0
6
+ tag=2017-GA
7
7
 
8
8
  docker pull metaskills/mssql-server-linux-tinytds:$tag
9
9
 
@@ -2,9 +2,7 @@
2
2
  require 'test_helper'
3
3
 
4
4
  class ClientTest < TinyTds::TestCase
5
-
6
- describe 'With valid credentials' do
7
-
5
+ describe 'with valid credentials' do
8
6
  before do
9
7
  @client = new_connection
10
8
  end
@@ -67,7 +65,6 @@ class ClientTest < TinyTds::TestCase
67
65
  client.close if client
68
66
  end
69
67
  end unless sqlserver_azure?
70
-
71
68
  end
72
69
 
73
70
  describe 'With in-valid options' do
@@ -132,14 +129,12 @@ class ClientTest < TinyTds::TestCase
132
129
  end
133
130
  end
134
131
 
135
- it 'must run this test to prove we account for dropped connections' do
136
- skip
132
+ it 'raises TinyTds exception with sql batch timeout due to network failure' do
133
+ skip if ENV['CI'] && ENV['APPVEYOR_BUILD_FOLDER'] # only CI using docker
137
134
  begin
138
- client = new_connection :login_timeout => 2, :timeout => 2
135
+ client = new_connection timeout: 2
139
136
  assert_client_works(client)
140
- STDOUT.puts "Disconnect network!"
141
- sleep 10
142
- STDOUT.puts "This should not get stuck past 6 seconds!"
137
+ docker_container('pause', wait_for: 1)
143
138
  action = lambda { client.execute('SELECT 1 as [one]').each }
144
139
  assert_raise_tinytds_error(action) do |e|
145
140
  assert_equal 20003, e.db_error_number
@@ -147,12 +142,11 @@ class ClientTest < TinyTds::TestCase
147
142
  assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
148
143
  end
149
144
  ensure
150
- STDOUT.puts "Reconnect network!"
151
- sleep 10
145
+ docker_container('unpause', wait_for: 1)
152
146
  action = lambda { client.execute('SELECT 1 as [one]').each }
153
147
  assert_raise_tinytds_error(action) do |e|
154
148
  assert_equal 20047, e.db_error_number
155
- assert_equal 1, e.severity
149
+ assert_includes [1,9], e.severity
156
150
  assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
157
151
  end
158
152
  close_client(client)
@@ -174,57 +168,68 @@ class ClientTest < TinyTds::TestCase
174
168
 
175
169
  end
176
170
 
177
- describe 'Private methods' do
178
-
171
+ describe '#parse_username' do
179
172
  let(:client) { @client = new_connection }
180
173
 
181
- it '#parse_username returns username if azure is not true' do
182
- username = 'user@abc123.database.windows.net'
183
- client.send(:parse_username, username: username).must_equal username
174
+ it 'returns username if azure is not true' do
175
+ _(
176
+ client.send(:parse_username, username: 'user@abc123.database.windows.net')
177
+ ).must_equal 'user@abc123.database.windows.net'
184
178
  end
185
179
 
186
- it '#parse_username returns short username if azure is true' do
187
- client.send(:parse_username,
188
- username: 'user@abc123.database.windows.net',
189
- host: 'abc123.database.windows.net',
190
- azure: true
180
+ it 'returns short username if azure is true' do
181
+ _(
182
+ client.send(
183
+ :parse_username,
184
+ username: 'user@abc123.database.windows.net',
185
+ host: 'abc123.database.windows.net',
186
+ azure: true
187
+ )
191
188
  ).must_equal 'user@abc123'
192
189
  end
193
190
 
194
- it '#parse_username returns full username if azure is false' do
195
- client.send(:parse_username,
196
- username: 'user@abc123.database.windows.net',
197
- host: 'abc123.database.windows.net',
198
- azure: false
191
+ it 'returns full username if azure is false' do
192
+ _(
193
+ client.send(
194
+ :parse_username,
195
+ username: 'user@abc123.database.windows.net',
196
+ host: 'abc123.database.windows.net',
197
+ azure: false
198
+ )
199
199
  ).must_equal 'user@abc123.database.windows.net'
200
200
  end
201
201
 
202
- it '#parse_username returns short username if passed and azure is true' do
203
- client.send(:parse_username,
204
- username: 'user@abc123',
205
- host: 'abc123.database.windows.net',
206
- azure: true
202
+ it 'returns short username if passed and azure is true' do
203
+ _(
204
+ client.send(
205
+ :parse_username,
206
+ username: 'user@abc123',
207
+ host: 'abc123.database.windows.net',
208
+ azure: true
209
+ )
207
210
  ).must_equal 'user@abc123'
208
211
  end
209
212
 
210
- it '#parse_username returns username with servername if passed and azure is true' do
211
- client.send(:parse_username,
212
- username: 'user',
213
- host: 'abc123.database.windows.net',
214
- azure: true
213
+ it 'returns username with servername if passed and azure is true' do
214
+ _(
215
+ client.send(
216
+ :parse_username,
217
+ username: 'user',
218
+ host: 'abc123.database.windows.net',
219
+ azure: true
220
+ )
215
221
  ).must_equal 'user@abc123'
216
222
  end
217
223
 
218
- it '#parse_username returns username with servername if passed and azure is false' do
219
- client.send(:parse_username,
220
- username: 'user',
221
- host: 'abc123.database.windows.net',
222
- azure: false
224
+ it 'returns username with servername if passed and azure is false' do
225
+ _(
226
+ client.send(
227
+ :parse_username,
228
+ username: 'user',
229
+ host: 'abc123.database.windows.net',
230
+ azure: false
231
+ )
223
232
  ).must_equal 'user'
224
233
  end
225
-
226
234
  end
227
-
228
-
229
235
  end
230
-
@@ -21,13 +21,13 @@ class GemTest < MiniTest::Spec
21
21
  let(:root_path) { TinyTds::Gem.root_path }
22
22
 
23
23
  it 'should be the root path' do
24
- root_path.must_equal gem_root
24
+ _(root_path).must_equal gem_root
25
25
  end
26
26
 
27
27
  it 'should be the root path no matter the cwd' do
28
28
  Dir.chdir '/'
29
29
 
30
- root_path.must_equal gem_root
30
+ _(root_path).must_equal gem_root
31
31
  end
32
32
  end
33
33
 
@@ -35,19 +35,19 @@ class GemTest < MiniTest::Spec
35
35
  let(:ports_root_path) { TinyTds::Gem.ports_root_path }
36
36
 
37
37
  it 'should be the ports path' do
38
- ports_root_path.must_equal File.join(gem_root,'ports')
38
+ _(ports_root_path).must_equal File.join(gem_root,'ports')
39
39
  end
40
40
 
41
41
  it 'should be the ports path no matter the cwd' do
42
42
  Dir.chdir '/'
43
43
 
44
- ports_root_path.must_equal File.join(gem_root,'ports')
44
+ _(ports_root_path).must_equal File.join(gem_root,'ports')
45
45
  end
46
46
  end
47
47
 
48
48
  describe '#ports_bin_paths' do
49
49
  let(:ports_bin_paths) { TinyTds::Gem.ports_bin_paths }
50
-
50
+
51
51
  describe 'when the ports directories exist' do
52
52
  let(:fake_bin_paths) do
53
53
  ports_host_root = File.join(gem_root, 'ports', 'fake-host-with-dirs')
@@ -74,12 +74,12 @@ class GemTest < MiniTest::Spec
74
74
  end
75
75
 
76
76
  it 'should return all the bin directories' do
77
- ports_bin_paths.sort.must_equal fake_bin_paths.sort
77
+ _(ports_bin_paths.sort).must_equal fake_bin_paths.sort
78
78
  end
79
79
 
80
80
  it 'should return all the bin directories regardless of cwd' do
81
81
  Dir.chdir '/'
82
- ports_bin_paths.sort.must_equal fake_bin_paths.sort
82
+ _(ports_bin_paths.sort).must_equal fake_bin_paths.sort
83
83
  end
84
84
  end
85
85
 
@@ -89,19 +89,19 @@ class GemTest < MiniTest::Spec
89
89
  end
90
90
 
91
91
  it 'should return no directories' do
92
- ports_bin_paths.must_be_empty
92
+ _(ports_bin_paths).must_be_empty
93
93
  end
94
94
 
95
95
  it 'should return no directories regardless of cwd' do
96
96
  Dir.chdir '/'
97
- ports_bin_paths.must_be_empty
97
+ _(ports_bin_paths).must_be_empty
98
98
  end
99
99
  end
100
100
  end
101
101
 
102
102
  describe '#ports_lib_paths' do
103
103
  let(:ports_lib_paths) { TinyTds::Gem.ports_lib_paths }
104
-
104
+
105
105
  describe 'when the ports directories exist' do
106
106
  let(:fake_lib_paths) do
107
107
  ports_host_root = File.join(gem_root, 'ports', 'fake-host-with-dirs')
@@ -128,12 +128,12 @@ class GemTest < MiniTest::Spec
128
128
  end
129
129
 
130
130
  it 'should return all the lib directories' do
131
- ports_lib_paths.sort.must_equal fake_lib_paths.sort
131
+ _(ports_lib_paths.sort).must_equal fake_lib_paths.sort
132
132
  end
133
133
 
134
134
  it 'should return all the lib directories regardless of cwd' do
135
135
  Dir.chdir '/'
136
- ports_lib_paths.sort.must_equal fake_lib_paths.sort
136
+ _(ports_lib_paths.sort).must_equal fake_lib_paths.sort
137
137
  end
138
138
  end
139
139
 
@@ -144,12 +144,12 @@ class GemTest < MiniTest::Spec
144
144
 
145
145
 
146
146
  it 'should return no directories' do
147
- ports_lib_paths.must_be_empty
147
+ _(ports_lib_paths).must_be_empty
148
148
  end
149
149
 
150
150
  it 'should return no directories regardless of cwd' do
151
151
  Dir.chdir '/'
152
- ports_lib_paths.must_be_empty
152
+ _(ports_lib_paths).must_be_empty
153
153
  end
154
154
  end
155
155
  end
@@ -169,7 +169,7 @@ class GemTest < MiniTest::Spec
169
169
  end
170
170
 
171
171
  it "should return a #{expected} ports host" do
172
- TinyTds::Gem.ports_host.must_equal expected
172
+ _(TinyTds::Gem.ports_host).must_equal expected
173
173
  end
174
174
  end
175
175
  end