tiny_tds 2.1.2 → 3.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.
Files changed (64) hide show
  1. checksums.yaml +5 -5
  2. data/.github/workflows/ci.yml +590 -0
  3. data/.gitignore +2 -0
  4. data/CHANGELOG.md +51 -1
  5. data/Gemfile +1 -8
  6. data/ISSUE_TEMPLATE.md +1 -1
  7. data/README.md +89 -89
  8. data/Rakefile +44 -30
  9. data/VERSION +1 -1
  10. data/docker-compose.yml +34 -0
  11. data/ext/tiny_tds/client.c +100 -59
  12. data/ext/tiny_tds/client.h +5 -3
  13. data/ext/tiny_tds/extconf.rb +173 -52
  14. data/ext/tiny_tds/extconsts.rb +4 -11
  15. data/ext/tiny_tds/result.c +52 -45
  16. data/ext/tiny_tds/tiny_tds_ext.c +4 -1
  17. data/lib/tiny_tds/bin.rb +12 -26
  18. data/lib/tiny_tds/client.rb +38 -42
  19. data/lib/tiny_tds/error.rb +0 -2
  20. data/lib/tiny_tds/gem.rb +5 -14
  21. data/lib/tiny_tds/result.rb +0 -2
  22. data/lib/tiny_tds/version.rb +1 -1
  23. data/lib/tiny_tds.rb +28 -47
  24. data/setup_cimgruby_dev.sh +25 -0
  25. data/start_dev.sh +21 -0
  26. data/tasks/native_gem.rake +12 -10
  27. data/tasks/package.rake +1 -3
  28. data/tasks/ports.rake +14 -77
  29. data/tasks/test.rake +3 -5
  30. data/test/bin/install-freetds.sh +2 -4
  31. data/test/bin/install-mssql.ps1 +42 -0
  32. data/test/bin/install-mssqltools.sh +9 -0
  33. data/test/bin/restore-from-native-gem.ps1 +10 -0
  34. data/test/bin/setup_tinytds_db.sh +7 -0
  35. data/test/bin/setup_volume_permissions.sh +10 -0
  36. data/test/client_test.rb +152 -116
  37. data/test/gem_test.rb +39 -118
  38. data/test/result_test.rb +285 -350
  39. data/test/schema_test.rb +369 -395
  40. data/test/sql/db-create.sql +18 -0
  41. data/test/sql/db-login.sql +38 -0
  42. data/test/test_helper.rb +112 -85
  43. data/test/thread_test.rb +22 -31
  44. data/tiny_tds.gemspec +28 -26
  45. metadata +85 -59
  46. data/.travis.yml +0 -24
  47. data/BACKERS.md +0 -32
  48. data/appveyor.yml +0 -51
  49. data/tasks/ports/freetds.rb +0 -37
  50. data/tasks/ports/libiconv.rb +0 -43
  51. data/tasks/ports/openssl.rb +0 -78
  52. data/tasks/ports/recipe.rb +0 -52
  53. data/test/appveyor/dbsetup.ps1 +0 -27
  54. data/test/appveyor/dbsetup.sql +0 -9
  55. data/test/benchmark/query.rb +0 -77
  56. data/test/benchmark/query_odbc.rb +0 -106
  57. data/test/benchmark/query_tinytds.rb +0 -126
  58. data/test/bin/setup.sh +0 -19
  59. data/test/schema/sqlserver_2000.sql +0 -140
  60. data/test/schema/sqlserver_2005.sql +0 -140
  61. data/test/schema/sqlserver_2014.sql +0 -140
  62. data/test/schema/sqlserver_2016.sql +0 -140
  63. data/test/schema/sybase_ase.sql +0 -138
  64. /data/test/schema/{sqlserver_2008.sql → sqlserver_2017.sql} +0 -0
data/tasks/ports.rake CHANGED
@@ -1,87 +1,24 @@
1
- # encoding: UTF-8
2
- require 'mini_portile2'
3
- require 'fileutils'
4
- require_relative 'ports/libiconv'
5
- require_relative 'ports/openssl'
6
- require_relative 'ports/freetds'
7
- require_relative '../ext/tiny_tds/extconsts'
8
-
9
- OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE if defined? OpenSSL
1
+ require_relative "../ext/tiny_tds/extconsts"
10
2
 
