decision_agent 0.1.4 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +83 -232
  3. data/bin/decision_agent +1 -1
  4. data/lib/decision_agent/ab_testing/ab_testing_agent.rb +46 -10
  5. data/lib/decision_agent/agent.rb +5 -3
  6. data/lib/decision_agent/auth/access_audit_logger.rb +122 -0
  7. data/lib/decision_agent/auth/authenticator.rb +127 -0
  8. data/lib/decision_agent/auth/password_reset_manager.rb +57 -0
  9. data/lib/decision_agent/auth/password_reset_token.rb +33 -0
  10. data/lib/decision_agent/auth/permission.rb +29 -0
  11. data/lib/decision_agent/auth/permission_checker.rb +43 -0
  12. data/lib/decision_agent/auth/rbac_adapter.rb +278 -0
  13. data/lib/decision_agent/auth/rbac_config.rb +51 -0
  14. data/lib/decision_agent/auth/role.rb +56 -0
  15. data/lib/decision_agent/auth/session.rb +33 -0
  16. data/lib/decision_agent/auth/session_manager.rb +57 -0
  17. data/lib/decision_agent/auth/user.rb +70 -0
  18. data/lib/decision_agent/context.rb +24 -4
  19. data/lib/decision_agent/decision.rb +10 -3
  20. data/lib/decision_agent/dsl/condition_evaluator.rb +378 -1
  21. data/lib/decision_agent/dsl/schema_validator.rb +8 -1
  22. data/lib/decision_agent/errors.rb +38 -0
  23. data/lib/decision_agent/evaluation.rb +10 -3
  24. data/lib/decision_agent/evaluation_validator.rb +8 -13
  25. data/lib/decision_agent/monitoring/dashboard_server.rb +1 -0
  26. data/lib/decision_agent/monitoring/metrics_collector.rb +17 -5
  27. data/lib/decision_agent/testing/batch_test_importer.rb +373 -0
  28. data/lib/decision_agent/testing/batch_test_runner.rb +244 -0
  29. data/lib/decision_agent/testing/test_coverage_analyzer.rb +191 -0
  30. data/lib/decision_agent/testing/test_result_comparator.rb +235 -0
  31. data/lib/decision_agent/testing/test_scenario.rb +42 -0
  32. data/lib/decision_agent/version.rb +10 -1
  33. data/lib/decision_agent/versioning/activerecord_adapter.rb +1 -1
  34. data/lib/decision_agent/versioning/file_storage_adapter.rb +96 -28
  35. data/lib/decision_agent/web/middleware/auth_middleware.rb +45 -0
  36. data/lib/decision_agent/web/middleware/permission_middleware.rb +94 -0
  37. data/lib/decision_agent/web/public/app.js +184 -29
  38. data/lib/decision_agent/web/public/batch_testing.html +640 -0
  39. data/lib/decision_agent/web/public/index.html +38 -10
  40. data/lib/decision_agent/web/public/login.html +298 -0
  41. data/lib/decision_agent/web/public/users.html +679 -0
  42. data/lib/decision_agent/web/server.rb +873 -7
  43. data/lib/decision_agent.rb +52 -0
  44. data/lib/generators/decision_agent/install/templates/README +1 -1
  45. data/lib/generators/decision_agent/install/templates/rule_version.rb +1 -1
  46. data/spec/ab_testing/ab_test_assignment_spec.rb +253 -0
  47. data/spec/ab_testing/ab_test_manager_spec.rb +282 -0
  48. data/spec/ab_testing/ab_testing_agent_spec.rb +481 -0
  49. data/spec/ab_testing/storage/adapter_spec.rb +64 -0
  50. data/spec/ab_testing/storage/memory_adapter_spec.rb +485 -0
  51. data/spec/advanced_operators_spec.rb +1003 -0
  52. data/spec/agent_spec.rb +40 -0
  53. data/spec/audit_adapters_spec.rb +18 -0
  54. data/spec/auth/access_audit_logger_spec.rb +394 -0
  55. data/spec/auth/authenticator_spec.rb +112 -0
  56. data/spec/auth/password_reset_spec.rb +294 -0
  57. data/spec/auth/permission_checker_spec.rb +207 -0
  58. data/spec/auth/permission_spec.rb +73 -0
  59. data/spec/auth/rbac_adapter_spec.rb +550 -0
  60. data/spec/auth/rbac_config_spec.rb +82 -0
  61. data/spec/auth/role_spec.rb +51 -0
  62. data/spec/auth/session_manager_spec.rb +172 -0
  63. data/spec/auth/session_spec.rb +112 -0
  64. data/spec/auth/user_spec.rb +130 -0
  65. data/spec/context_spec.rb +43 -0
  66. data/spec/decision_agent_spec.rb +96 -0
  67. data/spec/decision_spec.rb +423 -0
  68. data/spec/dsl/condition_evaluator_spec.rb +774 -0
  69. data/spec/evaluation_spec.rb +364 -0
  70. data/spec/evaluation_validator_spec.rb +165 -0
  71. data/spec/monitoring/metrics_collector_spec.rb +220 -2
  72. data/spec/monitoring/storage/activerecord_adapter_spec.rb +153 -1
  73. data/spec/monitoring/storage/base_adapter_spec.rb +61 -0
  74. data/spec/performance_optimizations_spec.rb +486 -0
  75. data/spec/spec_helper.rb +23 -0
  76. data/spec/testing/batch_test_importer_spec.rb +693 -0
  77. data/spec/testing/batch_test_runner_spec.rb +307 -0
  78. data/spec/testing/test_coverage_analyzer_spec.rb +292 -0
  79. data/spec/testing/test_result_comparator_spec.rb +392 -0
  80. data/spec/testing/test_scenario_spec.rb +113 -0
  81. data/spec/versioning/adapter_spec.rb +156 -0
  82. data/spec/versioning_spec.rb +253 -0
  83. data/spec/web/middleware/auth_middleware_spec.rb +133 -0
  84. data/spec/web/middleware/permission_middleware_spec.rb +247 -0
  85. data/spec/web_ui_rack_spec.rb +1705 -0
  86. metadata +103 -11
  87. data/spec/examples.txt +0 -612
