Class: Cybertrain::Test::HttpReceiver

Inherits:
Receiver
  • Object
show all
Defined in:
cybertrain/test/http_receiver.rb

Overview

A receiver for outbound HTTP calls in a test: start binds a port on 127.0.0.1, the application calls it, #received_request returns what arrived. It accepts max connections (1 by default), reads one request from each (Content-Length or chunked body) and answers it with the canned response and Connection: close.

Cybertrain::HttpClient refuses loopback addresses unless the test sets allow_private: true (or Cybertrain.config.http_allow_private = true).

Examples:

require "cybertrain/test/http_receiver"

test "the signup posts a webhook" do
  hook = Cybertrain::Test::HttpReceiver.new(status: 202, body: "queued")
  hook.start
  Cybertrain.config.http_allow_private = true
  Notifier.(hook.url("/hooks/signup"), "ann@example.com")  # the code under test
  req = hook.received_request          # waits at most 5 s; nil if nothing came
  hook.stop
  assert_equal "POST", req.http_method
  assert_equal "/hooks/signup", req.http_target
  assert_equal "application/json", req.http_header("Content-Type")
end

Instance Attribute Summary

Attributes inherited from Receiver

#port

Instance Method Summary collapse

Methods inherited from Receiver

#serving?, #start, #stop

Constructor Details

#initialize(status: 200, headers: HttpReceiver.no_headers, body: "ok", chunked: false, max: 1, accept_window: 10.0, read_timeout: 5.0) ⇒ HttpReceiver

Returns a new instance of HttpReceiver.

Parameters:

  • status (Integer) (defaults to: 200) —

    the canned response’s status

  • headers (Hash{String => String}) (defaults to: HttpReceiver.no_headers) —

    extra response headers

  • body (String) (defaults to: "ok") —

    the canned response’s body

  • chunked (Boolean) (defaults to: false) —

    send the body with Transfer-Encoding: chunked

  • max (Integer) (defaults to: 1) —

    how many connections (one request each) to accept

  • accept_window (Numeric) (defaults to: 10.0) —

    seconds to wait for each connection before the receiver gives up and closes its port

  • read_timeout (Numeric) (defaults to: 5.0) —

    seconds of silence that end a connection



108
109
110
111
112
113
114
115
116
117
118
119
# File 'cybertrain/test/http_receiver.rb', line 108

def initialize(status: 200, headers: HttpReceiver.no_headers, body: "ok", chunked: false, max: 1,
               accept_window: 10.0, read_timeout: 5.0)
  super(max, accept_window, read_timeout)
  @reply_status = 200
  @reply_headers = HttpReceiver.no_headers
  @reply_body = ""
  @reply_chunked = false
  @requests = Array.new(0) { ReceivedRequest.new("", "", HttpReceiver.no_headers, "") }
  @lock = Mutex.new
  @body_failed = false
  respond_with(status: status, headers: headers, body: body, chunked: chunked)
end

Instance Method Details

#received_request(wait = 5.0) ⇒ ReceivedRequest?

The first request, waiting for it at most wait seconds.

Parameters:

  • wait (Numeric) (defaults to: 5.0)

Returns:



150
151
152
153
154
# File 'cybertrain/test/http_receiver.rb', line 150

def received_request(wait = 5.0)
  return nil unless await_count(1, wait)

  @requests[0]
end

#received_requests(count = 0, wait = 5.0) ⇒ Array<ReceivedRequest>

The requests that arrived, waiting at most wait seconds for count of them (0: the receiver’s max). Fewer when the time ran out.

Parameters:

  • count (Integer) (defaults to: 0)
  • wait (Numeric) (defaults to: 5.0)

Returns:



163
164
165
166
167
168
169
170
171
172
173
# File 'cybertrain/test/http_receiver.rb', line 163

def received_requests(count = 0, wait = 5.0)
  await_count(count > 0 ? count : @max, wait)
  out = Array.new(0) { ReceivedRequest.new("", "", HttpReceiver.no_headers, "") }
  n = received_count
  i = 0
  while i < n
    out << @requests[i]
    i += 1
  end
  out
end

#respond_with(status: 200, headers: HttpReceiver.no_headers, body: "ok", chunked: false) ⇒ nil

Changes the canned response for the requests still to come.

Parameters:

  • status (Integer) (defaults to: 200)
  • headers (Hash{String => String}) (defaults to: HttpReceiver.no_headers)
  • body (String) (defaults to: "ok")
  • chunked (Boolean) (defaults to: false)

Returns:

  • (nil)


128
129
130
131
132
133
134
135
136
# File 'cybertrain/test/http_receiver.rb', line 128

def respond_with(status: 200, headers: HttpReceiver.no_headers, body: "ok", chunked: false)
  @reply_status = status.to_i
  copy = HttpReceiver.no_headers
  headers.each_key { |k| copy[k.to_s] = headers[k].to_s }
  @reply_headers = copy
  @reply_body = body.to_s
  @reply_chunked = chunked ? true : false
  nil
end

#url(path = "/") ⇒ String

“http://127.0.0.1:", once started.

Parameters:

  • path (String) (defaults to: "/")

Returns:

  • (String)


142
143
144
# File 'cybertrain/test/http_receiver.rb', line 142

def url(path = "/")
  "http://127.0.0.1:#{@port}#{path}"
end