11
3
  namespace :ports do
12
- openssl = Ports::Openssl.new(OPENSSL_VERSION)
13
- libiconv = Ports::Libiconv.new(ICONV_VERSION)
14
- freetds = Ports::Freetds.new(FREETDS_VERSION)
15
-
16
- directory "ports"
17
-
18
- task :openssl, [:host] do |task, args|
19
- args.with_defaults(host: RbConfig::CONFIG['host'])
4
+ libraries_to_compile = {
5
+ openssl: OPENSSL_VERSION,
6
+ libiconv: ICONV_VERSION,
7
+ freetds: FREETDS_VERSION
8
+ }
20
9
 
21
- openssl.files = [OPENSSL_SOURCE_URI]
22
- openssl.host = args.host
23
- openssl.cook
24
- openssl.activate
25
- end
26
-
27
- task :libiconv, [:host] do |task, args|
28
- args.with_defaults(host: RbConfig::CONFIG['host'])
10
+ desc "Notes the actual versions for the compiled ports into a file"
11
+ task "version_file", [:gem_platform] do |_task, args|
12
+ args.with_defaults(gem_platform: RbConfig::CONFIG["arch"])
29
13
 
30
- libiconv.files = [ICONV_SOURCE_URI]
31
- libiconv.host = args.host
32
- libiconv.cook
33
- libiconv.activate
34
- end
14
+ ports_version = {}
35
15
 
36
- task :freetds, [:host] do |task, args|
37
- args.with_defaults(host: RbConfig::CONFIG['host'])
38
-
39
- freetds.files = [FREETDS_SOURCE_URI]
40
- freetds.host = args.host
41
-
42
- if openssl
43
- # freetds doesn't have an option that will provide an rpath
44
- # so we do it manually
45
- ENV['OPENSSL_CFLAGS'] = "-Wl,-rpath -Wl,#{openssl.path}/lib"
46
- # Add the pkgconfig file with MSYS2'ish path, to prefer our ports build
47
- # over MSYS2 system OpenSSL.
48
- ENV['PKG_CONFIG_PATH'] = "#{openssl.path.gsub(/^(\w):/i){"/"+$1.downcase}}/lib/pkgconfig:#{ENV['PKG_CONFIG_PATH']}"
49
- freetds.configure_options << "--with-openssl=#{openssl.path}"
16
+ libraries_to_compile.each do |library, version|
17
+ ports_version[library] = version
50
18
  end
51
19
 
52
- if libiconv
53
- freetds.configure_options << "--with-libiconv-prefix=#{libiconv.path}"
54
- end
20
+ ports_version[:platform] = args.gem_platform
55
21
 
56
- freetds.cook
57
- freetds.activate
58
- end
59
-
60
- task :compile, [:host] do |task,args|
61
- args.with_defaults(host: RbConfig::CONFIG['host'])
62
-
63
- puts "Compiling ports for #{args.host}..."
64
-
65
- ['openssl','libiconv','freetds'].each do |lib|
66
- Rake::Task["ports:#{lib}"].invoke(args.host)
67
- end
68
- end
69
-
70
- desc 'Build the ports windows binaries via rake-compiler-dock'
71
- task 'cross' do
72
- require 'rake_compiler_dock'
73
-
74
- # make sure to install our bundle
75
- build = ['bundle']
76
-
77
- # build the ports for all our cross compile hosts
78
- GEM_PLATFORM_HOSTS.each do |gem_platform, host|
79
- build << "rake ports:compile[#{host}] MAKE='make -j`nproc`'"
80
- end
81
-
82
- RakeCompilerDock.sh build.join(' && ')
22
+ File.write(".ports_versions", ports_version)
83
23
  end
84
24
  end
85
-
86
- desc 'Build ports and activate libraries for the current architecture.'
87
- task :ports => ['ports:compile']
data/tasks/test.rake CHANGED
@@ -1,9 +1,7 @@
1
- # encoding: UTF-8
2
- require 'rake/testtask'
1
+ require "rake/testtask"
3
2
 
4
3
  Rake::TestTask.new do |t|
5
- t.libs << 'test'
6
- t.test_files = FileList['test/**/*_test.rb']
4
+ t.libs << "test"
5
+ t.test_files = FileList["test/**/*_test.rb"]
7
6
  t.verbose = true