@@ -266,7 +266,7 @@ RSpec.describe DecisionAgent::Monitoring::MetricsCollector do
266
266
 
267
267
  describe "metric cleanup" do
268
268
  it "removes old metrics outside window" do
269
- collector = described_class.new(window_size: 1, storage: :memory)
269
+ collector = described_class.new(window_size: 1, storage: :memory, cleanup_threshold: 1)
270
270
 
271
271
  collector.record_decision(decision, context)
272
272
  expect(collector.metrics_count[:decisions]).to eq(1)
@@ -274,8 +274,226 @@ RSpec.describe DecisionAgent::Monitoring::MetricsCollector do
274
274
  sleep 1.5
275
275
 
276
276
  collector.record_decision(decision, context)
277
- # Old metric should be cleaned up
277
+ # Old metric should be cleaned up (threshold=1 means cleanup on every record)
278
278
  expect(collector.metrics_count[:decisions]).to eq(1)
279
279
  end
280
280
  end
281
+
282
+ describe "#record_evaluation" do
283
+ let(:evaluation) do
284
+ double(
285
+ "Evaluation",
286
+ decision: "approve",
287
+ weight: 0.9,
288
+ evaluator_name: "test_evaluator"
289
+ )
290
+ end
291
+
292
+ it "notifies observers" do
293
+ observed = []
294
+ collector.add_observer do |type, metric|
295
+ observed << [type, metric]
296
+ end
297
+
298
+ collector.record_evaluation(evaluation)
299
+
300
+ expect(observed.size).to eq(1)
301
+ expect(observed[0][0]).to eq(:evaluation)
302
+ expect(observed[0][1][:decision]).to eq("approve")
303
+ end
304
+ end
305
+
306
+ describe "#record_performance" do
307
+ it "notifies observers" do
308
+ observed = []
309
+ collector.add_observer do |type, metric|
310
+ observed << [type, metric]
311
+ end
312
+
313
+ collector.record_performance(operation: "test", duration_ms: 10.0, success: true)
314
+
315
+ expect(observed.size).to eq(1)
316
+ expect(observed[0][0]).to eq(:performance)
317
+ expect(observed[0][1][:operation]).to eq("test")
318
+ end
319
+ end
320
+
321
+ describe "#record_error" do
322
+ it "notifies observers" do
323
+ observed = []
324
+ collector.add_observer do |type, metric|
325
+ observed << [type, metric]
326
+ end
327
+
328
+ collector.record_error(StandardError.new("Test"))
329
+
330
+ expect(observed.size).to eq(1)
331
+ expect(observed[0][0]).to eq(:error)
332
+ expect(observed[0][1][:error_class]).to eq("StandardError")
333
+ end
334
+
335
+ it "handles different error types" do
336
+ expect { collector.record_error(ArgumentError.new("Arg error")) }.not_to raise_error
337
+ expect { collector.record_error(TypeError.new("Type error")) }.not_to raise_error
338
+ expect { collector.record_error(Exception.new("Exception")) }.not_to raise_error
339
+ end
340
+ end
341
+
342
+ describe "#add_observer" do
343
+ it "adds an observer callback" do
344
+ callback = proc { |type, metric| }
345
+ collector.add_observer(&callback)
346
+ # Observer should be stored
347
+ expect(collector.instance_variable_get(:@observers)).to include(callback)
348
+ end
349
+
350
+ it "handles observer errors gracefully" do
351
+ # Add observer that raises error
352
+ collector.add_observer do |_type, _metric|
353
+ raise "Observer error"
354
+ end
355
+
356
+ # Should not raise, just warn
357
+ expect { collector.record_decision(decision, context) }.not_to raise_error
358
+ end
359
+ end
360
+
361
+ describe "#statistics" do
362
+ before do
363
+ 3.times do
364
+ evaluation = double("Evaluation", decision: "approve", weight: 0.8, evaluator_name: "eval1")
365
+ collector.record_evaluation(evaluation)
366
+ end
367
+ 2.times do
368
+ evaluation = double("Evaluation", decision: "reject", weight: 0.6, evaluator_name: "eval2")
369
+ collector.record_evaluation(evaluation)
370
+ end
371
+ end
372
+
373
+ it "computes evaluation statistics" do
374
+ stats = collector.statistics
375
+ expect(stats[:evaluations][:total]).to eq(5)
376
+ expect(stats[:evaluations][:avg_weight]).to be_within(0.01).of(0.72)
377
+ end
378
+
379
+ it "handles empty decisions gracefully" do
380
+ empty_collector = described_class.new(storage: :memory)
381
+ stats = empty_collector.statistics
382
+ expect(stats[:decisions]).to eq({})
383
+ end
384
+
385
+ it "handles decisions without duration_ms" do
386
+ decision_no_duration = double(
387
+ "Decision",
388
+ decision: "approve",
389
+ confidence: 0.5,
390
+ evaluations: []
391
+ )
392
+ collector.record_decision(decision_no_duration, context)
393
+ stats = collector.statistics
394
+ expect(stats[:decisions][:avg_duration_ms]).to be_nil
395
+ end
396
+ end
397
+
398
+ describe "#time_series" do
399
+ it "handles empty metric types" do
400
+ series = collector.time_series(metric_type: :nonexistent, bucket_size: 60, time_range: 3600)
401
+ expect(series).to eq([])
402
+ end
403
+
404
+ it "filters metrics by time range" do
405
+ # Record some old metrics (simulated)
406
+ old_time = Time.now.utc - 7200
407
+ allow(Time).to receive(:now).and_return(Time.at(old_time.to_i))
408
+ 5.times { collector.record_decision(decision, context) }
409
+
410
+ # Record new metrics
411
+ allow(Time).to receive(:now).and_call_original
412
+ 3.times { collector.record_decision(decision, context) }
413
+
414
+ series = collector.time_series(metric_type: :decisions, bucket_size: 60, time_range: 3600)
415
+ # Should only include recent metrics
416
+ total = series.sum { |s| s[:count] }
417
+ expect(total).to be <= 3
418
+ end
419
+ end
420
+
421
+ describe "#cleanup_old_metrics_from_storage" do
422
+ it "delegates to storage adapter if it has cleanup method" do
423
+ # Using memory adapter which doesn't have cleanup
424
+ expect(collector.cleanup_old_metrics_from_storage(older_than: 3600)).to eq(0)
425
+ end
426
+ end
427
+
428
+ describe "#initialize_storage_adapter" do
429
+ it "uses memory storage when :memory specified" do
430
+ collector = described_class.new(storage: :memory)
431
+ expect(collector.storage_adapter).to be_a(DecisionAgent::Monitoring::Storage::MemoryAdapter)
432
+ end
433
+
434
+ it "raises error for unknown storage option" do
435
+ expect do
436
+ described_class.new(storage: :unknown)
437
+ end.to raise_error(ArgumentError, /Unknown storage option/)
438
+ end
439
+ end
440
+
441
+ describe "error severity determination" do
442
+ it "determines severity for ArgumentError as medium" do
443
+ error = ArgumentError.new("test")
444
+ collector.record_error(error)
445
+ # Just verify it doesn't raise
446
+ expect(collector.metrics_count[:errors]).to eq(1)
447
+ end
448
+
449
+ it "determines severity for TypeError as medium" do
450
+ error = TypeError.new("test")
451
+ collector.record_error(error)
452
+ expect(collector.metrics_count[:errors]).to eq(1)
453
+ end
454
+
455
+ it "determines severity for Exception as critical" do
456
+ error = Exception.new("test")
457
+ collector.record_error(error)
458
+ expect(collector.metrics_count[:errors]).to eq(1)
459
+ end
460
+ end
461
+
462
+ describe "decision status determination" do
463
+ it "determines status for high confidence decisions" do
464
+ high_conf_decision = double(
465
+ "Decision",
466
+ decision: "approve",
467
+ confidence: 0.9,
468
+ evaluations: []
469
+ )
470
+ collector.record_decision(high_conf_decision, context)
471
+ # Just verify it records successfully
472
+ expect(collector.metrics_count[:decisions]).to eq(1)
473
+ end
474
+
475
+ it "determines status for low confidence decisions" do
476
+ low_conf_decision = double(
477
+ "Decision",
478
+ decision: "approve",
479
+ confidence: 0.2,
480
+ evaluations: []
481
+ )
482
+ collector.record_decision(low_conf_decision, context)
483
+ expect(collector.metrics_count[:decisions]).to eq(1)
484
+ end
485
+ end
486
+
487
+ describe "#compute_performance_stats" do
488
+ it "computes percentile statistics" do
489
+ durations = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
490
+ durations.each do |duration|
491
+ collector.record_performance(operation: "test", duration_ms: duration, success: true)
492
+ end
493
+
494
+ stats = collector.statistics
495
+ expect(stats[:performance][:p95_duration_ms]).to be >= 90
496
+ expect(stats[:performance][:p99_duration_ms]).to be >= 95
497
+ end
498
+ end
281
499
  end
