Class: Maze::Server

Inherits:
Object
  • Object
show all
Defined in:
lib/maze/server.rb

Overview

Receives and stores requests through a WEBrick HTTPServer

Constant Summary collapse

ALLOWED_HTTP_VERBS =
%w[OPTIONS GET POST PUT DELETE HEAD TRACE PATCH CONNECT]
DEFAULT_RESPONSE_DELAY =
0
DEFAULT_SAMPLING_PROBABILITY =
1
DEFAULT_STATUS_CODE =
200

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.last_command_uuidString

Records the previous command UUID sent to the test fixture

Returns:

  • (String)

    The UUID of the last command sent



22
23
24
# File 'lib/maze/server.rb', line 22

def last_command_uuid
  @last_command_uuid
end

Class Method Details

.buildsRequestList

A list of build requests received

Returns:



142
143
144
# File 'lib/maze/server.rb', line 142

def builds
  @builds ||= RequestList.new
end

.commandsRequestList

A list of commands for a test fixture to perform. Strictly speaking these are responses to HTTP requests, but the list behavior is all we need.

Returns:



185
186
187
# File 'lib/maze/server.rb', line 185

def commands
  @commands ||= RequestList.new
end

.errorsRequestList

A list of error requests received

Returns:



114
115
116
# File 'lib/maze/server.rb', line 114

def errors
  @errors ||= RequestList.new
end

.invalid_requestsRequestList

Whether the server thread is running An array of any invalid requests received. Each request is hash consisting of:

request: The original HTTPRequest object
reason: Reason for being considered invalid. Examples include invalid JSON and missing/invalid digest.

Returns:



195
196
197
# File 'lib/maze/server.rb', line 195

def invalid_requests
  @invalid_requests ||= RequestList.new
end

.list_for(type) ⇒ Object

Provides dynamic access to request lists by name

Parameters:

  • type (String, Symbol)

    Request type

Returns:

  • Request list for the type given



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
# File 'lib/maze/server.rb', line 81

def list_for(type)
  type = type.to_s
  case type
  when 'error', 'errors'
    errors
  when 'session', 'sessions'
    sessions
  when 'build', 'builds'
    builds
  when 'log', 'logs'
    logs
  when 'metric', 'metrics'
    metrics
  when 'sampling request', 'sampling requests'
    sampling_requests
  when 'trace', 'traces'
    traces
  when 'upload', 'uploads'
    uploads
  when 'sourcemap', 'sourcemaps'
    sourcemaps
  when 'reflect', 'reflects', 'reflection', 'reflections'
    reflections
  when 'invalid', 'invalid requests'
    invalid_requests
  else
    raise "Invalid request type '#{type}'"
  end
end

.logsRequestList

A list of log requests received

Returns:



163
164
165
# File 'lib/maze/server.rb', line 163

def logs
  @logs ||= RequestList.new
end

.metricsRequestList

A list of metric requests received

Returns:



170
171
172
# File 'lib/maze/server.rb', line 170

def metrics
  @metrics ||= RequestList.new
end

.reflectionsRequestList

A list of reflection requests received

Returns:



177
178
179
# File 'lib/maze/server.rb', line 177

def reflections
  @reflections ||= RequestList.new
end

.reset!Object



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
# File 'lib/maze/server.rb', line 274

def reset!
  # Reset generators
  set_response_delay_generator(Maze::Generator.new [DEFAULT_RESPONSE_DELAY].cycle)
  set_status_code_generator(Maze::Generator.new [DEFAULT_STATUS_CODE].cycle)
  set_sampling_probability_generator(Maze::Generator.new [DEFAULT_SAMPLING_PROBABILITY].cycle)

  # Clear request lists
  commands.clear
  errors.clear
  sessions.clear
  builds.clear
  uploads.clear
  sourcemaps.clear
  sampling_requests.clear
  traces.clear
  logs.clear
  invalid_requests.clear
  reflections.clear
end

.response_delay_msObject



73
74
75
# File 'lib/maze/server.rb', line 73

def response_delay_ms
  @response_delay_generator.next
end

.running?Boolean

Whether the server thread is running

Returns:

  • (Boolean)

    If the server is running



202
203
204
# File 'lib/maze/server.rb', line 202

def running?
  @thread&.alive?
end

.sampling_probabilityObject



69
70
71
# File 'lib/maze/server.rb', line 69

def sampling_probability
  @sampling_probability_generator.next
end

.sampling_requestsRequestList

A list of sampling requests received

Returns:



128
129
130
# File 'lib/maze/server.rb', line 128

def sampling_requests
  @sampling_requests ||= RequestList.new
end

.sessionsRequestList

A list of session requests received

Returns:



121
122
123
# File 'lib/maze/server.rb', line 121

def sessions
  @sessions ||= RequestList.new
end

.set_response_delay_generator(generator) ⇒ Object

Sets the response delay generator.

Parameters:



27
28
29
30
# File 'lib/maze/server.rb', line 27