8
7
  end
9
-
@@ -10,11 +10,9 @@ fi
10
10
  wget http://www.freetds.org/files/stable/freetds-$FREETDS_VERSION.tar.gz
11
11
  tar -xzf freetds-$FREETDS_VERSION.tar.gz
12
12
  cd freetds-$FREETDS_VERSION
13
- ./configure --prefix=/opt/local \
14
- --with-openssl=/opt/local \
15
- --with-tdsver=7.3
13
+ ./configure
16
14
  make
17
- make install
15
+ sudo make install
18
16
  cd ..
19
17
  rm -rf freetds-$FREETDS_VERSION
20
18
  rm freetds-$FREETDS_VERSION.tar.gz
@@ -0,0 +1,42 @@
1
+ param ([int] $Version)
2
+
3
+ $ProgressPreference = 'SilentlyContinue'
4
+
5
+ $DownloadLinkTable = @{
6
+ 2017 = "https://go.microsoft.com/fwlink/?linkid=829176";
7
+ 2019 = "https://download.microsoft.com/download/7/c/1/7c14e92e-bdcb-4f89-b7cf-93543e7112d1/SQLEXPR_x64_ENU.exe";
8
+ 2022 = "https://download.microsoft.com/download/3/8/d/38de7036-2433-4207-8eae-06e247e17b25/SQLEXPR_x64_ENU.exe";
9
+ }
10
+
11
+ $MajorVersionTable = @{
12
+ 2017 = 14;
13
+ 2019 = 15;
14
+ 2022 = 16;
15
+ }
16
+
17
+ if (-not(Test-path "C:\Downloads")) {
18
+ mkdir "C:\Downloads"
19
+ }
20
+
21
+ $sqlInstallationFile = "C:\Downloads\sqlexpress.exe"
22
+ if (-not(Test-path $sqlInstallationFile -PathType leaf)) {
23
+ Write-Host "Downloading SQL Express ..."
24
+ Invoke-WebRequest -Uri $DownloadLinkTable[$Version] -OutFile "C:\Downloads\sqlexpress.exe"
25
+ }
26
+
27
+ Write-Host "Installing SQL Express ..."
28
+ Start-Process -Wait -FilePath "C:\Downloads\sqlexpress.exe" -ArgumentList /qs, /x:"C:\Downloads\setup"
29
+ C:\Downloads\setup\setup.exe /q /ACTION=Install /INSTANCENAME=SQLEXPRESS /FEATURES=SQLEngine /UPDATEENABLED=0 /SQLSVCACCOUNT='NT AUTHORITY\System' /SQLSYSADMINACCOUNTS='BUILTIN\ADMINISTRATORS' /TCPENABLED=1 /NPENABLED=0 /IACCEPTSQLSERVERLICENSETERMS
30
+
31
+ Write-Host "Configuring SQL Express ..."
32
+ stop-service MSSQL`$SQLEXPRESS
33
+ set-itemproperty -path "HKLM:\software\microsoft\microsoft sql server\mssql$($MajorVersionTable[$Version]).SQLEXPRESS\mssqlserver\supersocketnetlib\tcp\ipall" -name tcpdynamicports -value ''
34
+ set-itemproperty -path "HKLM:\software\microsoft\microsoft sql server\mssql$($MajorVersionTable[$Version]).SQLEXPRESS\mssqlserver\supersocketnetlib\tcp\ipall" -name tcpport -value 1433
35
+ set-itemproperty -path "HKLM:\software\microsoft\microsoft sql server\mssql$($MajorVersionTable[$Version]).SQLEXPRESS\mssqlserver\" -name LoginMode -value 2
36
+
37
+ Write-Host "Starting SQL Express ..."
38
+ start-service MSSQL`$SQLEXPRESS
39
+
40
+ Write-Host "Configuring MSSQL for TinyTDS ..."
41
+ & sqlcmd -i './test/sql/db-create.sql'
42
+ & sqlcmd -i './test/sql/db-login.sql'
@@ -0,0 +1,9 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -x
4
+ set -e
5
+
6
+ curl https://packages.microsoft.com/keys/microsoft.asc | sudo apt-key add -
7
+ curl https://packages.microsoft.com/config/ubuntu/20.04/prod.list | sudo tee /etc/apt/sources.list.d/msprod.list
8
+ sudo apt-get update
9
+ sudo ACCEPT_EULA=Y apt-get -y install mssql-tools unixodbc-dev
@@ -0,0 +1,10 @@
1
+ $gemVersion = (Get-Content VERSION).Trim()
2
+ $gemToUnpack = "./tiny_tds-$gemVersion-$env:RUBY_ARCHITECTURE.gem"
3
+
4
+ Write-Host "Looking to unpack $gemToUnpack"
5
+ gem unpack --target ./tmp "$gemToUnpack"
6
+
7
+ # Restore precompiled code
8
+ $source = (Resolve-Path ".\tmp\tiny_tds-$gemVersion-$env:RUBY_ARCHITECTURE\lib\tiny_tds").Path
9
+ $destination = (Resolve-Path ".\lib\tiny_tds").Path
10
+ Get-ChildItem $source -Recurse -Exclude "*.rb" | Copy-Item -Destination {Join-Path $destination $_.FullName.Substring($source.length)}
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -x
4
+ set -e
5
+
6
+ /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -i ./test/sql/db-create.sql
7
+ /opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P $SA_PASSWORD -i ./test/sql/db-login.sql
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env bash
2
+
3
+ set -x
4
+
5
+ sudo groupadd -g 3434 circleci_tinytds
6
+ sudo usermod -a -G circleci_tinytds $USER
7
+ sudo useradd circleci_tinytds -u 3434 -g 3434
8
+ sudo usermod -a -G circleci_tinytds circleci_tinytds
9
+ sudo chgrp -R circleci_tinytds .
10
+ sudo chmod -R g+rwx .
data/test/client_test.rb CHANGED
@@ -1,126 +1,123 @@
1
- # encoding: utf-8
2
- require 'test_helper'
1
+ require "test_helper"
3
2
 