@@ -170,6 +170,13 @@ RSpec.describe DecisionAgent::Monitoring::Storage::ActiveRecordAdapter do
170
170
  expect(log.status).to eq("success")
171
171
  expect(log.parsed_context).to eq(user_id: 123, amount: 500)
172
172
  end
173
+
174
+ it "handles database errors gracefully" do
175
+ allow(DecisionLog).to receive(:create!).and_raise(StandardError.new("DB error"))
176
+ expect do
177
+ adapter.record_decision("test", {})
178
+ end.not_to raise_error
179
+ end
173
180
  end
174
181
 
175
182
  describe "#record_evaluation" do
@@ -191,6 +198,13 @@ RSpec.describe DecisionAgent::Monitoring::Storage::ActiveRecordAdapter do
191
198
  expect(metric.duration_ms).to eq(12.3)
192
199
  expect(metric.parsed_details).to eq(risk_level: "low")
193
200
  end
201
+
202
+ it "handles database errors gracefully" do
203
+ allow(EvaluationMetric).to receive(:create!).and_raise(StandardError.new("DB error"))
204
+ expect do
205
+ adapter.record_evaluation("test")
206
+ end.not_to raise_error
207
+ end
194
208
  end
195
209
 
196
210
  describe "#record_performance" do
@@ -209,6 +223,13 @@ RSpec.describe DecisionAgent::Monitoring::Storage::ActiveRecordAdapter do
209
223
  expect(metric.duration_ms).to eq(250.5)
