chaos_detector 0.4.9
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 +7 -0
- data/bin/detect_chaos +31 -0
- data/lib/chaos_detector.rb +22 -0
- data/lib/chaos_detector/chaos_graphs/chaos_edge.rb +32 -0
- data/lib/chaos_detector/chaos_graphs/chaos_graph.rb +389 -0
- data/lib/chaos_detector/chaos_graphs/domain_metrics.rb +19 -0
- data/lib/chaos_detector/chaos_graphs/domain_node.rb +57 -0
- data/lib/chaos_detector/chaos_graphs/function_node.rb +112 -0
- data/lib/chaos_detector/chaos_graphs/module_node.rb +86 -0
- data/lib/chaos_detector/chaos_utils.rb +57 -0
- data/lib/chaos_detector/graph_theory/appraiser.rb +162 -0
- data/lib/chaos_detector/graph_theory/edge.rb +76 -0
- data/lib/chaos_detector/graph_theory/graph.rb +144 -0
- data/lib/chaos_detector/graph_theory/loop_detector.rb +32 -0
- data/lib/chaos_detector/graph_theory/node.rb +70 -0
- data/lib/chaos_detector/graph_theory/node_metrics.rb +68 -0
- data/lib/chaos_detector/graph_theory/reduction.rb +40 -0
- data/lib/chaos_detector/graphing/directed_graphs.rb +396 -0
- data/lib/chaos_detector/graphing/graphs.rb +129 -0
- data/lib/chaos_detector/graphing/matrix_graphs.rb +101 -0
- data/lib/chaos_detector/navigator.rb +237 -0
- data/lib/chaos_detector/options.rb +51 -0
- data/lib/chaos_detector/stacker/comp_info.rb +42 -0
- data/lib/chaos_detector/stacker/fn_info.rb +44 -0
- data/lib/chaos_detector/stacker/frame.rb +34 -0
- data/lib/chaos_detector/stacker/frame_stack.rb +63 -0
- data/lib/chaos_detector/stacker/mod_info.rb +24 -0
- data/lib/chaos_detector/tracker.rb +276 -0
- data/lib/chaos_detector/utils/core_util.rb +117 -0
- data/lib/chaos_detector/utils/fs_util.rb +49 -0
- data/lib/chaos_detector/utils/lerp_util.rb +20 -0
- data/lib/chaos_detector/utils/log_util.rb +45 -0
- data/lib/chaos_detector/utils/str_util.rb +90 -0
- data/lib/chaos_detector/utils/tensor_util.rb +21 -0
- data/lib/chaos_detector/walkman.rb +214 -0
- metadata +147 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 560bb0eb60cbfb4a982c2189aba4a952eda085864e134dd328f98a0e3e4c80ee
|
4
|
+
data.tar.gz: 31042b5f09a591c43bdcfbafb984a216feafa989dcc9c7355e1c7d00d00aed8a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e5b1e511011a833c3ce5ca72c59ea2dd38dd029197667a7ba8b1af024d4e681fc9ecf78ebf242ad8671f7d45f7063fa4193eec5dea587a3026d48fb8c84d209f
|
7
|
+
data.tar.gz: 35ea321082b59f7efeb717bf878168be956da718814984c9ecff1117f34e4c8bb125fb3dca02c8c37601fc6cc2012676ea9373c978ed220d624d41d2b530b106
|
data/bin/detect_chaos
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
require 'chaos_detector/navigator'
|
5
|
+
require 'chaos_detector/options'
|
6
|
+
require 'chaos_detector/chaos_utils'
|
7
|
+
|
8
|
+
module ChaosDetector
|
9
|
+
class DetectChaos < Thor
|
10
|
+
package_name 'DetectChaos'
|
11
|
+
desc 'playback', 'Loads dependencies saved by a previous test run'
|
12
|
+
opts = ChaosDetector::Options.new
|
13
|
+
method_option :opt_frame_csv, type: :string, default: opts.path_with_root(key: :frame_csv_path), required: true
|
14
|
+
method_option :opt_app_root, type: :string, default: opts.app_root_path, required: true
|
15
|
+
method_option :opt_module_filter, type: :string, default: 'ChaosDetector', required: true
|
16
|
+
# default_task :playback
|
17
|
+
|
18
|
+
def playback
|
19
|
+
ARGV.clear
|
20
|
+
opts = ChaosDetector::Options.new
|
21
|
+
chaos_nav = ChaosDetector::Navigator.new(options: opts)
|
22
|
+
ChaosUtils.log_msg("ChaosDetector::Navigator.playback with options: #{options}")
|
23
|
+
opts.frame_csv_path = options[:opt_frame_csv] # .sub(options[:opt_app_root], "")
|
24
|
+
opts.app_root_path = options[:opt_app_root]
|
25
|
+
opts.module_filter = options[:opt_module_filter]
|
26
|
+
chaos_nav.playback
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
ChaosDetector::DetectChaos.start(ARGV)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'chaos_detector/navigator'
|
2
|
+
require 'chaos_detector/graphing/directed_graphs'
|
3
|
+
require 'chaos_detector/options'
|
4
|
+
|
5
|
+
# module ChaosDetector
|
6
|
+
# # class << self
|
7
|
+
# # # Add struct or class to encapsulate include/exclude rules:
|
8
|
+
# # # include_paths:, exclude_paths:, include_classes:, exclude_classes:
|
9
|
+
# # def record(options=nil)#, include_paths:, exclude_paths:, include_classes:, exclude_classes:)
|
10
|
+
|
11
|
+
# # # puts(" Domains #{domain_hash.inspect}")
|
12
|
+
# # # # options.log_root_path = app_root_path
|
13
|
+
# # # puts(" log_root_path #{options.log_root_path}")
|
14
|
+
# # ChaosDetector::Navigator.record(options: options || ChaosDetector::Options.new)
|
15
|
+
# # end
|
16
|
+
|
17
|
+
# # def stop
|
18
|
+
# # ChaosDetector::Navigator.stop
|
19
|
+
# # end
|
20
|
+
|
21
|
+
# # end
|
22
|
+
# end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'function_node'
|
2
|
+
require_relative 'domain_node'
|
3
|
+
require_relative 'module_node'
|
4
|
+
|
5
|
+
require 'chaos_detector/graph_theory/edge'
|
6
|
+
require 'chaos_detector/graph_theory/graph'
|
7
|
+
require 'chaos_detector/chaos_utils'
|
8
|
+
|
9
|
+
# Edge with dependency-tracking attributes
|
10
|
+
module ChaosDetector
|
11
|
+
module ChaosGraphs
|
12
|
+
class ChaosEdge < GraphTheory::Edge
|
13
|
+
attr_reader :dep_type
|
14
|
+
|
15
|
+
# association
|
16
|
+
DEP_TYPES = %i[association generalization aggregation composition].freeze
|
17
|
+
def initialize(src_node, dep_node, dep_type: :association, reduction: nil)
|
18
|
+
super
|
19
|
+
@dep_type = dep_type
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
m = ChaosUtils.decorate(super, clamp: :parens, suffix: ' ')
|
24
|
+
m << ChaosUtils.decorate(@dep_type, clamp: :parens)
|
25
|
+
end
|
26
|
+
|
27
|
+
def log(msg, **opts)
|
28
|
+
ChaosUtils.log_msg(msg, subject: 'ChaosEdge', **opts)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,389 @@
|
|
1
|
+
require_relative 'function_node'
|
2
|
+
require_relative 'domain_node'
|
3
|
+
require_relative 'module_node'
|
4
|
+
|
5
|
+
require 'chaos_detector/chaos_utils'
|
6
|
+
require 'chaos_detector/graph_theory/appraiser'
|
7
|
+
require 'chaos_detector/graph_theory/edge'
|
8
|
+
require 'chaos_detector/graph_theory/graph'
|
9
|
+
require 'chaos_detector/graph_theory/node'
|
10
|
+
require 'chaos_detector/graph_theory/reduction'
|
11
|
+
|
12
|
+
# Encapsulate and aggregates graphs for dependency tracking
|
13
|
+
# * Function directed graph
|
14
|
+
# * Module directed graph - derived from function graph
|
15
|
+
# * Domain directed graph - derived from function graph
|
16
|
+
module ChaosDetector
|
17
|
+
module ChaosGraphs
|
18
|
+
class ChaosGraph
|
19
|
+
NODE_TYPES = %i[function module domain].freeze
|
20
|
+
STATES = %i[initialized inferred].freeze
|
21
|
+
|
22
|
+
attr_reader :function_graph
|
23
|
+
attr_reader :mod_rel_graph
|
24
|
+
attr_reader :domain_nodes
|
25
|
+
attr_reader :module_nodes
|
26
|
+
|
27
|
+
attr_reader :domain_appraisal
|
28
|
+
attr_reader :function_appraisal
|
29
|
+
attr_reader :module_appraisal
|
30
|
+
attr_reader :domain_edges
|
31
|
+
attr_reader :module_edges
|
32
|
+
attr_reader :module_domain_edges
|
33
|
+
attr_reader :domain_module_edges
|
34
|
+
attr_reader :function_domain_edges
|
35
|
+
attr_reader :domain_function_edges
|
36
|
+
|
37
|
+
def initialize(function_graph, mod_rel_graph)
|
38
|
+
@function_graph = function_graph
|
39
|
+
@mod_rel_graph = mod_rel_graph
|
40
|
+
@domain_nodes = nil
|
41
|
+
@module_nodes = nil
|
42
|
+
|
43
|
+
@domain_edges = nil
|
44
|
+
@module_edges = nil
|
45
|
+
@module_domain_edges = nil
|
46
|
+
@domain_module_edges = nil
|
47
|
+
@function_domain_edges = nil
|
48
|
+
@domain_function_edges = nil
|
49
|
+
end
|
50
|
+
|
51
|
+
def infer_all
|
52
|
+
assert_state
|
53
|
+
infer_module_nodes
|
54
|
+
infer_domain_nodes
|
55
|
+
prepare_root_nodes
|
56
|
+
|
57
|
+
# Now infer all edges:
|
58
|
+
infer_edges
|
59
|
+
|
60
|
+
# Graph theory appraisal
|
61
|
+
appraise_all
|
62
|
+
self
|
63
|
+
# @domain_graph = build_domain_graph(@domain_edges)
|
64
|
+
# @module_graph = build_domain_graph(@module_edges)
|
65
|
+
end
|
66
|
+
|
67
|
+
# ChaosDetector::ChaosGraphs::ChaosGraph.NODE_TYPES
|
68
|
+
def derive_graph(graph_type:, sort_col: :total_couplings, include_root: true, sort: :desc, top: nil)
|
69
|
+
sortcol = sort_col || :total_couplings
|
70
|
+
graph, appraisal = graph_data_for(graph_type: graph_type)
|
71
|
+
|
72
|
+
nodes = graph.nodes(include_root: false)
|
73
|
+
# nodes.filter!{ |node| yield(node) } if block_given?
|
74
|
+
|
75
|
+
# Use appraisal metrics for sorting:
|
76
|
+
node_metrics = nodes.map{|node| appraisal.metrics_for(node: node)}
|
77
|
+
n_sort = node_metrics.map{|m| m.send(sortcol)}.map.with_index.sort.map(&:last)
|
78
|
+
n_sort.reverse! if sort == :desc
|
79
|
+
|
80
|
+
# Limit:
|
81
|
+
if top
|
82
|
+
ChaosUtils.with(top.to_i) do |t|
|
83
|
+
n_sort = n_sort.take(t) if t.positive?
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
gnodes = n_sort.map{|i| nodes[i].clone }
|
89
|
+
|
90
|
+
# gnodes = new_nodes.map(&:clone)
|
91
|
+
gedges = graph.edges.filter_map do |edge|
|
92
|
+
src_node = gnodes.find{ |node| node == edge.src_node }
|
93
|
+
dep_node = gnodes.find{ |node| node == edge.dep_node }
|
94
|
+
if src_node && dep_node
|
95
|
+
edge.dup.tap do |gedge|
|
96
|
+
gedge.src_node = src_node
|
97
|
+
gedge.dep_node = dep_node
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
ChaosDetector::GraphTheory::Graph.new(
|
103
|
+
root_node: include_root ? gnodes.find(&:is_root)&.dup : nil,
|
104
|
+
nodes: gnodes,
|
105
|
+
edges: gedges
|
106
|
+
)
|
107
|
+
end
|
108
|
+
|
109
|
+
def domain_graph
|
110
|
+
assert_state(:inferred)
|
111
|
+
@domain_graph ||= build_domain_graph(edges: @domain_edges)
|
112
|
+
end
|
113
|
+
|
114
|
+
def module_graph
|
115
|
+
assert_state(:inferred)
|
116
|
+
@module_graph ||= build_module_graph(edges: @module_edges)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Lookup domain node by name:
|
120
|
+
def domain_node_for(name:)
|
121
|
+
# domain_nodes.find(->{root_node_domain}){|node| node.name.to_s == name.to_s}
|
122
|
+
domain_nodes.find(->{root_node_domain}){|node| node.name.to_s == name.to_s}
|
123
|
+
end
|
124
|
+
|
125
|
+
## Derive domain-level graph from function-based graph
|
126
|
+
def build_domain_graph(edges: @domain_edes)
|
127
|
+
assert_state
|
128
|
+
ChaosDetector::GraphTheory::Graph.new(root_node: root_node_domain, nodes: @domain_nodes, edges: edges)
|
129
|
+
end
|
130
|
+
|
131
|
+
## Derive module-level graph from function-based graph
|
132
|
+
def build_module_graph(edges: @module_edges)
|
133
|
+
assert_state
|
134
|
+
ChaosDetector::GraphTheory::Graph.new(root_node: root_node_module, nodes: @module_nodes, edges: edges)
|
135
|
+
end
|
136
|
+
|
137
|
+
## Return [graph, appraisal] for given type:
|
138
|
+
def graph_data_for(graph_type:)
|
139
|
+
assert_state(:inferred)
|
140
|
+
|
141
|
+
case graph_type
|
142
|
+
when :function
|
143
|
+
[function_graph, function_appraisal]
|
144
|
+
when :module
|
145
|
+
[module_graph, module_appraisal]
|
146
|
+
when :domain
|
147
|
+
[domain_graph, domain_appraisal]
|
148
|
+
else
|
149
|
+
raise "graph_type should be one of #{NODE_TYPES.inspect}, actual value: #{ChaosUtils.decorate(graph_type)}"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
# Use Graph theory to appraise given graph:
|
154
|
+
def appraise_graph(graph, sort_col: :total_couplings, sort_desc: true, top: nil)
|
155
|
+
appraiser = ChaosDetector::GraphTheory::Appraiser.new(graph)
|
156
|
+
appraiser.appraise
|
157
|
+
appraiser
|
158
|
+
end
|
159
|
+
|
160
|
+
|
161
|
+
private
|
162
|
+
|
163
|
+
# Graph theory appraisal
|
164
|
+
def appraise_all
|
165
|
+
log("Appraising graphs")
|
166
|
+
@domain_appraisal = appraise_graph(domain_graph)
|
167
|
+
@module_appraisal = appraise_graph(module_graph)
|
168
|
+
@function_appraisal = appraise_graph(function_graph)
|
169
|
+
end
|
170
|
+
|
171
|
+
def assert_state(state = nil)
|
172
|
+
raise "function_graph.nodes isn't set!" unless function_graph&.nodes
|
173
|
+
|
174
|
+
if state == :inferred
|
175
|
+
raise "@domain_nodes isn't set; call #build" unless @domain_nodes
|
176
|
+
raise "@module_nodes isn't set; call #build" unless @module_nodes
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
def prepare_root_nodes
|
181
|
+
assert_state(:inferred)
|
182
|
+
ChaosUtils.with(root_node_function) do |fn_root_node|
|
183
|
+
@function_graph.nodes.unshift(fn_root_node) unless @function_graph.nodes.include?(fn_root_node)
|
184
|
+
end
|
185
|
+
|
186
|
+
ChaosUtils.with(root_node_domain) do |domain_root_node|
|
187
|
+
@domain_nodes.unshift(domain_root_node) unless @domain_nodes.include?(domain_root_node)
|
188
|
+
end
|
189
|
+
|
190
|
+
ChaosUtils.with(root_node_module) do |mod_root_node|
|
191
|
+
@module_nodes.unshift(mod_root_node) unless @module_nodes.include?(mod_root_node)
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def root_node_function
|
196
|
+
assert_state
|
197
|
+
root_node = @function_graph.nodes.find(&:is_root)
|
198
|
+
root_node || ChaosDetector::ChaosGraphs::FunctionNode.root_node
|
199
|
+
end
|
200
|
+
|
201
|
+
def root_node_domain
|
202
|
+
assert_state(:inferred)
|
203
|
+
root_node = @domain_nodes.find(&:is_root)
|
204
|
+
root_node || ChaosDetector::ChaosGraphs::DomainNode.root_node
|
205
|
+
end
|
206
|
+
|
207
|
+
def root_node_module
|
208
|
+
assert_state(:inferred)
|
209
|
+
|
210
|
+
root_node = @module_nodes.find(&:is_root)
|
211
|
+
root_node || ChaosDetector::ChaosGraphs::ModuleNode.root_node
|
212
|
+
end
|
213
|
+
|
214
|
+
def infer_module_nodes
|
215
|
+
assert_state
|
216
|
+
|
217
|
+
grouped_nodes = @function_graph.nodes.group_by(&:mod_info_prime)
|
218
|
+
|
219
|
+
# mod_nodes = grouped_nodes.select do |mod_info, _fn_nodes|
|
220
|
+
# ChaosUtils.aught?(mod_info&.mod_name)
|
221
|
+
# end
|
222
|
+
|
223
|
+
mod_nodes = grouped_nodes.filter_map do |mod_info, fn_nodes|
|
224
|
+
next unless ChaosUtils.aught?(mod_info&.mod_name)
|
225
|
+
|
226
|
+
node_fn = fn_nodes.first
|
227
|
+
|
228
|
+
fn_reductions = fn_nodes.map(&:reduction)
|
229
|
+
|
230
|
+
mod_reduction = ChaosDetector::GraphTheory::Reduction.combine_all(fn_reductions)
|
231
|
+
# puts ("mod_reduction: %s" % mod_reduction.inspect)
|
232
|
+
|
233
|
+
ChaosDetector::ChaosGraphs::ModuleNode.new(
|
234
|
+
mod_name: mod_info.mod_name,
|
235
|
+
mod_type: mod_info.mod_type,
|
236
|
+
mod_path: mod_info.mod_path,
|
237
|
+
domain_name: node_fn.domain_name,
|
238
|
+
reduction: mod_reduction
|
239
|
+
)
|
240
|
+
end
|
241
|
+
|
242
|
+
mod_nodes.uniq!
|
243
|
+
|
244
|
+
@mod_rel_graph.nodes.each do |rel_node|
|
245
|
+
n = mod_nodes.index(rel_node)
|
246
|
+
mod_nodes << rel_node if n.nil?
|
247
|
+
end
|
248
|
+
|
249
|
+
@module_nodes = mod_nodes.uniq
|
250
|
+
end
|
251
|
+
|
252
|
+
def infer_domain_nodes
|
253
|
+
assert_state
|
254
|
+
|
255
|
+
@domain_nodes = @module_nodes.group_by(&:domain_name).map do |dom_nm, mod_nodes|
|
256
|
+
mod_reductions = mod_nodes.map(&:reduction)
|
257
|
+
dom_reduction = ChaosDetector::GraphTheory::Reduction.combine_all(mod_reductions)
|
258
|
+
ChaosDetector::ChaosGraphs::DomainNode.new(
|
259
|
+
domain_name: dom_nm,
|
260
|
+
reduction: dom_reduction,
|
261
|
+
is_root: dom_nm==ChaosDetector::GraphTheory::Node::ROOT_NODE_NAME || !ChaosUtils.aught?(dom_nm)
|
262
|
+
)
|
263
|
+
end
|
264
|
+
end
|
265
|
+
|
266
|
+
def infer_edges
|
267
|
+
assert_state
|
268
|
+
|
269
|
+
fn_edges = @function_graph.edges
|
270
|
+
mod_edges = group_edges_by(fn_edges, :module, :module).concat(@mod_rel_graph.edges)
|
271
|
+
check_edges("mod_edges", mod_edges)
|
272
|
+
|
273
|
+
dom_edges = group_edges_by(mod_edges, :domain, :domain)
|
274
|
+
check_edges("dom_edges", dom_edges)
|
275
|
+
|
276
|
+
@domain_edges = reduce_edges(dom_edges)
|
277
|
+
check_edges("@domain_edges", @domain_edges)
|
278
|
+
|
279
|
+
@module_edges = reduce_edges(mod_edges)
|
280
|
+
check_edges("@module_edges", @module_edges)
|
281
|
+
end
|
282
|
+
|
283
|
+
def check_edges(name, edges)
|
284
|
+
return
|
285
|
+
edges.each do |edge|
|
286
|
+
puts("#{name} EDGE: #{edge.class} / #{edge.reduction.class} / #{edge}")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
|
290
|
+
def group_edges_by(edges, src, dep)
|
291
|
+
assert_state
|
292
|
+
raise ArgumentError, 'edges argument required' unless edges
|
293
|
+
|
294
|
+
# log("GROUPING EDGES by #{src} and #{dep}")
|
295
|
+
|
296
|
+
groupedges = edges.group_by do |e|
|
297
|
+
[
|
298
|
+
node_group_prop(e.src_node, node_type: src),
|
299
|
+
node_group_prop(e.dep_node, node_type: dep)
|
300
|
+
]
|
301
|
+
end
|
302
|
+
|
303
|
+
# valid_edges = groupedges.select do |src_dep_pair, g_edges|
|
304
|
+
# src_dep_pair.all?
|
305
|
+
# end
|
306
|
+
|
307
|
+
groupedges.filter_map do |src_dep_pair, g_edges|
|
308
|
+
raise 'Pair should have two exactly items.' unless src_dep_pair.length == 2
|
309
|
+
|
310
|
+
# log("Looking up pair: #{src_dep_pair.inspect}")
|
311
|
+
edge_src_node = lookup_node_by(node_type: src, node_info: src_dep_pair.first)
|
312
|
+
edge_dep_node = lookup_node_by(node_type: dep, node_info: src_dep_pair.last)
|
313
|
+
|
314
|
+
# log("Creating #{src_dep_pair.first.class} edge with #{ChaosUtils.decorate_pair(edge_src_node, edge_dep_node)}")
|
315
|
+
if (edge_src_node != edge_dep_node)
|
316
|
+
ChaosDetector::GraphTheory::Edge.new(
|
317
|
+
edge_src_node,
|
318
|
+
edge_dep_node,
|
319
|
+
reduction: ChaosDetector::GraphTheory::Reduction.new(
|
320
|
+
reduction_count: g_edges.count,
|
321
|
+
reduction_sum: g_edges.reduce(0) do |sum, e|
|
322
|
+
sum + (e.reduction&.reduction_count || 1)
|
323
|
+
end
|
324
|
+
)
|
325
|
+
)
|
326
|
+
end
|
327
|
+
end
|
328
|
+
end
|
329
|
+
|
330
|
+
def reduce_edges(edges)
|
331
|
+
edges.reduce(Set.new) do |memo, obj|
|
332
|
+
existing = memo.find{|m| obj==m}
|
333
|
+
if existing
|
334
|
+
existing.merge!(obj)
|
335
|
+
else
|
336
|
+
memo << obj
|
337
|
+
end
|
338
|
+
memo
|
339
|
+
end.to_a
|
340
|
+
end
|
341
|
+
|
342
|
+
def node_group_prop(node, node_type:)
|
343
|
+
unless NODE_TYPES.include? node_type
|
344
|
+
raise format('node_type should be one of symbols in %s, actual value: %s (%s)', NODE_TYPES.inspect, ChaosUtils.decorate(node_type), ChaosUtils.decorate(node_type.class))
|
345
|
+
end
|
346
|
+
|
347
|
+
case node_type
|
348
|
+
when :function
|
349
|
+
node.to_info
|
350
|
+
when :module
|
351
|
+
node.mod_info_prime
|
352
|
+
when :domain
|
353
|
+
node.domain_name
|
354
|
+
end
|
355
|
+
end
|
356
|
+
|
357
|
+
def lookup_node_by(node_type:, node_info:)
|
358
|
+
assert_state
|
359
|
+
|
360
|
+
# It is already a node:
|
361
|
+
return node_info if node_info.is_a? ChaosDetector::GraphTheory::Node
|
362
|
+
|
363
|
+
case node_type
|
364
|
+
when :function
|
365
|
+
# Look up by FnInfo
|
366
|
+
n = node_info && @function_graph.nodes.index(node_info)
|
367
|
+
n.nil? ? root_node_function : @function_graph.nodes[n]
|
368
|
+
when :module
|
369
|
+
# Look up by module info
|
370
|
+
n = node_info && @module_nodes.index(node_info)
|
371
|
+
n.nil? ? root_node_module : @module_nodes[n]
|
372
|
+
when :domain
|
373
|
+
# Look up by Domain name
|
374
|
+
unless (node_info.nil? || node_info.is_a?(String) || node_info.is_a?(Symbol))
|
375
|
+
log("NodeInfo is something other than info or string type: class: (#{node_info.class}) = #{node_info.inspect}")
|
376
|
+
end
|
377
|
+
|
378
|
+
domain_node_for(name: node_info.to_s) || root_node_domain
|
379
|
+
else
|
380
|
+
raise "node_type should be one of #{NODE_TYPES.inspect}, actual value: #{ChaosUtils.decorate(node_type)}"
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
def log(msg, **opts)
|
385
|
+
ChaosUtils.log_msg(msg, subject: 'ChaosGraph', **opts)
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|