4
3
  class ClientTest < TinyTds::TestCase
5
-
6
- describe 'With valid credentials' do
7
-
4
+ describe "with valid credentials" do
8
5
  before do
9
6
  @client = new_connection
10
7
  end
11
8
 
12
- it 'must not be closed' do
9
+ it "must not be closed" do
13
10
  assert !@client.closed?
14
11
  assert @client.active?
15
12
  end
16
13
 
17
- it 'allows client connection to be closed' do
14
+ it "allows client connection to be closed" do
18
15
  assert @client.close
19
16
  assert @client.closed?
20
17
  assert !@client.active?
21
- action = lambda { @client.execute('SELECT 1 as [one]').each }
18
+ assert @client.dead?
19
+ action = lambda { @client.execute("SELECT 1 as [one]").each }
22
20
  assert_raise_tinytds_error(action) do |e|
23
- assert_match %r{closed connection}i, e.message, 'ignore if non-english test run'
21
+ assert_match %r{closed connection}i, e.message, "ignore if non-english test run"
24
22
  end
25
23
  end
26
24
 
27
- it 'has getters for the tds version information (brittle since conf takes precedence)' do
28
- if sybase_ase?
29
- assert_equal 7, @client.tds_version
30
- assert_equal 'DBTDS_5_0 - 5.0 SQL Server', @client.tds_version_info
31
- elsif @client.tds_73?
25
+ it "has getters for the tds version information (brittle since conf takes precedence)" do
26
+ if @client.tds_73?
32
27
  assert_equal 11, @client.tds_version
33
- assert_equal 'DBTDS_7_3 - Microsoft SQL Server 2008', @client.tds_version_info
28
+ assert_equal "DBTDS_7_3 - Microsoft SQL Server 2008", @client.tds_version_info
34
29
  else
35
30
  assert_equal 9, @client.tds_version
36
- assert_equal 'DBTDS_7_1/DBTDS_8_0 - Microsoft SQL Server 2000', @client.tds_version_info
31
+ assert_equal "DBTDS_7_1/DBTDS_8_0 - Microsoft SQL Server 2000", @client.tds_version_info
37
32
  end
38
33
  end
39
34
 
40
- it 'uses UTF-8 client charset/encoding by default' do
41
- assert_equal 'UTF-8', @client.charset
42
- assert_equal Encoding.find('UTF-8'), @client.encoding
35
+ it "uses UTF-8 client charset/encoding by default" do
36
+ assert_equal "UTF-8", @client.charset
37
+ assert_equal Encoding.find("UTF-8"), @client.encoding
43
38
  end