210
224
  expect(metric.status).to eq("success")
211
225
  end
226
+
227
+ it "handles database errors gracefully" do
228
+ allow(PerformanceMetric).to receive(:create!).and_raise(StandardError.new("DB error"))
229
+ expect do
230
+ adapter.record_performance("test")
231
+ end.not_to raise_error
232
+ end
212
233
  end
213
234
 
214
235
  describe "#record_error" do
@@ -229,6 +250,19 @@ RSpec.describe DecisionAgent::Monitoring::Storage::ActiveRecordAdapter do
229
250
  expect(error.severity).to eq("critical")
230
251
  expect(error.parsed_context).to eq(user_id: 456)
231
252
  end
253
+
254
+ it "handles nil stack_trace" do
255
+ adapter.record_error("TestError", stack_trace: nil)
256
+ error = ErrorMetric.last
257
+ expect(error.stack_trace).to be_nil
258
+ end
259
+
260
+ it "handles database errors gracefully" do
261
+ allow(ErrorMetric).to receive(:create!).and_raise(StandardError.new("DB error"))
262
+ expect do
263
+ adapter.record_error("test")
264
+ end.not_to raise_error
265
+ end
232
266
  end
233
267
 
234
268
  describe "#statistics" do
@@ -275,6 +309,37 @@ RSpec.describe DecisionAgent::Monitoring::Storage::ActiveRecordAdapter do
275
309
  expect(stats[:errors][:total]).to eq(1)
