chaos_detector 0.4.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|