44
39
 
45
- it 'has a #escape method used for quote strings' do
40
+ it "has a #escape method used for quote strings" do
46
41
  assert_equal "''hello''", @client.escape("'hello'")
47
42
  end
48
43
 
49
- ['CP850', 'CP1252', 'ISO-8859-1'].each do |encoding|
44
+ ["CP850", "CP1252", "ISO-8859-1"].each do |encoding|
50
45
  it "allows valid iconv character set - #{encoding}" do
46
+ client = new_connection(encoding: encoding)
47
+ assert_equal encoding, client.charset
48
+ assert_equal Encoding.find(encoding), client.encoding
49
+ ensure
50
+ client&.close
51
+ end
52
+ end
53
+
54
+ unless sqlserver_azure?
55
+ it "must be able to use :host/:port connection" do
56
+ host = ENV["TINYTDS_UNIT_HOST_TEST"] || ENV["TINYTDS_UNIT_HOST"] || "localhost"
57
+ port = ENV["TINYTDS_UNIT_PORT_TEST"] || ENV["TINYTDS_UNIT_PORT"] || 1433
51
58
  begin
52
- client = new_connection(:encoding => encoding)
53
- assert_equal encoding, client.charset
54
- assert_equal Encoding.find(encoding), client.encoding
59
+ client = new_connection dataserver: nil, host: host, port: port
55
60
  ensure
56
- client.close if client
61
+ client&.close
57
62
  end
58
63
  end
59
64
  end
60
-
61
- it 'must be able to use :host/:port connection' do
62
- host = ENV['TINYTDS_UNIT_HOST_TEST'] || ENV['TINYTDS_UNIT_HOST'] || 'localhost'
63
- port = ENV['TINYTDS_UNIT_PORT_TEST'] || ENV['TINYTDS_UNIT_PORT'] || 1433
64
- begin
65
- client = new_connection dataserver: nil, host: host, port: port
66
- ensure
67
- client.close if client
68
- end
69
- end unless sqlserver_azure?
70
-
71
65
  end
72
66
 
73
- describe 'With in-valid options' do
67
+ describe "With in-valid options" do
68
+ before(:all) do
69
+ init_toxiproxy
70
+ end
74
71
 
75
- it 'raises an argument error when no :host given and :dataserver is blank' do
76
- assert_raises(ArgumentError) { new_connection :dataserver => nil, :host => nil }
72
+ it "raises an argument error when no :host given and :dataserver is blank" do
73
+ assert_raises(ArgumentError) { new_connection dataserver: nil, host: nil }
77
74
  end
78
75
 
79
- it 'raises an argument error when no :username is supplied' do
80
- assert_raises(ArgumentError) { TinyTds::Client.new :username => nil }
76
+ it "raises an argument error when no :username is supplied" do
77
+ assert_raises(ArgumentError) { TinyTds::Client.new username: nil }
81
78
  end
82
79
 
83
- it 'raises TinyTds exception with undefined :dataserver' do
84
- options = connection_options :login_timeout => 1, :dataserver => 'DOESNOTEXIST'
80
+ it "raises TinyTds exception with undefined :dataserver" do
81
+ options = connection_options login_timeout: 1, dataserver: "DOESNOTEXIST"
85
82
  action = lambda { new_connection(options) }
86
83
  assert_raise_tinytds_error(action) do |e|
87
84
  # Not sure why tese are different.
88
85
  if ruby_darwin?
89
86
  assert_equal 20009, e.db_error_number
90
87
  assert_equal 9, e.severity
91
- assert_match %r{is unavailable or does not exist}i, e.message, 'ignore if non-english test run'
88
+ assert_match %r{is unavailable or does not exist}i, e.message, "ignore if non-english test run"
92
89
  else
93
90
  assert_equal 20012, e.db_error_number
94
91
  assert_equal 2, e.severity
95
- assert_match %r{server name not found in configuration files}i, e.message, 'ignore if non-english test run'
92
+ assert_match %r{server name not found in configuration files}i, e.message, "ignore if non-english test run"
96
93
  end
97
94
  end
98
95
  assert_new_connections_work
99
96
  end
100
97
 