def set_response_delay_generator(generator)
  @response_delay_generator&.close
  @response_delay_generator = generator
end

.set_sampling_probability_generator(generator) ⇒ Object

Sets the sampling probability generator.

Parameters:



35
36
37
38
# File 'lib/maze/server.rb', line 35

def set_sampling_probability_generator(generator)
  @sampling_probability_generator&.close
  @sampling_probability_generator = generator
end

.set_status_code_generator(generator, verb = nil) ⇒ Object

Sets the status code generator for the HTTP verb given. If no verb is given then the generator will be shared across all allowable HTTP verbs.

Parameters:

  • generator (Maze::Generator)

    The new generator

  • verb (String) (defaults to: nil)

    HTTP verb



45
46
47
48
49
50
51
52
53
54
# File 'lib/maze/server.rb', line 45

def set_status_code_generator(generator, verb = nil)
  @status_code_generators ||= {}
  Array(verb || ALLOWED_HTTP_VERBS).each do |verb|
    old = @status_code_generators[verb]
    @status_code_generators[verb] = generator

    # Close the old generator unless it's still being used by another verb
    old&.close unless @status_code_generators.value?(old)
  end
end

.sourcemapsRequestList

A list of sourcemap requests received

Returns:



156
157
158
# File 'lib/maze/server.rb', line 156

def sourcemaps
  @sourcemaps ||= RequestList.new
end

.startObject

Starts the WEBrick server in a separate thread



207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
# File 'lib/maze/server.rb', line 207

def start
  attempts = 0
  loop do

    @thread = Thread.new do
      options = {
          Port: Maze.config.port,
          Logger: $logger,
          AccessLog: []
      }
      options[:BindAddress] = Maze.config.bind_address unless Maze.config.bind_address.nil?
      server = WEBrick::HTTPServer.new(options)

      # Mount a block to respond to all requests with status:200
      server.mount_proc '/' do |_request, response|
        $logger.trace 'Received request on server root, responding with 200'
        response.header['Access-Control-Allow-Origin'] = '*'
        response.body = 'Maze runner received request'
        response.status = 200
      end

      # When adding more endpoints, be sure to update the 'I should receive no requests' step
      server.mount '/notify', Servlets::Servlet, :errors
      server.mount '/sessions', Servlets::Servlet, :sessions
      server.mount '/builds', Servlets::Servlet, :builds
      server.mount '/uploads', Servlets::Servlet, :uploads
      server.mount '/traces', Servlets::TraceServlet, :traces, Maze::Schemas::TRACE_SCHEMA
      server.mount '/sourcemap', Servlets::Servlet, :sourcemaps
      server.mount '/react-native-source-map', Servlets::Servlet, :sourcemaps
      server.mount '/dart-symbol', Servlets::Servlet, :sourcemaps
      server.mount '/ndk-symbol', Servlets::Servlet, :sourcemaps
      server.mount '/proguard', Servlets::Servlet, :sourcemaps
      server.mount '/dsym', Servlets::Servlet, :sourcemaps
      server.mount '/command', Servlets::CommandServlet
      server.mount '/commands', Servlets::AllCommandsServlet
      server.mount '/logs', Servlets::LogServlet
      server.mount '/metrics', Servlets::Servlet, :metrics
      server.mount '/reflect', Servlets::ReflectiveServlet
      server.mount '/docs', WEBrick::HTTPServlet::FileHandler, Maze.config.document_server_root unless Maze.config.document_server_root.nil?
      server.start
    rescue StandardError => e
      Bugsnag.notify e
      $logger.warn "Failed to start mock server: #{e.message}"
    ensure
      server&.shutdown
    end

    # Need a short sleep here as a dying thread is still alive momentarily
    sleep 1
    break if running?

    # Bail out after 3 attempts
    attempts += 1
    raise 'Too many failed attempts to start mock server' if attempts == 3

    # Failed to start - sleep before retrying
    $logger.info 'Retrying in 5 seconds'
    sleep 5
  end
end

.status_code(verb) ⇒ Integer

The intended HTTP status code on a successful request

Parameters:

  • verb (String)

    HTTP verb for which the status code is wanted

Returns:

  • (Integer)

    The HTTP status code for the verb given



61
62
63
64
65
66
67
# File 'lib/maze/server.rb', line 61

def status_code(verb)
  if @status_code_generators[verb].nil? || @status_code_generators[verb].closed?
    DEFAULT_STATUS_CODE
  else
    @status_code_generators[verb].next
  end
end

.stopObject

Stops the WEBrick server thread if it’s running



269
270
271
272
# File 'lib/maze/server.rb', line 269

def stop
  @thread&.kill if @thread&.alive?
  @thread = nil
end

.tracesRequestList

A list of trace requests received

Returns:



135
136
137
# File 'lib/maze/server.rb', line 135

def traces
  @traces ||= RequestList.new
end

.uploadsRequestList

A list of upload requests received

Returns:



149
150
151
# File 'lib/maze/server.rb', line 149

def uploads
  @uploads ||= RequestList.new
end