File: test_connection_pool.rb

package info (click to toggle)
ruby-sshkit 1.21.2-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 700 kB
  • sloc: ruby: 3,522; makefile: 2
file content (148 lines) | stat: -rw-r--r-- 3,860 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
require 'helper'
require 'ostruct'

module SSHKit
  module Backend
    class TestConnectionPool < UnitTest

      def setup
        super
        pool.flush_connections
      end

      def pool
        @pool ||= SSHKit::Backend::ConnectionPool.new
      end

      def connect
        ->(*_args) { Object.new }
      end

      def connect_and_close
        ->(*_args) { OpenStruct.new(:closed? => true) }
      end

      def echo_args
        ->(*args) { args }
      end

      def test_default_idle_timeout
        assert_equal 30, pool.idle_timeout
      end

      def test_connection_factory_receives_args
        args = %w(a b c)
        conn = pool.with(echo_args, *args) { |c| c }

        assert_equal args, conn
      end

      def test_connections_are_not_reused_if_not_checked_in
        conn1 = nil
        conn2 = nil

        pool.with(connect, "conn") do |yielded_conn_1|
          conn1 = yielded_conn_1
          conn2 = pool.with(connect, "conn") { |c| c }
        end

        refute_equal conn1, conn2
      end

      def test_connections_are_reused_if_checked_in
        conn1 = pool.with(connect, "conn") { |c| c }
        conn2 = pool.with(connect, "conn") { |c| c }

        assert_equal conn1, conn2
      end

      def test_connections_are_reused_across_threads_multiple_times
        t1 = Thread.new do
          pool.with(connect, "conn") { |c| c }
        end

        t2 = Thread.new do
          pool.with(connect, "conn") { |c| c }
        end

        t3 = Thread.new do
          pool.with(connect, "conn") { |c| c }
        end

        refute_nil t1.value
        assert_equal t1.value, t2.value
        assert_equal t2.value, t3.value
      end

      def test_zero_idle_timeout_disables_pooling
        pool.idle_timeout = 0

        conn1 = pool.with(connect, "conn") { |c| c }
        conn2 = pool.with(connect, "conn") { |c| c }
        refute_equal conn1, conn2
      end

      def test_expired_connection_is_not_reused
        pool.idle_timeout = 0.1

        conn1 = pool.with(connect, "conn") { |c| c }
        sleep(pool.idle_timeout)
        conn2 = pool.with(connect, "conn") { |c| c }

        refute_equal conn1, conn2
      end

      def test_expired_connection_is_closed
        pool.idle_timeout = 0.1
        conn1 = mock
        conn1.expects(:closed?).twice.returns(false)
        conn1.expects(:close)

        pool.with(->(*) { conn1 }, "conn1") {}
        # Pause to allow the background thread to wake and close the conn
        sleep(5 + pool.idle_timeout)
      end

      def test_closed_connection_is_not_reused
        conn1 = pool.with(connect_and_close, "conn") { |c| c }
        conn2 = pool.with(connect, "conn") { |c| c }

        refute_equal conn1, conn2
      end

      def test_connections_with_different_args_are_not_reused
        conn1 = pool.with(connect, "conn1") { |c| c }
        conn2 = pool.with(connect, "conn2") { |c| c }

        refute_equal conn1, conn2
      end

      def test_close_connections
        conn1 = mock
        conn1.expects(:closed?).twice.returns(false)
        conn1.expects(:close)

        conn2 = mock
        conn2.expects(:closed?).returns(false)
        conn2.expects(:close).never

        pool.with(->(*) { conn1 }, "conn1") {}

        # We are using conn2 when close_connections is called, so it should
        # not be closed.
        pool.with(->(*) { conn2 }, "conn2") do
          pool.close_connections
        end
      end

      def test_connections_with_changed_args_is_reused
        options = { known_hosts: "foo" }
        connect_change_options = ->(*args) { args.last[:known_hosts] = "bar"; Object.new }
        conn1 = pool.with(connect_change_options, "arg", options) { |c| c }
        conn2 = pool.with(connect_change_options, "arg", options) { |c| c }

        assert_equal conn1, conn2
      end
    end
  end
end