101
- it 'raises TinyTds exception with long query past :timeout option' do
102
- client = new_connection :timeout => 1
98
+ it "raises TinyTds exception with long query past :timeout option" do
99
+ client = new_connection timeout: 1
103
100
  action = lambda { client.execute("WaitFor Delay '00:00:02'").do }
104
101
  assert_raise_tinytds_error(action) do |e|
105
102
  assert_equal 20003, e.db_error_number
106
103
  assert_equal 6, e.severity
107
- assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
104
+ assert_match %r{timed out}i, e.message, "ignore if non-english test run"
108
105
  end
109
106
  assert_client_works(client)
110
107
  close_client(client)
111
108
  assert_new_connections_work
112
109
  end
113
110
 
114
- it 'must not timeout per sql batch when not under transaction' do
115
- client = new_connection :timeout => 2
111
+ it "must not timeout per sql batch when not under transaction" do
112
+ client = new_connection timeout: 2
116
113
  client.execute("WaitFor Delay '00:00:01'").do
117
114
  client.execute("WaitFor Delay '00:00:01'").do
118
115
  client.execute("WaitFor Delay '00:00:01'").do
119
116
  close_client(client)
120
117
  end
121
118
 
122
- it 'must not timeout per sql batch when under transaction' do
123
- client = new_connection :timeout => 2
119
+ it "must not timeout per sql batch when under transaction" do
120
+ client = new_connection timeout: 2
124
121
  begin
125
122
  client.execute("BEGIN TRANSACTION").do
126
123
  client.execute("WaitFor Delay '00:00:01'").do
@@ -132,99 +129,138 @@ 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
137
- begin
138
- client = new_connection :login_timeout => 2, :timeout => 2
139
- assert_client_works(client)
140
- STDOUT.puts "Disconnect network!"
141
- sleep 10
142
- STDOUT.puts "This should not get stuck past 6 seconds!"
143
- action = lambda { client.execute('SELECT 1 as [one]').each }
132
+ it "raises TinyTds exception with tcp socket network failure" do
133
+ client = new_connection timeout: 2, port: 1234, host: ENV["TOXIPROXY_HOST"]
134
+ assert_client_works(client)
135
+ action = lambda { client.execute("waitfor delay '00:00:05'").do }
136
+
137
+ # Use toxiproxy to close the TCP socket after 1 second.
138
+ # We want TinyTds to execute the statement, hit the timeout configured above, and then not be able to use the network to cancel
139
+ # the network connection needs to close after the sql batch is sent and before the timeout above is hit
140
+ Toxiproxy[:sqlserver_test].toxic(:slow_close, delay: 1000).apply do
144
141
  assert_raise_tinytds_error(action) do |e|
145
142
  assert_equal 20003, e.db_error_number
146
143
  assert_equal 6, e.severity
147
- assert_match %r{timed out}i, e.message, 'ignore if non-english test run'
144
+ assert_match %r{timed out}i, e.message, "ignore if non-english test run"
148
145
  end
149
- ensure
150
- STDOUT.puts "Reconnect network!"
151
- sleep 10
152
- action = lambda { client.execute('SELECT 1 as [one]').each }
153
- assert_raise_tinytds_error(action) do |e|
154
- assert_equal 20047, e.db_error_number
155
- assert_equal 1, e.severity
156
- assert_match %r{dead or not enabled}i, e.message, 'ignore if non-english test run'
146
+ end
147
+ ensure
148
+ assert_new_connections_work
149
+ end
150
+
151
+ it "raises TinyTds exception with dead connection network failure" do
152
+ skip if ruby_windows?
153
+
154
+ begin
155
+ client = new_connection timeout: 2, port: 1234, host: ENV["TOXIPROXY_HOST"]
156
+ assert_client_works(client)
157
+ action = lambda { client.execute("waitfor delay '00:00:05'").do }
158
+
159
+ # Use toxiproxy to close the network connection after 1 second.
160
+ # We want TinyTds to execute the statement, hit the timeout configured above, and then not be able to use the network to cancel
161
+ # the network connection needs to close after the sql batch is sent and before the timeout above is hit
162
+ Toxiproxy[:sqlserver_test].toxic(:timeout, timeout: 1000).apply do
163
+ assert_raise_tinytds_error(action) do |e|
164
+ assert_equal 20047, e.db_error_number
165
+ assert_includes [1, 9], e.severity
166
+ assert_match %r{dead or not enabled}i, e.message, "ignore if non-english test run"
167
+ end
157
168
  end