276
310
  expect(stats[:errors][:critical_count]).to eq(1)
277
311
  end
312
+
313
+ it "handles empty statistics" do
314
+ DecisionLog.delete_all
315
+ EvaluationMetric.delete_all
316
+ PerformanceMetric.delete_all
317
+ ErrorMetric.delete_all
318
+
319
+ stats = adapter.statistics(time_range: 3600)
320
+
321
+ expect(stats[:decisions][:total]).to eq(0)
322
+ expect(stats[:decisions][:average_confidence]).to eq(0.0)
323
+ expect(stats[:evaluations][:total]).to eq(0)
324
+ expect(stats[:performance][:total]).to eq(0)
325
+ expect(stats[:errors][:total]).to eq(0)
326
+ end
327
+
328
+ it "handles decisions without confidence" do
329
+ DecisionLog.delete_all
330
+ adapter.record_decision("test", {}, confidence: nil)
331
+
332
+ stats = adapter.statistics(time_range: 3600)
333
+ expect(stats[:decisions][:average_confidence]).to eq(0.0)
334
+ end
335
+
336
+ it "handles database errors gracefully" do
337
+ allow(DecisionLog).to receive(:recent).and_raise(StandardError.new("DB error"))
338
+ stats = adapter.statistics(time_range: 3600)
339
+
340
+ expect(stats[:decisions][:total]).to eq(0)
341
+ expect(stats[:evaluations][:total]).to eq(0)
342
+ end
278
343
  end
279
344
 
280
345
  describe "#time_series" do
@@ -290,13 +355,77 @@ RSpec.describe DecisionAgent::Monitoring::Storage::ActiveRecordAdapter do
290
355
  end
291
356
  end
292
357
 
293
- it "returns time series data grouped by buckets" do
358
+ it "returns time series data grouped by buckets for decisions" do
294
359
  series = adapter.time_series(:decisions, bucket_size: 60, time_range: 200)
295
360
 
296
361
  expect(series[:timestamps]).to be_an(Array)
297
362
  expect(series[:data]).to be_an(Array)
298
363
  expect(series[:data].sum).to eq(3)
299
364
  end
365
+
366
+ it "returns time series data for evaluations" do
367
+ [10, 70].each do |seconds_ago|
368
+ travel_back = Time.now - seconds_ago
369
+ EvaluationMetric.create!(
370
+ evaluator_name: "test",
371
+ score: 0.8,
372
+ created_at: travel_back
373
+ )
374
+ end
375
+
376
+ series = adapter.time_series(:evaluations, bucket_size: 60, time_range: 200)
377
+
378
+ expect(series[:timestamps]).to be_an(Array)
379
+ expect(series[:data]).to be_an(Array)
380
+ expect(series[:data].sum).to eq(2)
381
+ end
382
+
383
+ it "returns time series data for performance" do
384
+ [10, 70].each do |seconds_ago|
385
+ travel_back = Time.now - seconds_ago
386
+ PerformanceMetric.create!(
387
+ operation: "test",
388
+ duration_ms: 100,
389
+ created_at: travel_back
390
+ )
391
+ end
392
+
393
+ series = adapter.time_series(:performance, bucket_size: 60, time_range: 200)
394
+
395
+ expect(series[:timestamps]).to be_an(Array)
396
+ expect(series[:data]).to be_an(Array)
397
+ end
398
+
399
+ it "returns time series data for errors" do
400
+ [10, 70].each do |seconds_ago|
401
+ travel_back = Time.now - seconds_ago
402
+ ErrorMetric.create!(
403
+ error_type: "TestError",
404
+ created_at: travel_back
405
+ )
406
+ end
407
+
408
+ series = adapter.time_series(:errors, bucket_size: 60, time_range: 200)
409
+
410
+ expect(series[:timestamps]).to be_an(Array)
411
+ expect(series[:data]).to be_an(Array)
412
+ expect(series[:data].sum).to eq(2)
413
+ end
414
+
415
+ it "returns empty data for unknown metric type" do
416
+ series = adapter.time_series(:unknown, bucket_size: 60, time_range: 200)
417
+
418
+ expect(series[:timestamps]).to eq([])
419
+ expect(series[:data]).to eq([])
420
+ end
421
+
422
+ it "handles database errors gracefully" do
423
+ allow(DecisionLog).to receive(:recent).and_raise(StandardError.new("DB error"))
424
+ series = adapter.time_series(:decisions, bucket_size: 60, time_range: 200)
425
+
426
+ expect(series[:timestamps]).to eq([])
427
+ expect(series[:data]).to eq([])
428
+ end
300
429
  end
