Class: Overseer::TestingControl::Rails::Configuration

Inherits:
Object
  • Object
show all
Defined in:
lib/overseer/testing_control/rails/configuration.rb

Defined Under Namespace

Classes: HandlerContext, Probe, Sink, State

Constant Summary collapse

FEATURES =
%w[
  correlation-propagation
  deterministic-replay
  reset
  schema-validation
  sink-clearing
].freeze
RESET_STRATEGIES =
%w[in-process runtime-restart].freeze
IDEMPOTENCY =
%w[required supported none].freeze
EFFECT_KINDS =
%w[email sms webhook document-delivery integration-command custom].freeze
DEFAULT_SOURCE_PROVIDER =
-> { ENV.fetch('OVERSEER_TESTING_CONTROL_APPLICATION_VERSION', '') }
DEFAULT_ENVIRONMENT_PROVIDER =
-> { ENV.fetch('OVERSEER_TESTING_CONTROL_ENVIRONMENT_ID', '') }
DEFAULT_LIMITS =
{
  'maxRequestBytes' => 65_536,
  'maxResponseBytes' => 262_144,
  'maxSchemaBytes' => 65_536,
  'maxSinkRecordsPerQuery' => 25,
  'maxSinkRecordBytes' => 16_384
}.freeze
LIMIT_RANGES =
{
  'maxRequestBytes' => (1_024..16_777_216),
  'maxResponseBytes' => (1_024..16_777_216),
  'maxSchemaBytes' => (1_024..1_048_576),
  'maxSinkRecordsPerQuery' => (1..1_000),
  'maxSinkRecordBytes' => (256..1_048_576)
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize ⇒ Configuration

Returns a new instance of Configuration.



48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/overseer/testing_control/rails/configuration.rb', line 48

def initialize
  @request_lock = Monitor.new
  @identity = {
    application: nil,
    source: DEFAULT_SOURCE_PROVIDER,
    environment: DEFAULT_ENVIRONMENT_PROVIDER,
    kind: 'test',
    isolated: true
  }
  @reset_strategy = 'runtime-restart'
  @reset_handler = nil
  @states = []
  @probes = []
  @sinks = []
  @limits = DEFAULT_LIMITS
  @idempotency_limit = 128
  @max_sink_records = 250
  rebuild_stores!
  @finalized = false
end

Instance Attribute Details

#idempotency_store ⇒ Object (readonly)

Returns the value of attribute idempotency_store.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def idempotency_store
  @idempotency_store
end

#limits ⇒ Object (readonly)

Returns the value of attribute limits.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def limits
  @limits
end

#max_sink_records ⇒ Object (readonly)

Returns the value of attribute max_sink_records.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def max_sink_records
  @max_sink_records
end

#probes ⇒ Object (readonly)

Returns the value of attribute probes.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def probes
  @probes
end

#request_lock ⇒ Object (readonly)

Returns the value of attribute request_lock.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def request_lock
  @request_lock
end

#reset_handler ⇒ Object (readonly)

Returns the value of attribute reset_handler.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def reset_handler
  @reset_handler
end

#reset_strategy ⇒ Object (readonly)

Returns the value of attribute reset_strategy.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def reset_strategy
  @reset_strategy
end

#sink_store ⇒ Object (readonly)

Returns the value of attribute sink_store.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def sink_store
  @sink_store
end

#sinks ⇒ Object (readonly)

Returns the value of attribute sinks.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def sinks
  @sinks
end

#states ⇒ Object (readonly)

Returns the value of attribute states.



45
46
47
# File 'lib/overseer/testing_control/rails/configuration.rb', line 45

def states
  @states
end

Instance Method Details

#application_id ⇒ Object



154
155
156
# File 'lib/overseer/testing_control/rails/configuration.rb', line 154

def application_id
  resolve_identity(:application)
end

#application_version ⇒ Object



162
163
164
# File 'lib/overseer/testing_control/rails/configuration.rb', line 162

def application_version
  resolve_identity(:source)
end

#bounds(max_request_bytes: limits.fetch('maxRequestBytes'), max_response_bytes: limits.fetch('maxResponseBytes'), max_schema_bytes: limits.fetch('maxSchemaBytes'), max_sink_records_per_query: limits.fetch('maxSinkRecordsPerQuery'), max_sink_record_bytes: limits.fetch('maxSinkRecordBytes'), idempotency_entries: @idempotency_limit, sink_records: max_sink_records) ⇒ Object



86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/overseer/testing_control/rails/configuration.rb', line 86

def bounds(
  max_request_bytes: limits.fetch('maxRequestBytes'),
  max_response_bytes: limits.fetch('maxResponseBytes'),
  max_schema_bytes: limits.fetch('maxSchemaBytes'),
  max_sink_records_per_query: limits.fetch('maxSinkRecordsPerQuery'),
  max_sink_record_bytes: limits.fetch('maxSinkRecordBytes'),
  idempotency_entries: @idempotency_limit,
  sink_records: max_sink_records
)
  mutable!
  candidate = {
    'maxRequestBytes' => max_request_bytes,
    'maxResponseBytes' => max_response_bytes,
    'maxSchemaBytes' => max_schema_bytes,
    'maxSinkRecordsPerQuery' => max_sink_records_per_query,
    'maxSinkRecordBytes' => max_sink_record_bytes
  }
  validate_limits!(candidate, idempotency_entries:, sink_records:)
  @limits = candidate.freeze
  @idempotency_limit = idempotency_entries
  @max_sink_records = sink_records
  rebuild_stores!
end

#capabilities_data ⇒ Object



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/overseer/testing_control/rails/configuration.rb', line 174

def capabilities_data
  finalize!
  {
    'application' => { 'id' => application_id, 'version' => application_version },
    'environment' => {
      'id' => environment_id,
      'kind' => environment_kind,
      'isolated' => environment_isolated
    },
    'reset' => { 'strategy' => reset_strategy, 'clearsSinks' => true },
    'features' => FEATURES,
    'limits' => limits,
    'safety' => {
      'syntheticDataRequired' => true,
      'realCredentialsAllowed' => false,
      'secretPersistenceAllowed' => false,
      'externalNetwork' => 'blocked'
    },
    'states' => states.map { |state| state_document(state) },
    'probes' => probes.map { |probe| probe_document(probe) },
    'sinks' => sinks.map { |sink| sink_document(sink) }
  }
end

#clear_stores! ⇒ Object



213
214
215
216
# File 'lib/overseer/testing_control/rails/configuration.rb', line 213

def clear_stores!
  idempotency_store.clear
  sink_store.clear
end

#environment_id ⇒ Object



158
159
160
# File 'lib/overseer/testing_control/rails/configuration.rb', line 158

def environment_id
  resolve_identity(:environment)
end

#environment_isolated ⇒ Object



170
171
172
# File 'lib/overseer/testing_control/rails/configuration.rb', line 170

def environment_isolated
  resolve_identity(:isolated)
end

#environment_kind ⇒ Object



166
167
168
# File 'lib/overseer/testing_control/rails/configuration.rb', line 166

def environment_kind
  resolve_identity(:kind)
end

#finalize! ⇒ Object



134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/overseer/testing_control/rails/configuration.rb', line 134

def finalize!
  return self if @finalized

  validate!
  @states.freeze
  @probes.freeze
  @sinks.freeze
  @finalized = true
  self
rescue ProtocolV3::ValidationError => e
  raise ConfigurationError, e.message
end

#identity(application:, source: DEFAULT_SOURCE_PROVIDER, environment: DEFAULT_ENVIRONMENT_PROVIDER, kind: 'test', isolated: true) ⇒ Object



69
70
71
72
73
74
75
76
77
78
# File 'lib/overseer/testing_control/rails/configuration.rb', line 69

def identity(
  application:,
  source: DEFAULT_SOURCE_PROVIDER,
  environment: DEFAULT_ENVIRONMENT_PROVIDER,
  kind: 'test',
  isolated: true
)
  mutable!
  @identity = { application:, source:, environment:, kind:, isolated: }
end

#probe!(id, version) ⇒ Object



203
204
205
206
# File 'lib/overseer/testing_control/rails/configuration.rb', line 203

def probe!(id, version)
  probes.find { |item| item.id == id && item.version == version } ||
    raise(ProtocolV3::ValidationError, "probe capability #{id}@#{version} is unavailable")
end

#register_probe(id:, version:, title:, input_schema:, output_schema:, handler:, description: nil) ⇒ Object



118
119
120
121
# File 'lib/overseer/testing_control/rails/configuration.rb', line 118

def register_probe(id:, version:, title:, input_schema:, output_schema:, handler:, description: nil)
  mutable!
  @probes << Probe.new(id:, version:, title:, description:, input_schema:, output_schema:, handler:)
end

#register_sink(id:, version:, title:, effect_kinds:, outcomes:, query_input_schema:, record_schema:, description: nil, query_matcher: nil) ⇒ Object



123
124
125
126
127
128
129
130
131
132
# File 'lib/overseer/testing_control/rails/configuration.rb', line 123

def register_sink(
  id:, version:, title:, effect_kinds:, outcomes:, query_input_schema:, record_schema:,
  description: nil, query_matcher: nil
)
  mutable!
  @sinks << Sink.new(
    id:, version:, title:, description:, effect_kinds:, outcomes:, query_input_schema:,
    record_schema:, query_matcher:
  )
end

#register_state(id:, version:, title:, idempotency:, input_schema:, output_schema:, handler:, description: nil) ⇒ Object



110
111
112
113
114
115
116
# File 'lib/overseer/testing_control/rails/configuration.rb', line 110

def register_state(id:, version:, title:, idempotency:, input_schema:, output_schema:, handler:,
                   description: nil)
  mutable!
  @states << State.new(
    id:, version:, title:, description:, idempotency:, input_schema:, output_schema:, handler:
  )
end

#reset(strategy:, handler: nil) ⇒ Object



80
81
82
83
84
# File 'lib/overseer/testing_control/rails/configuration.rb', line 80

def reset(strategy:, handler: nil)
  mutable!
  @reset_strategy = strategy
  @reset_handler = handler
end

#runtime_identity_valid? ⇒ Boolean

Returns:

  • (Boolean)


147
148
149
150
151
152
# File 'lib/overseer/testing_control/rails/configuration.rb', line 147

def runtime_identity_valid?
  validate_identity!
  true
rescue ConfigurationError, ProtocolV3::ValidationError, KeyError, TypeError
  false
end

#sink!(id, version) ⇒ Object



208
209
210
211
# File 'lib/overseer/testing_control/rails/configuration.rb', line 208

def sink!(id, version)
  sinks.find { |item| item.id == id && item.version == version } ||
    raise(ProtocolV3::ValidationError, "sink capability #{id}@#{version} is unavailable")
end

#state!(id, version) ⇒ Object



198
199
200
201
# File 'lib/overseer/testing_control/rails/configuration.rb', line 198

def state!(id, version)
  states.find { |item| item.id == id && item.version == version } ||
    raise(ProtocolV3::ValidationError, "state capability #{id}@#{version} is unavailable")
end