decision_agent 0.3.0 → 1.0.1
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.
- checksums.yaml +4 -4
- data/README.md +272 -7
- data/lib/decision_agent/agent.rb +72 -1
- data/lib/decision_agent/context.rb +1 -0
- data/lib/decision_agent/data_enrichment/cache/memory_adapter.rb +86 -0
- data/lib/decision_agent/data_enrichment/cache_adapter.rb +49 -0
- data/lib/decision_agent/data_enrichment/circuit_breaker.rb +135 -0
- data/lib/decision_agent/data_enrichment/client.rb +220 -0
- data/lib/decision_agent/data_enrichment/config.rb +78 -0
- data/lib/decision_agent/data_enrichment/errors.rb +36 -0
- data/lib/decision_agent/decision.rb +102 -2
- data/lib/decision_agent/dmn/feel/evaluator.rb +28 -6
- data/lib/decision_agent/dsl/condition_evaluator.rb +982 -839
- data/lib/decision_agent/dsl/schema_validator.rb +51 -13
- data/lib/decision_agent/evaluators/dmn_evaluator.rb +106 -19
- data/lib/decision_agent/evaluators/json_rule_evaluator.rb +69 -9
- data/lib/decision_agent/explainability/condition_trace.rb +83 -0
- data/lib/decision_agent/explainability/explainability_result.rb +52 -0
- data/lib/decision_agent/explainability/rule_trace.rb +39 -0
- data/lib/decision_agent/explainability/trace_collector.rb +24 -0
- data/lib/decision_agent/monitoring/alert_manager.rb +5 -1
- data/lib/decision_agent/simulation/errors.rb +18 -0
- data/lib/decision_agent/simulation/impact_analyzer.rb +498 -0
- data/lib/decision_agent/simulation/monte_carlo_simulator.rb +635 -0
- data/lib/decision_agent/simulation/replay_engine.rb +486 -0
- data/lib/decision_agent/simulation/scenario_engine.rb +318 -0
- data/lib/decision_agent/simulation/scenario_library.rb +163 -0
- data/lib/decision_agent/simulation/shadow_test_engine.rb +287 -0
- data/lib/decision_agent/simulation/what_if_analyzer.rb +1002 -0
- data/lib/decision_agent/simulation.rb +17 -0
- data/lib/decision_agent/version.rb +1 -1
- data/lib/decision_agent/versioning/activerecord_adapter.rb +23 -8
- data/lib/decision_agent/web/public/app.js +119 -0
- data/lib/decision_agent/web/public/index.html +49 -0
- data/lib/decision_agent/web/public/simulation.html +130 -0
- data/lib/decision_agent/web/public/simulation_impact.html +478 -0
- data/lib/decision_agent/web/public/simulation_replay.html +551 -0
- data/lib/decision_agent/web/public/simulation_shadow.html +546 -0
- data/lib/decision_agent/web/public/simulation_whatif.html +532 -0
- data/lib/decision_agent/web/public/styles.css +65 -0
- data/lib/decision_agent/web/server.rb +594 -23
- data/lib/decision_agent.rb +60 -2
- metadata +53 -73
- data/spec/ab_testing/ab_test_assignment_spec.rb +0 -253
- data/spec/ab_testing/ab_test_manager_spec.rb +0 -612
- data/spec/ab_testing/ab_test_spec.rb +0 -270
- data/spec/ab_testing/ab_testing_agent_spec.rb +0 -655
- data/spec/ab_testing/storage/adapter_spec.rb +0 -64
- data/spec/ab_testing/storage/memory_adapter_spec.rb +0 -485
- data/spec/activerecord_thread_safety_spec.rb +0 -553
- data/spec/advanced_operators_spec.rb +0 -3150
- data/spec/agent_spec.rb +0 -289
- data/spec/api_contract_spec.rb +0 -430
- data/spec/audit_adapters_spec.rb +0 -92
- data/spec/auth/access_audit_logger_spec.rb +0 -394
- data/spec/auth/authenticator_spec.rb +0 -112
- data/spec/auth/password_reset_spec.rb +0 -294
- data/spec/auth/permission_checker_spec.rb +0 -207
- data/spec/auth/permission_spec.rb +0 -73
- data/spec/auth/rbac_adapter_spec.rb +0 -778
- data/spec/auth/rbac_config_spec.rb +0 -82
- data/spec/auth/role_spec.rb +0 -51
- data/spec/auth/session_manager_spec.rb +0 -172
- data/spec/auth/session_spec.rb +0 -112
- data/spec/auth/user_spec.rb +0 -130
- data/spec/comprehensive_edge_cases_spec.rb +0 -1777
- data/spec/context_spec.rb +0 -127
- data/spec/decision_agent_spec.rb +0 -96
- data/spec/decision_spec.rb +0 -423
- data/spec/dmn/decision_graph_spec.rb +0 -282
- data/spec/dmn/decision_tree_spec.rb +0 -203
- data/spec/dmn/feel/errors_spec.rb +0 -18
- data/spec/dmn/feel/functions_spec.rb +0 -400
- data/spec/dmn/feel/simple_parser_spec.rb +0 -274
- data/spec/dmn/feel/types_spec.rb +0 -176
- data/spec/dmn/feel_parser_spec.rb +0 -489
- data/spec/dmn/hit_policy_spec.rb +0 -202
- data/spec/dmn/integration_spec.rb +0 -226
- data/spec/dsl/condition_evaluator_spec.rb +0 -774
- data/spec/dsl_validation_spec.rb +0 -648
- data/spec/edge_cases_spec.rb +0 -353
- data/spec/evaluation_spec.rb +0 -364
- data/spec/evaluation_validator_spec.rb +0 -165
- data/spec/examples/feedback_aware_evaluator_spec.rb +0 -460
- data/spec/examples.txt +0 -1909
- data/spec/fixtures/dmn/complex_decision.dmn +0 -81
- data/spec/fixtures/dmn/invalid_structure.dmn +0 -31
- data/spec/fixtures/dmn/simple_decision.dmn +0 -40
- data/spec/issue_verification_spec.rb +0 -759
- data/spec/json_rule_evaluator_spec.rb +0 -587
- data/spec/monitoring/alert_manager_spec.rb +0 -378
- data/spec/monitoring/metrics_collector_spec.rb +0 -501
- data/spec/monitoring/monitored_agent_spec.rb +0 -225
- data/spec/monitoring/prometheus_exporter_spec.rb +0 -242
- data/spec/monitoring/storage/activerecord_adapter_spec.rb +0 -498
- data/spec/monitoring/storage/base_adapter_spec.rb +0 -61
- data/spec/monitoring/storage/memory_adapter_spec.rb +0 -247
- data/spec/performance_optimizations_spec.rb +0 -493
- data/spec/replay_edge_cases_spec.rb +0 -699
- data/spec/replay_spec.rb +0 -210
- data/spec/rfc8785_canonicalization_spec.rb +0 -215
- data/spec/scoring_spec.rb +0 -225
- data/spec/spec_helper.rb +0 -60
- data/spec/testing/batch_test_importer_spec.rb +0 -693
- data/spec/testing/batch_test_runner_spec.rb +0 -307
- data/spec/testing/test_coverage_analyzer_spec.rb +0 -292
- data/spec/testing/test_result_comparator_spec.rb +0 -392
- data/spec/testing/test_scenario_spec.rb +0 -113
- data/spec/thread_safety_spec.rb +0 -490
- data/spec/thread_safety_spec.rb.broken +0 -878
- data/spec/versioning/adapter_spec.rb +0 -156
- data/spec/versioning_spec.rb +0 -1030
- data/spec/web/middleware/auth_middleware_spec.rb +0 -133
- data/spec/web/middleware/permission_middleware_spec.rb +0 -247
- data/spec/web_ui_rack_spec.rb +0 -2134
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe DecisionAgent::Auth::RbacConfig do
|
|
4
|
-
let(:config) { described_class.new }
|
|
5
|
-
|
|
6
|
-
describe "#initialize" do
|
|
7
|
-
it "initializes with nil adapter, authenticator, and user_store" do
|
|
8
|
-
expect(config.instance_variable_get(:@adapter)).to be_nil
|
|
9
|
-
expect(config.authenticator).to be_nil
|
|
10
|
-
expect(config.user_store).to be_nil
|
|
11
|
-
end
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
describe "#use" do
|
|
15
|
-
it "configures default adapter" do
|
|
16
|
-
config.use(:default)
|
|
17
|
-
expect(config.adapter).to be_a(DecisionAgent::Auth::DefaultAdapter)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
it "configures devise_cancan adapter" do
|
|
21
|
-
config.use(:devise_cancan)
|
|
22
|
-
expect(config.adapter).to be_a(DecisionAgent::Auth::DeviseCanCanAdapter)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "configures pundit adapter" do
|
|
26
|
-
config.use(:pundit)
|
|
27
|
-
expect(config.adapter).to be_a(DecisionAgent::Auth::PunditAdapter)
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
it "configures custom adapter" do
|
|
31
|
-
config.use(:custom)
|
|
32
|
-
expect(config.adapter).to be_a(DecisionAgent::Auth::CustomAdapter)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
it "raises error for unknown adapter type" do
|
|
36
|
-
expect do
|
|
37
|
-
config.use(:unknown)
|
|
38
|
-
end.to raise_error(ArgumentError, /Unknown adapter type/)
|
|
39
|
-
end
|
|
40
|
-
|
|
41
|
-
it "returns self for chaining" do
|
|
42
|
-
result = config.use(:default)
|
|
43
|
-
expect(result).to eq(config)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
describe "#adapter=" do
|
|
48
|
-
it "sets custom adapter instance" do
|
|
49
|
-
custom_adapter = DecisionAgent::Auth::DefaultAdapter.new
|
|
50
|
-
config.adapter = custom_adapter
|
|
51
|
-
expect(config.adapter).to eq(custom_adapter)
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it "raises error for non-RbacAdapter instance" do
|
|
55
|
-
expect do
|
|
56
|
-
config.adapter = "not an adapter"
|
|
57
|
-
end.to raise_error(ArgumentError, /must be an instance of DecisionAgent::Auth::RbacAdapter/)
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
describe "#adapter" do
|
|
62
|
-
it "returns configured adapter" do
|
|
63
|
-
config.use(:default)
|
|
64
|
-
expect(config.adapter).to be_a(DecisionAgent::Auth::DefaultAdapter)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
it "returns default adapter if none configured" do
|
|
68
|
-
expect(config.adapter).to be_a(DecisionAgent::Auth::DefaultAdapter)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
|
|
72
|
-
describe "#configured?" do
|
|
73
|
-
it "returns false when no adapter configured" do
|
|
74
|
-
expect(config.configured?).to be false
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
it "returns true when adapter configured" do
|
|
78
|
-
config.use(:default)
|
|
79
|
-
expect(config.configured?).to be true
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
data/spec/auth/role_spec.rb
DELETED
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe DecisionAgent::Auth::Role do
|
|
4
|
-
describe ".all" do
|
|
5
|
-
it "returns all role symbols" do
|
|
6
|
-
roles = DecisionAgent::Auth::Role.all
|
|
7
|
-
expect(roles).to include(:admin, :editor, :viewer, :auditor, :approver)
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
describe ".exists?" do
|
|
12
|
-
it "returns true for valid roles" do
|
|
13
|
-
expect(DecisionAgent::Auth::Role.exists?(:admin)).to be true
|
|
14
|
-
expect(DecisionAgent::Auth::Role.exists?(:editor)).to be true
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it "returns false for invalid roles" do
|
|
18
|
-
expect(DecisionAgent::Auth::Role.exists?(:invalid)).to be false
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
describe ".permissions_for" do
|
|
23
|
-
it "returns permissions for admin role" do
|
|
24
|
-
permissions = DecisionAgent::Auth::Role.permissions_for(:admin)
|
|
25
|
-
expect(permissions).to include(:read, :write, :delete, :approve, :deploy, :manage_users, :audit)
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
it "returns permissions for editor role" do
|
|
29
|
-
permissions = DecisionAgent::Auth::Role.permissions_for(:editor)
|
|
30
|
-
expect(permissions).to include(:read, :write)
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
it "returns permissions for viewer role" do
|
|
34
|
-
permissions = DecisionAgent::Auth::Role.permissions_for(:viewer)
|
|
35
|
-
expect(permissions).to include(:read)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it "returns empty array for invalid role" do
|
|
39
|
-
permissions = DecisionAgent::Auth::Role.permissions_for(:invalid)
|
|
40
|
-
expect(permissions).to eq([])
|
|
41
|
-
end
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
describe ".has_permission?" do
|
|
45
|
-
it "returns true if role has permission" do
|
|
46
|
-
expect(DecisionAgent::Auth::Role.has_permission?(:admin, :write)).to be true
|
|
47
|
-
expect(DecisionAgent::Auth::Role.has_permission?(:editor, :write)).to be true
|
|
48
|
-
expect(DecisionAgent::Auth::Role.has_permission?(:viewer, :write)).to be false
|
|
49
|
-
end
|
|
50
|
-
end
|
|
51
|
-
end
|
|
@@ -1,172 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe DecisionAgent::Auth::SessionManager do
|
|
4
|
-
let(:manager) { DecisionAgent::Auth::SessionManager.new }
|
|
5
|
-
|
|
6
|
-
describe "#initialize" do
|
|
7
|
-
it "initializes with empty sessions" do
|
|
8
|
-
expect(manager.count).to eq(0)
|
|
9
|
-
end
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
describe "#create_session" do
|
|
13
|
-
it "creates a new session" do
|
|
14
|
-
session = manager.create_session("user123")
|
|
15
|
-
expect(session).to be_a(DecisionAgent::Auth::Session)
|
|
16
|
-
expect(session.user_id).to eq("user123")
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
it "stores the session" do
|
|
20
|
-
session = manager.create_session("user123")
|
|
21
|
-
retrieved = manager.get_session(session.token)
|
|
22
|
-
expect(retrieved).to eq(session)
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
it "accepts custom expiration time" do
|
|
26
|
-
session = manager.create_session("user123", expires_in: 7200)
|
|
27
|
-
expect(session.expires_at).to be > Time.now.utc + 7100
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
describe "#get_session" do
|
|
32
|
-
it "returns session for valid token" do
|
|
33
|
-
session = manager.create_session("user123")
|
|
34
|
-
retrieved = manager.get_session(session.token)
|
|
35
|
-
expect(retrieved).to eq(session)
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
it "returns nil for invalid token" do
|
|
39
|
-
expect(manager.get_session("invalid_token")).to be_nil
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
it "returns nil for expired session" do
|
|
43
|
-
session = manager.create_session("user123", expires_in: -1)
|
|
44
|
-
expect(manager.get_session(session.token)).to be_nil
|
|
45
|
-
end
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
describe "#delete_session" do
|
|
49
|
-
it "deletes a session" do
|
|
50
|
-
session = manager.create_session("user123")
|
|
51
|
-
manager.delete_session(session.token)
|
|
52
|
-
expect(manager.get_session(session.token)).to be_nil
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it "does not raise error for non-existent session" do
|
|
56
|
-
expect { manager.delete_session("nonexistent") }.not_to raise_error
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
describe "#delete_user_sessions" do
|
|
61
|
-
it "deletes all sessions for a user" do
|
|
62
|
-
session1 = manager.create_session("user123")
|
|
63
|
-
session2 = manager.create_session("user123")
|
|
64
|
-
session3 = manager.create_session("user456")
|
|
65
|
-
|
|
66
|
-
manager.delete_user_sessions("user123")
|
|
67
|
-
|
|
68
|
-
expect(manager.get_session(session1.token)).to be_nil
|
|
69
|
-
expect(manager.get_session(session2.token)).to be_nil
|
|
70
|
-
expect(manager.get_session(session3.token)).to eq(session3) # Other user's session still exists
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "does not raise error for user with no sessions" do
|
|
74
|
-
expect { manager.delete_user_sessions("nonexistent") }.not_to raise_error
|
|
75
|
-
end
|
|
76
|
-
end
|
|
77
|
-
|
|
78
|
-
describe "#cleanup_expired_sessions" do
|
|
79
|
-
it "removes expired sessions" do
|
|
80
|
-
# Create expired session
|
|
81
|
-
expired_session = manager.create_session("user123", expires_in: -1)
|
|
82
|
-
# Create valid session
|
|
83
|
-
valid_session = manager.create_session("user456", expires_in: 3600)
|
|
84
|
-
|
|
85
|
-
expect(manager.count).to eq(2)
|
|
86
|
-
|
|
87
|
-
# Force cleanup by setting last_cleanup far in the past and creating another session
|
|
88
|
-
manager.instance_variable_set(:@last_cleanup, Time.now - 400) # More than 300 seconds
|
|
89
|
-
manager.create_session("user789", expires_in: 3600)
|
|
90
|
-
|
|
91
|
-
# Expired session should be cleaned up
|
|
92
|
-
expect(manager.get_session(expired_session.token)).to be_nil
|
|
93
|
-
expect(manager.get_session(valid_session.token)).to eq(valid_session)
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
it "only runs cleanup after cleanup_interval" do
|
|
97
|
-
manager = DecisionAgent::Auth::SessionManager.new
|
|
98
|
-
|
|
99
|
-
# Create an expired session
|
|
100
|
-
expired_session = manager.create_session("user123", expires_in: -1)
|
|
101
|
-
expect(manager.count).to eq(1)
|
|
102
|
-
|
|
103
|
-
# The cleanup_expired_sessions is called during create_session, but it checks the interval
|
|
104
|
-
# Let's test by manually setting last_cleanup to far in the past
|
|
105
|
-
manager.instance_variable_set(:@last_cleanup, Time.now - 400) # More than 300 seconds
|
|
106
|
-
manager.create_session("user456", expires_in: 3600)
|
|
107
|
-
|
|
108
|
-
# The expired session should be cleaned up now
|
|
109
|
-
expect(manager.get_session(expired_session.token)).to be_nil
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
describe "#count" do
|
|
114
|
-
it "returns zero initially" do
|
|
115
|
-
expect(manager.count).to eq(0)
|
|
116
|
-
end
|
|
117
|
-
|
|
118
|
-
it "returns correct count after creating sessions" do
|
|
119
|
-
manager.create_session("user123")
|
|
120
|
-
expect(manager.count).to eq(1)
|
|
121
|
-
|
|
122
|
-
manager.create_session("user123")
|
|
123
|
-
expect(manager.count).to eq(2)
|
|
124
|
-
|
|
125
|
-
manager.create_session("user456")
|
|
126
|
-
expect(manager.count).to eq(3)
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
it "reflects deletions" do
|
|
130
|
-
session1 = manager.create_session("user123")
|
|
131
|
-
manager.create_session("user123")
|
|
132
|
-
expect(manager.count).to eq(2)
|
|
133
|
-
|
|
134
|
-
manager.delete_session(session1.token)
|
|
135
|
-
expect(manager.count).to eq(1)
|
|
136
|
-
|
|
137
|
-
manager.delete_user_sessions("user123")
|
|
138
|
-
expect(manager.count).to eq(0)
|
|
139
|
-
end
|
|
140
|
-
|
|
141
|
-
it "does not count expired sessions" do
|
|
142
|
-
manager.create_session("user123", expires_in: -1)
|
|
143
|
-
# Expired sessions are not counted when retrieved, but are still in storage until cleanup
|
|
144
|
-
# So count will include them until cleanup runs
|
|
145
|
-
expect(manager.count).to eq(1)
|
|
146
|
-
|
|
147
|
-
# After cleanup
|
|
148
|
-
manager.instance_variable_set(:@last_cleanup, Time.now - 400)
|
|
149
|
-
manager.create_session("user456", expires_in: 3600)
|
|
150
|
-
# Now expired session should be cleaned up
|
|
151
|
-
expect(manager.count).to eq(1)
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
|
|
155
|
-
describe "thread safety" do
|
|
156
|
-
it "handles concurrent access safely" do
|
|
157
|
-
threads = []
|
|
158
|
-
10.times do
|
|
159
|
-
threads << Thread.new do
|
|
160
|
-
10.times do
|
|
161
|
-
session = manager.create_session("user#{rand(100)}")
|
|
162
|
-
manager.get_session(session.token)
|
|
163
|
-
manager.count
|
|
164
|
-
end
|
|
165
|
-
end
|
|
166
|
-
end
|
|
167
|
-
|
|
168
|
-
threads.each(&:join)
|
|
169
|
-
expect(manager.count).to eq(100)
|
|
170
|
-
end
|
|
171
|
-
end
|
|
172
|
-
end
|
data/spec/auth/session_spec.rb
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe DecisionAgent::Auth::Session do
|
|
4
|
-
describe "#initialize" do
|
|
5
|
-
it "creates a session with user_id" do
|
|
6
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123")
|
|
7
|
-
expect(session.user_id).to eq("user123")
|
|
8
|
-
expect(session.token).to be_a(String)
|
|
9
|
-
expect(session.token.length).to eq(64) # 32 bytes hex = 64 chars
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
it "sets expiration time" do
|
|
13
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: 1800)
|
|
14
|
-
expect(session.expires_at).to be > Time.now.utc
|
|
15
|
-
expect(session.expires_at).to be <= Time.now.utc + 1801
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
it "uses default expiration of 3600 seconds" do
|
|
19
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123")
|
|
20
|
-
expected_expiry = session.created_at + 3600
|
|
21
|
-
expect(session.expires_at).to be_within(1).of(expected_expiry)
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
describe "#expired?" do
|
|
26
|
-
it "returns false for valid session" do
|
|
27
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: 3600)
|
|
28
|
-
expect(session.expired?).to be false
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
it "returns true for expired session" do
|
|
32
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: -1)
|
|
33
|
-
expect(session.expired?).to be true
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
describe "#valid?" do
|
|
38
|
-
it "returns true for non-expired session" do
|
|
39
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: 3600)
|
|
40
|
-
expect(session.valid?).to be true
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
it "returns false for expired session" do
|
|
44
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: -1)
|
|
45
|
-
expect(session.valid?).to be false
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
it "returns false when expired? returns true" do
|
|
49
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: -1)
|
|
50
|
-
expect(session.expired?).to be true
|
|
51
|
-
expect(session.valid?).to be false
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
it "returns true when expired? returns false" do
|
|
55
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: 3600)
|
|
56
|
-
expect(session.expired?).to be false
|
|
57
|
-
expect(session.valid?).to be true
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
describe "#to_h" do
|
|
62
|
-
it "returns hash with all session attributes" do
|
|
63
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: 3600)
|
|
64
|
-
hash = session.to_h
|
|
65
|
-
|
|
66
|
-
expect(hash).to be_a(Hash)
|
|
67
|
-
expect(hash[:token]).to eq(session.token)
|
|
68
|
-
expect(hash[:user_id]).to eq("user123")
|
|
69
|
-
expect(hash[:created_at]).to be_a(String)
|
|
70
|
-
expect(hash[:expires_at]).to be_a(String)
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
it "serializes timestamps as ISO8601 strings" do
|
|
74
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123")
|
|
75
|
-
hash = session.to_h
|
|
76
|
-
|
|
77
|
-
expect { Time.iso8601(hash[:created_at]) }.not_to raise_error
|
|
78
|
-
expect { Time.iso8601(hash[:expires_at]) }.not_to raise_error
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
it "includes correct user_id" do
|
|
82
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user456")
|
|
83
|
-
hash = session.to_h
|
|
84
|
-
expect(hash[:user_id]).to eq("user456")
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
it "includes correct token" do
|
|
88
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123")
|
|
89
|
-
hash = session.to_h
|
|
90
|
-
expect(hash[:token]).to eq(session.token)
|
|
91
|
-
end
|
|
92
|
-
end
|
|
93
|
-
|
|
94
|
-
describe "#created_at" do
|
|
95
|
-
it "is set to current UTC time" do
|
|
96
|
-
before = Time.now.utc
|
|
97
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123")
|
|
98
|
-
after = Time.now.utc
|
|
99
|
-
|
|
100
|
-
expect(session.created_at).to be >= before
|
|
101
|
-
expect(session.created_at).to be <= after
|
|
102
|
-
end
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
describe "#expires_at" do
|
|
106
|
-
it "is set based on expires_in parameter" do
|
|
107
|
-
session = DecisionAgent::Auth::Session.new(user_id: "user123", expires_in: 7200)
|
|
108
|
-
expected = session.created_at + 7200
|
|
109
|
-
expect(session.expires_at).to be_within(1).of(expected)
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
data/spec/auth/user_spec.rb
DELETED
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
require "spec_helper"
|
|
2
|
-
|
|
3
|
-
RSpec.describe DecisionAgent::Auth::User do
|
|
4
|
-
describe "#initialize" do
|
|
5
|
-
it "creates a user with email and password" do
|
|
6
|
-
user = DecisionAgent::Auth::User.new(
|
|
7
|
-
email: "test@example.com",
|
|
8
|
-
password: "password123"
|
|
9
|
-
)
|
|
10
|
-
|
|
11
|
-
expect(user.email).to eq("test@example.com")
|
|
12
|
-
expect(user.id).to be_a(String)
|
|
13
|
-
expect(user.active).to be true
|
|
14
|
-
expect(user.roles).to eq([])
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
it "creates a user with roles" do
|
|
18
|
-
user = DecisionAgent::Auth::User.new(
|
|
19
|
-
email: "admin@example.com",
|
|
20
|
-
password: "password123",
|
|
21
|
-
roles: %i[admin editor]
|
|
22
|
-
)
|
|
23
|
-
|
|
24
|
-
expect(user.roles).to include(:admin, :editor)
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
it "raises error if neither password nor password_hash provided" do
|
|
28
|
-
expect do
|
|
29
|
-
DecisionAgent::Auth::User.new(email: "test@example.com")
|
|
30
|
-
end.to raise_error(ArgumentError, /password/)
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
describe "#authenticate" do
|
|
35
|
-
it "returns true for correct password" do
|
|
36
|
-
user = DecisionAgent::Auth::User.new(
|
|
37
|
-
email: "test@example.com",
|
|
38
|
-
password: "password123"
|
|
39
|
-
)
|
|
40
|
-
|
|
41
|
-
expect(user.authenticate("password123")).to be true
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it "returns false for incorrect password" do
|
|
45
|
-
user = DecisionAgent::Auth::User.new(
|
|
46
|
-
email: "test@example.com",
|
|
47
|
-
password: "password123"
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
expect(user.authenticate("wrongpassword")).to be false
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
it "returns false for inactive user" do
|
|
54
|
-
user = DecisionAgent::Auth::User.new(
|
|
55
|
-
email: "test@example.com",
|
|
56
|
-
password: "password123",
|
|
57
|
-
active: false
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
expect(user.authenticate("password123")).to be false
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
describe "#assign_role" do
|
|
65
|
-
it "adds a role to the user" do
|
|
66
|
-
user = DecisionAgent::Auth::User.new(
|
|
67
|
-
email: "test@example.com",
|
|
68
|
-
password: "password123"
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
user.assign_role(:editor)
|
|
72
|
-
expect(user.roles).to include(:editor)
|
|
73
|
-
end
|
|
74
|
-
|
|
75
|
-
it "does not add duplicate roles" do
|
|
76
|
-
user = DecisionAgent::Auth::User.new(
|
|
77
|
-
email: "test@example.com",
|
|
78
|
-
password: "password123"
|
|
79
|
-
)
|
|
80
|
-
|
|
81
|
-
user.assign_role(:editor)
|
|
82
|
-
user.assign_role(:editor)
|
|
83
|
-
|
|
84
|
-
expect(user.roles.count(:editor)).to eq(1)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
describe "#remove_role" do
|
|
89
|
-
it "removes a role from the user" do
|
|
90
|
-
user = DecisionAgent::Auth::User.new(
|
|
91
|
-
email: "test@example.com",
|
|
92
|
-
password: "password123",
|
|
93
|
-
roles: %i[editor viewer]
|
|
94
|
-
)
|
|
95
|
-
|
|
96
|
-
user.remove_role(:editor)
|
|
97
|
-
expect(user.roles).not_to include(:editor)
|
|
98
|
-
expect(user.roles).to include(:viewer)
|
|
99
|
-
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
describe "#has_role?" do
|
|
103
|
-
it "returns true if user has the role" do
|
|
104
|
-
user = DecisionAgent::Auth::User.new(
|
|
105
|
-
email: "test@example.com",
|
|
106
|
-
password: "password123",
|
|
107
|
-
roles: [:editor]
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
expect(user.has_role?(:editor)).to be true
|
|
111
|
-
expect(user.has_role?(:admin)).to be false
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
describe "#to_h" do
|
|
116
|
-
it "returns a hash representation of the user" do
|
|
117
|
-
user = DecisionAgent::Auth::User.new(
|
|
118
|
-
email: "test@example.com",
|
|
119
|
-
password: "password123",
|
|
120
|
-
roles: [:editor]
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
hash = user.to_h
|
|
124
|
-
expect(hash[:email]).to eq("test@example.com")
|
|
125
|
-
expect(hash[:roles]).to eq(["editor"])
|
|
126
|
-
expect(hash[:active]).to be true
|
|
127
|
-
expect(hash[:id]).to be_a(String)
|
|
128
|
-
end
|
|
129
|
-
end
|
|
130
|
-
end
|