|
| 1 | +require "net/http" |
| 2 | +require "socket" |
| 3 | +require "stringio" |
| 4 | +require "uri" |
| 5 | +require "rbs_test_helper" |
| 6 | + |
| 7 | +module NetHTTPTypeTestSupport |
| 8 | + class Server |
| 9 | + attr_reader :uri |
| 10 | + |
| 11 | + def initialize(host = "127.0.0.1") |
| 12 | + @server = TCPServer.open(host, 0) |
| 13 | + @uri = URI("http://#{host}:#{@server.local_address.ip_port}/") |
| 14 | + @thread = Thread.new do |
| 15 | + loop do |
| 16 | + handle_session(@server.accept) |
| 17 | + end |
| 18 | + rescue IOError, Errno::EBADF |
| 19 | + end |
| 20 | + end |
| 21 | + |
| 22 | + def finish |
| 23 | + @thread.kill |
| 24 | + @thread.join |
| 25 | + @server.close |
| 26 | + rescue IOError, Errno::EBADF |
| 27 | + end |
| 28 | + |
| 29 | + private |
| 30 | + |
| 31 | + def handle_session(socket) |
| 32 | + content_length = nil |
| 33 | + |
| 34 | + while (line = socket.gets) |
| 35 | + content_length = line.split(":", 2)[1].strip.to_i if line.start_with?("Content-Length:") |
| 36 | + break if line == "\r\n" |
| 37 | + end |
| 38 | + |
| 39 | + socket.read(content_length) if content_length |
| 40 | + |
| 41 | + body = "ok" |
| 42 | + socket.write( |
| 43 | + "HTTP/1.1 200 OK\r\n" \ |
| 44 | + "Content-Type: text/plain\r\n" \ |
| 45 | + "Set-Cookie: session=1\r\n" \ |
| 46 | + "Content-Length: #{body.bytesize}\r\n" \ |
| 47 | + "\r\n" \ |
| 48 | + "#{body}" |
| 49 | + ) |
| 50 | + ensure |
| 51 | + socket.close |
| 52 | + end |
| 53 | + end |
| 54 | + |
| 55 | + def with_server(host = "127.0.0.1") |
| 56 | + server = Server.new(host) |
| 57 | + yield server.uri |
| 58 | + ensure |
| 59 | + server&.finish |
| 60 | + end |
| 61 | +end |
| 62 | + |
| 63 | +class NetHTTPSingletonRBSTest < NetHTTPRBSTestCase |
| 64 | + include NetHTTPTypeTestSupport |
| 65 | + |
| 66 | + testing "singleton(::Net::HTTP)" |
| 67 | + |
| 68 | + def test_singleton_api |
| 69 | + previous_stdout = $stdout |
| 70 | + $stdout = StringIO.new |
| 71 | + |
| 72 | + with_server do |uri| |
| 73 | + assert_send_type "(URI::Generic) -> nil", |
| 74 | + Net::HTTP, :get_print, uri |
| 75 | + assert_send_type "(String, String, Integer) -> nil", |
| 76 | + Net::HTTP, :get_print, uri.host, "/", uri.port |
| 77 | + assert_send_type "(URI::Generic, Hash[String, String]) -> String", |
| 78 | + Net::HTTP, :get, uri, { "Accept" => "text/plain" } |
| 79 | + assert_send_type "(URI::Generic, Hash[Symbol, String]) -> Net::HTTPResponse", |
| 80 | + Net::HTTP, :get_response, uri, { Accept: "text/plain" } |
| 81 | + assert_send_type "(URI, String, Hash[String, String]) -> Net::HTTPResponse", |
| 82 | + Net::HTTP, :post, uri, "payload", "Content-Type" => "text/plain" |
| 83 | + assert_send_type "(URI, Hash[String, Symbol]) -> Net::HTTPResponse", |
| 84 | + Net::HTTP, :post_form, uri, { "q" => :ruby } |
| 85 | + |
| 86 | + http = assert_send_type "(String, Integer) -> Net::HTTP", |
| 87 | + Net::HTTP, :start, uri.host, uri.port |
| 88 | + http.finish if http.started? |
| 89 | + |
| 90 | + assert_send_type "(String, Integer) { (Net::HTTP) -> Class } -> Class", |
| 91 | + Net::HTTP, :start, uri.host, uri.port do |net_http| |
| 92 | + net_http.class |
| 93 | + end |
| 94 | + end |
| 95 | + |
| 96 | + assert_send_type "(String, Integer, nil, nil, nil, nil, nil) -> Net::HTTP", |
| 97 | + Net::HTTP, :new, "127.0.0.1", 80, nil, nil, nil, nil, nil |
| 98 | + ensure |
| 99 | + $stdout = previous_stdout |
| 100 | + end |
| 101 | +end |
| 102 | + |
| 103 | +class NetHTTPInstanceRBSTest < NetHTTPRBSTestCase |
| 104 | + include NetHTTPTypeTestSupport |
| 105 | + |
| 106 | + testing "::Net::HTTP" |
| 107 | + |
| 108 | + def test_attribute_api |
| 109 | + http = Net::HTTP.new("127.0.0.1", 80) |
| 110 | + |
| 111 | + assert_send_type "() -> String", http, :inspect |
| 112 | + assert_send_type "() -> String", http, :address |
| 113 | + assert_send_type "() -> Integer", http, :port |
| 114 | + assert_send_type "() -> nil", http, :ipaddr |
| 115 | + assert_send_type "(String) -> void", http, :ipaddr=, "127.0.0.1" |
| 116 | + assert_send_type "() -> Integer", http, :open_timeout |
| 117 | + assert_send_type "() -> Integer", http, :read_timeout |
| 118 | + assert_send_type "(Integer) -> void", http, :read_timeout=, 10 |
| 119 | + assert_send_type "() -> Integer", http, :write_timeout |
| 120 | + assert_send_type "(Integer) -> void", http, :write_timeout=, 10 |
| 121 | + assert_send_type "() -> nil", http, :continue_timeout |
| 122 | + assert_send_type "(Integer) -> void", http, :continue_timeout=, 10 |
| 123 | + assert_send_type "() -> Integer", http, :max_retries |
| 124 | + assert_send_type "(Integer) -> void", http, :max_retries=, 10 |
| 125 | + assert_send_type "() -> Integer", http, :keep_alive_timeout |
| 126 | + assert_send_type "() -> bool", http, :started? |
| 127 | + assert_send_type "() -> bool", http, :active? |
| 128 | + assert_send_type "() -> bool", http, :use_ssl? |
| 129 | + assert_send_type "(bool) -> void", http, :use_ssl=, true |
| 130 | + assert_send_type "() -> bool", http, :proxy? |
| 131 | + assert_send_type "() -> bool", http, :proxy_from_env? |
| 132 | + assert_send_type "() -> nil", http, :proxy_uri |
| 133 | + assert_send_type "() -> nil", http, :proxy_address |
| 134 | + assert_send_type "() -> nil", http, :proxy_port |
| 135 | + assert_send_type "() -> nil", http, :proxy_user |
| 136 | + assert_send_type "() -> nil", http, :proxy_pass |
| 137 | + assert_send_type "(IO) -> void", http, :set_debug_output, $stderr |
| 138 | + end |
| 139 | + |
| 140 | + def test_request_api |
| 141 | + with_server do |uri| |
| 142 | + http = Net::HTTP.start(uri.host, uri.port) |
| 143 | + |
| 144 | + assert_send_type "(String) -> Net::HTTPResponse", http, :get, "/" |
| 145 | + assert_send_type "(String, Hash[String, String]) -> Net::HTTPResponse", |
| 146 | + http, :get, "/", { "Accept" => "text/plain" } |
| 147 | + assert_send_type "(String) { (String) -> String } -> Net::HTTPResponse", |
| 148 | + http, :get, "/" do |body| |
| 149 | + body |
| 150 | + end |
| 151 | + assert_send_type "(String) -> Net::HTTPResponse", http, :head, "/" |
| 152 | + assert_send_type "(String, String) -> Net::HTTPResponse", http, :post, "/", "payload" |
| 153 | + assert_send_type "(String, String, Hash[String, String]) -> Net::HTTPResponse", |
| 154 | + http, :request_post, "/", "payload", { "Content-Type" => "text/plain" } |
| 155 | + assert_send_type "(String) { (Net::HTTPResponse) -> String? } -> Net::HTTPResponse", |
| 156 | + http, :request_get, "/" do |response| |
| 157 | + response.body |
| 158 | + end |
| 159 | + assert_send_type "(String, String) -> Net::HTTPResponse", |
| 160 | + http, :send_request, "GET", "/" |
| 161 | + assert_send_type "(Net::HTTPRequest) -> Net::HTTPResponse", |
| 162 | + http, :request, Net::HTTP::Get.new(uri) |
| 163 | + ensure |
| 164 | + http.finish if http&.started? |
| 165 | + end |
| 166 | + end |
| 167 | +end |
| 168 | + |
| 169 | +class NetHTTPRequestRBSTest < NetHTTPRBSTestCase |
| 170 | + include NetHTTPTypeTestSupport |
| 171 | + |
| 172 | + testing "::Net::HTTPRequest" |
| 173 | + |
| 174 | + def test_request_attributes_and_headers |
| 175 | + uri = URI("http://127.0.0.1/") |
| 176 | + request = Net::HTTP::Get.new(uri) |
| 177 | + |
| 178 | + assert_send_type "() -> String", request, :inspect |
| 179 | + assert_send_type "() -> String", request, :method |
| 180 | + assert_send_type "() -> String", request, :path |
| 181 | + assert_send_type "() -> URI::Generic", request, :uri |
| 182 | + assert_send_type "() -> bool", request, :decode_content |
| 183 | + assert_send_type "() -> bool", request, :request_body_permitted? |
| 184 | + assert_send_type "() -> bool", request, :response_body_permitted? |
| 185 | + assert_send_type "() -> nil", request, :body |
| 186 | + assert_send_type "(String) -> void", request, :body=, "payload" |
| 187 | + assert_send_type "() -> nil", request, :body_stream |
| 188 | + assert_send_type "(untyped) -> untyped", request, :body_stream=, StringIO.new |
| 189 | + assert_send_type "(String) -> nil", request, :[], "Content-Type" |
| 190 | + assert_send_type "(String, untyped) -> void", request, :[]=, "Content-Type", "text/plain" |
| 191 | + assert_send_type "(String, untyped) -> void", request, :add_field, "X-Test", "1" |
| 192 | + assert_send_type "(String) -> bool", request, :key?, "X-Test" |
| 193 | + assert_send_type "() -> nil", request, :range |
| 194 | + assert_send_type "(Range[Integer]) -> Range[Integer]", request, :set_range, 0..10 |
| 195 | + assert_send_type "(Integer) -> void", request, :content_length=, 10 |
| 196 | + assert_send_type "(String) -> void", request, :set_content_type, "text/plain" |
| 197 | + assert_send_type "(Hash[untyped, untyped]) -> void", request, :set_form_data, { "q" => "ruby" } |
| 198 | + assert_send_type "(Hash[untyped, untyped]) -> void", request, :set_form, { "q" => "ruby" } |
| 199 | + assert_send_type "(String account, String password) -> void", |
| 200 | + request, :basic_auth, "username", "password" |
| 201 | + assert_send_type "(String account, String password) -> void", |
| 202 | + request, :proxy_basic_auth, "username", "password" |
| 203 | + assert_send_type "() -> bool", request, :connection_close? |
| 204 | + assert_send_type "() -> bool", request, :connection_keep_alive? |
| 205 | + assert_send_type "() { (String, String) -> String } -> Hash[String, Array[String]]", |
| 206 | + request, :each_header do |key, value| |
| 207 | + "#{key}:#{value}" |
| 208 | + end |
| 209 | + assert_send_type "() -> Enumerator[[String, String], Hash[String, Array[String]]]", |
| 210 | + request, :each_header |
| 211 | + assert_send_type "() -> Hash[String, Array[String]]", request, :to_hash |
| 212 | + end |
| 213 | + |
| 214 | + def test_response_header_helpers |
| 215 | + with_server do |uri| |
| 216 | + response = Net::HTTP.start(uri.host, uri.port) { |http| http.request_get("/") } |
| 217 | + |
| 218 | + assert_send_type "(String) -> Array[String]", |
| 219 | + response, :get_fields, "Set-Cookie" |
| 220 | + assert_send_type "(String) { (String) -> String } -> String", |
| 221 | + response, :fetch, "Set-Cookie" do |value| |
| 222 | + value |
| 223 | + end |
| 224 | + assert_send_type "(String) -> Array[String]", |
| 225 | + response, :delete, "Set-Cookie" |
| 226 | + end |
| 227 | + end |
| 228 | +end |
| 229 | + |
| 230 | +class NetHTTPResponseRBSTest < NetHTTPRBSTestCase |
| 231 | + include NetHTTPTypeTestSupport |
| 232 | + |
| 233 | + testing "::Net::HTTPResponse" |
| 234 | + |
| 235 | + class SingletonTest < NetHTTPRBSTestCase |
| 236 | + testing "singleton(::Net::HTTPResponse)" |
| 237 | + |
| 238 | + def test_singleton_api |
| 239 | + assert_send_type "() -> bool", Net::HTTPSuccess, :body_permitted? |
| 240 | + end |
| 241 | + end |
| 242 | + |
| 243 | + def response |
| 244 | + with_server do |uri| |
| 245 | + Net::HTTP.get_response(uri) |
| 246 | + end |
| 247 | + end |
| 248 | + |
| 249 | + def test_response_api |
| 250 | + assert_send_type "() -> String", response, :http_version |
| 251 | + assert_send_type "() -> String", response, :code |
| 252 | + assert_send_type "() -> String", response, :message |
| 253 | + assert_send_type "() -> String", response, :msg |
| 254 | + assert_send_type "() -> URI::Generic", response, :uri |
| 255 | + assert_send_type "() -> bool", response, :decode_content |
| 256 | + assert_send_type "() -> String", response, :inspect |
| 257 | + assert_send_type "() -> untyped", response, :code_type |
| 258 | + assert_send_type "() -> nil", response, :value |
| 259 | + assert_send_type "(URI::Generic) -> void", response, :uri=, URI("http://127.0.0.1/next") |
| 260 | + assert_send_type "() -> String", response, :body |
| 261 | + assert_send_type "(String) -> void", response, :body=, "payload" |
| 262 | + assert_send_type "() -> String", response, :entity |
| 263 | + end |
| 264 | +end |
0 commit comments