Class: Cybertrain::Test::WebSocketReceiver

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

Overview

A receiver for outbound WebSocket connections in a test. Give each connection a script with #ws_script (in the order the connections will come; one without a script accepts and echoes until close), start it, point the client at #url, then read what the client sent with #ws_received.

Examples:

rx = Cybertrain::Test::WebSocketReceiver.new
rx.ws_script([Cybertrain::Test::WsStep.new("accept"),
              Cybertrain::Test::WsStep.new("send_text", "hello"),
              Cybertrain::Test::WsStep.new("expect")])
rx.start
Cybertrain.config.http_allow_private = true
ws = Cybertrain::WebSocket::Client.connect(rx.url("/feed"))
msg = ws.receive(5)             # "hello"
ws.send_text("thanks")
frames = rx.ws_received         # [RecordedFrame "thanks"]
ws.close
rx.stop

Instance Attribute Summary

Attributes inherited from Receiver

#port

Instance Method Summary collapse

Methods inherited from Receiver

#serving?, #start, #stop

Constructor Details

#initialize(max: 1, accept_window: 10.0, read_timeout: 5.0) ⇒ WebSocketReceiver

Returns a new instance of WebSocketReceiver.

Parameters:

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

    how many connections 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 read



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

def initialize(max: 1, accept_window: 10.0, read_timeout: 5.0)
  super(max, accept_window, read_timeout)
  # Scripts are kept flat: each step with the number of the connection
  # it belongs to.
  @script_steps = Array.new(0) { WsStep.new("", "") }
  @script_owner = Array.new(0) { 0 }
  @scripts_given = 0
  @frames = Array.new(0) { RecordedFrame.new(0, false, "") }
  @heads = Array.new(0) { WebSocketReceiver.no_headers }
  @targets = Array.new(0) { "" }
  @last_frame = RecordedFrame.new(0, false, "")
  @lock = Mutex.new
  @started_count = 0
  @finished_count = 0
end

Instance Method Details

#url(path = "/") ⇒ String

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

Parameters:

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

Returns:

  • (String)


127
128
129
# File 'cybertrain/test/websocket_receiver.rb', line 127

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

#ws_received(wait = 5.0) ⇒ Array<RecordedFrame>

Every frame recorded so far, once the connections that have begun have ended (at least one), waiting at most wait seconds for that.

Parameters:

  • wait (Numeric) (defaults to: 5.0)

Returns:



154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'cybertrain/test/websocket_receiver.rb', line 154

def ws_received(wait = 5.0)
  ends_at = Receiver.now + wait.to_f
  while Receiver.now < ends_at
    break if ws_idle?

    sleep(0.01)
  end
  out = Array.new(0) { RecordedFrame.new(0, false, "") }
  @lock.synchronize do
    i = 0
    while i < @frames.size
      out << @frames[i]
      i += 1
    end
  end
  out
end

#ws_request_headers(index) ⇒ Hash{String => String}

The handshake request headers of connection index (0 the first), names lowercased; empty when it sent none (or not yet, after 5 s).

Parameters:

  • index (Integer)

Returns:

  • (Hash{String => String})


177
178
179
180
181
182
183
184
185
# File 'cybertrain/test/websocket_receiver.rb', line 177

def ws_request_headers(index)
  return WebSocketReceiver.no_headers unless ws_await_head(index)

  seen = WebSocketReceiver.no_headers
  @lock.synchronize { seen = @heads[index] }
  # A head is never changed once recorded, so the copy is made
  # outside the lock (and outside its block).
  WebSocketReceiver.ws_copy_headers(seen)
end

#ws_request_target(index) ⇒ String

The request target (path and query) of connection index’s handshake; “” when it sent none.

Parameters:

  • index (Integer)

Returns:

  • (String)


198
199
200
201
202
203
204
# File 'cybertrain/test/websocket_receiver.rb', line 198

def ws_request_target(index)
  return "" unless ws_await_head(index)

  out = ""
  @lock.synchronize { out = @targets[index].to_s }
  out
end

#ws_script(steps) ⇒ nil

The script of the next connection that has none yet.

Parameters:

Returns:

  • (nil)


135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'cybertrain/test/websocket_receiver.rb', line 135

def ws_script(steps)
  @lock.synchronize do
    owner = @scripts_given
    i = 0
    while i < steps.size
      @script_steps << steps[i]
      @script_owner << owner
      i += 1
    end
    @scripts_given = owner + 1
  end
  nil
end