301
430
 
302
431
  describe "#metrics_count" do
@@ -315,6 +444,16 @@ RSpec.describe DecisionAgent::Monitoring::Storage::ActiveRecordAdapter do
315
444
  expect(counts[:performance]).to eq(1)
316
445
  expect(counts[:errors]).to eq(1)
317
446
  end
447
+
448
+ it "handles database errors gracefully" do
449
+ allow(DecisionLog).to receive(:count).and_raise(StandardError.new("DB error"))
450
+ counts = adapter.metrics_count
451
+
452
+ expect(counts[:decisions]).to eq(0)
453
+ expect(counts[:evaluations]).to eq(0)
454
+ expect(counts[:performance]).to eq(0)
455
+ expect(counts[:errors]).to eq(0)
456
+ end
318
457
  end
319
458
 
320
459
  describe "#cleanup" do
@@ -342,5 +481,18 @@ RSpec.describe DecisionAgent::Monitoring::Storage::ActiveRecordAdapter do
342
481
  expect(PerformanceMetric.count).to eq(1)
343
482
  expect(ErrorMetric.count).to eq(1)
344
483
  end
484
+
485
+ it "handles database errors gracefully" do
486
+ allow(DecisionLog).to receive(:where).and_raise(StandardError.new("DB error"))
487
+ count = adapter.cleanup(older_than: 7.days.to_i)
488
+
489
+ expect(count).to eq(0)
490
+ end
491
+ end
492
+
493
+ describe "#initialize" do
494
+ it "validates required models exist" do
495
+ expect { described_class.new }.not_to raise_error
496
+ end
345
497
  end
346
498
  end
@@ -0,0 +1,61 @@
1
+ require "spec_helper"
2
+
3
+ RSpec.describe DecisionAgent::Monitoring::Storage::BaseAdapter do
4
+ let(:adapter) { described_class.new }
5
+
6
+ describe "abstract methods" do
7
+ it "raises NotImplementedError for record_decision" do
8
+ expect do
9
+ adapter.record_decision("approve", {})
10
+ end.to raise_error(NotImplementedError)
11
+ end
12
+
13
+ it "raises NotImplementedError for record_evaluation" do
14
+ expect do
15
+ adapter.record_evaluation("evaluator1")
16
+ end.to raise_error(NotImplementedError)
17
+ end
18
+
19
+ it "raises NotImplementedError for record_performance" do
20
+ expect do
21
+ adapter.record_performance("operation")
22
+ end.to raise_error(NotImplementedError)
23
+ end
24
+
25
+ it "raises NotImplementedError for record_error" do
26
+ expect do
27
+ adapter.record_error("ErrorType")
28
+ end.to raise_error(NotImplementedError)
29
+ end
30
+
31
+ it "raises NotImplementedError for statistics" do
32
+ expect do
33
+ adapter.statistics
34
+ end.to raise_error(NotImplementedError)
35
+ end
36
+
37
+ it "raises NotImplementedError for time_series" do
38
+ expect do
39
+ adapter.time_series(:decisions)
40
+ end.to raise_error(NotImplementedError)
41
+ end
42
+
43
+ it "raises NotImplementedError for metrics_count" do
44
+ expect do
45
+ adapter.metrics_count
46
+ end.to raise_error(NotImplementedError)
47
+ end
48
+
49
+ it "raises NotImplementedError for cleanup" do
50
+ expect do
51
+ adapter.cleanup(older_than: 3600)
52
+ end.to raise_error(NotImplementedError)
53
+ end
54
+
55
+ it "raises NotImplementedError for available?" do
56
+ expect do
57
+ described_class.available?
58
+ end.to raise_error(NotImplementedError)
59
+ end
60
+ end
61
+ end