158
- close_client(client)
169
+ ensure
159
170
  assert_new_connections_work
160
171
  end
161
172
  end
162
173
 
163
- it 'raises TinyTds exception with wrong :username' do
164
- skip if ENV['CI'] && sqlserver_azure? # Some issue with db_error_number.
165
- options = connection_options :username => 'willnotwork'
174
+ it "raises TinyTds exception with login timeout" do
175
+ action = lambda do
176
+ Toxiproxy[:sqlserver_test].toxic(:timeout, timeout: 0).apply do
177
+ new_connection login_timeout: 1, port: 1234, host: ENV["TOXIPROXY_HOST"]
178
+ end
179
+ end
180
+ assert_raise_tinytds_error(action) do |e|
181
+ assert_equal 20003, e.db_error_number
182
+ assert_equal 6, e.severity
183
+ assert_match %r{timed out}i, e.message, "ignore if non-english test run"
184
+ end
185
+ ensure
186
+ assert_new_connections_work
187
+ end
188
+
189
+ it "raises TinyTds exception with wrong :username" do
190
+ skip if ENV["CI"] && sqlserver_azure? # Some issue with db_error_number.
191
+ options = connection_options username: "willnotwork"
166
192
  action = lambda { new_connection(options) }
167
193
  assert_raise_tinytds_error(action) do |e|
168
- assert_equal sybase_ase? ? 4002 : 18456, e.db_error_number
194
+ assert_equal 18456, e.db_error_number
169
195
  assert_equal 14, e.severity
170
- assert_match %r{login failed}i, e.message, 'ignore if non-english test run'
196
+ assert_match %r{login failed}i, e.message, "ignore if non-english test run"
171
197
  end
172
198
  assert_new_connections_work
173
199
  end
174
-
175
200
  end
176
201
 
177
- describe 'Private methods' do
178
-
202
+ describe "#parse_username" do
179
203
  let(:client) { @client = new_connection }
180
204
 
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
205
+ it "returns username if azure is not true" do
206
+ _(
207
+ client.send(:parse_username, username: "user@abc123.database.windows.net")
208
+ ).must_equal "user@abc123.database.windows.net"
184
209
  end
185
210
 
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
191
- ).must_equal 'user@abc123'
211
+ it "returns short username if azure is true" do
212
+ _(
213
+ client.send(
214
+ :parse_username,
215
+ username: "user@abc123.database.windows.net",
216
+ host: "abc123.database.windows.net",
217
+ azure: true
218
+ )
219
+ ).must_equal "user@abc123"
192
220
  end
193
221
 
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
199
- ).must_equal 'user@abc123.database.windows.net'
222
+ it "returns full username if azure is false" do
223
+ _(
224
+ client.send(
225
+ :parse_username,
226
+ username: "user@abc123.database.windows.net",
227
+ host: "abc123.database.windows.net",
228
+ azure: false
229
+ )
230
+ ).must_equal "user@abc123.database.windows.net"
200
231
  end
201
232
 
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
207
- ).must_equal 'user@abc123'
233
+ it "returns short username if passed and azure is true" do
234
+ _(
235
+ client.send(
236
+ :parse_username,
237
+ username: "user@abc123",
238
+ host: "abc123.database.windows.net",
239
+ azure: true
240
+ )
241
+ ).must_equal "user@abc123"
208
242
  end
209
243
 
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
215
- ).must_equal 'user@abc123'
244
+ it "returns username with servername if passed and azure is true" do
245
+ _(
246
+ client.send(
247
+ :parse_username,
248
+ username: "user",
249
+ host: "abc123.database.windows.net",
250
+ azure: true
251
+ )
252
+ ).must_equal "user@abc123"
216
253
  end
217
254
 
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
223
- ).must_equal 'user'
255
+ it "returns username with servername if passed and azure is false" do
256
+ _(
257
+ client.send(
258
+ :parse_username,
259
+ username: "user",
260
+ host: "abc123.database.windows.net",
261
+ azure: false
262
+ )
263
+ ).must_equal "user"
224
264
  end
225
-
226
265
  end
227
-
228
-
229
266
  end
230
-