class ChaosDetector::Navigator
Constants
- DEFAULT_GROUP
- FRAME_ACTIONS
- REGEX_MODULE_UNDECORATE
Attributes
domain_hash[R]
edges[R]
mod_edges[R]
mod_nodes[R]
nodes[R]
options[R]
walkman[R]
Public Class Methods
new(options:)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 31 def initialize(options:) raise ArgumentError, '#initialize requires options' if options.nil? @options = options apply_options end
Public Instance Methods
playback(row_range: nil)
click to toggle source
Playback of walkman CSV file:
# File lib/chaos_detector/navigator.rb, line 39 def playback(row_range: nil) log('Chaos playing through navigator. Total lines: ', object: @walkman.count) @nodes = Set.new @edges_call = Set.new @edges_ret = Set.new @mod_nodes = Set.new @mod_edges = Set.new @err_nodes = Set.new @walkman.playback(row_range: row_range) do |_rownum, frame| perform_node_action(frame) end # log('Found nodes.', object: @nodes.length) @walkman.playback(row_range: row_range) do |_rownum, frame| if [:call, :return].include?(frame.event) perform_edge_action(frame) else perform_mod_edge_action(frame) end end edges = merge_edges.to_a # log('Found edges.', object: edges.length) @mod_graph = ChaosDetector::GraphTheory::Graph.new( root_node: ChaosDetector::ChaosGraphs::ModuleNode.root_node(force_new: true), nodes: @mod_nodes.to_a, edges: @mod_edges.to_a ) @fn_graph = ChaosDetector::GraphTheory::Graph.new( root_node: ChaosDetector::ChaosGraphs::FunctionNode.root_node(force_new: true), nodes: @nodes.to_a, edges: edges ) [@fn_graph, @mod_graph] end
Private Instance Methods
apply_options()
click to toggle source
# File lib/chaos_detector/navigator.rb, line 82 def apply_options @walkman = ChaosDetector::Walkman.new(options: @options) @domain_hash = {} # @options.path_domain_hash && options.path_domain_hash.each do |path, group| # dpath = Pathname.new(path.to_s).cleanpath.to_s # @domain_hash[dpath] = group # end end
domain_from_path(local_path:)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 228 def domain_from_path(local_path:) key = domain_hash.keys.find { |k| local_path.start_with?(k) } key ? domain_hash[key] : ChaosDetector::GraphTheory::Node::ROOT_NODE_NAME end
edge_for_nodes(src_node, dep_node, edges:, edge_type: :dependent)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 172 def edge_for_nodes(src_node, dep_node, edges:, edge_type: :dependent) edge = edges.find do |e| e.src_node == src_node && e.dep_node == dep_node end if edge.nil? edge = ChaosDetector::GraphTheory::Edge.new(src_node, dep_node, edge_type: edge_type) edges << edge end edge end
fn_node_for(fn_info)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 116 def fn_node_for(fn_info) return nil unless fn_info&.fn_name @nodes.find do |n| n.fn_name == fn_info.fn_name && n.fn_path == fn_info.fn_path end end
fn_node_for_frame(frame)
click to toggle source
@return Node matching given frame or create a new one.
# File lib/chaos_detector/navigator.rb, line 135 def fn_node_for_frame(frame) # log("Calling fn_node_for_frame", object: frame) node = fn_node_for(frame.fn_info) if node.nil? && frame.event == :call fn_info = frame.fn_info node = ChaosDetector::ChaosGraphs::FunctionNode.new( fn_name: fn_info.fn_name, fn_path: fn_info.fn_path, fn_line: fn_info.fn_line, domain_name: options.domain_from_path(fn_info.fn_path), mod_info: frame.mod_info ) @nodes << node end node end
log(msg, **opts)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 233 def log(msg, **opts) ChaosUtils.log_msg(msg, subject: 'Navigator', **opts) end
merge_edges()
click to toggle source
We merge/reduce edges elsewhere:
# File lib/chaos_detector/navigator.rb, line 92 def merge_edges c = Set.new(@edges_call) r = Set.new(@edges_ret) raise 'Call Edges should be Set' unless c.length == @edges_call.length raise 'Ret Edges should be Set' unless r.length == @edges_ret.length raise 'Call Edges should be unique' unless @edges_call.uniq.length == @edges_call.length raise 'Call Edges should be unique' unless @edges_ret.uniq.length == @edges_ret.length # log('Unique edges in call (n/total)', object: [(c - r).length, c.length]) # log('Unique edges in return (n/total)', object: [(r - c).length, r.length]) # @edges_call.each do |e| # log("edges_call", object: e) # end # @edges_ret.each do |e| # log("edges_ret ", object: e) # end c.union(r) end
mod_node_for(mod_info)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 125 def mod_node_for(mod_info) return nil unless mod_info&.mod_name @mod_nodes.find do |n| n.mod_name == mod_info.mod_name && n.mod_path == mod_info.mod_path end end
mod_node_from_info(mod_info)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 154 def mod_node_from_info(mod_info) # log("Calling fn_node_for_frame", object: frame) node = mod_node_for(mod_info) if node.nil? #&& frame.event == :call node = ChaosDetector::ChaosGraphs::ModuleNode.new( mod_name: mod_info.mod_name, mod_path: mod_info.mod_path, mod_type: mod_info.mod_type, domain_name: options.domain_from_path(mod_info.mod_path) ) @mod_nodes << node end node end
perform_edge_action(frame)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 195 def perform_edge_action(frame) return unless frame.fn_info && frame.event==:call #&& frame.caller_info dest_node = fn_node_for(frame.fn_info) if dest_node.nil? # unless @err_nodes.include?(dest_node) # log "Couldn't find destination node (of #{@nodes.length} / #{@edges_call.length}) on #{frame}" # @err_nodes << dest_node # end return end caller_node = fn_node_for(frame.caller_info) if caller_node.nil? caller_node = ChaosDetector::ChaosGraphs::FunctionNode.root_node raise 'Caller node is required (falls back to root).' if caller_node.nil? # log("Adding edge to root!") @nodes << caller_node end edges = frame.event == :return ? @edges_ret : @edges_call edge_for_nodes(caller_node, dest_node, edges: edges) end
perform_mod_edge_action(frame)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 220 def perform_mod_edge_action(frame) return unless frame.mod_info && frame.caller_info caller_node = mod_node_from_info(frame.caller_info) dest_node = mod_node_from_info(frame.mod_info) edge_for_nodes(dest_node, caller_node, edges: @mod_edges, edge_type: frame.event) end
perform_node_action(frame)
click to toggle source
# File lib/chaos_detector/navigator.rb, line 183 def perform_node_action(frame) return unless [:call, :return].include?(frame.event) node = fn_node_for_frame(frame) ChaosUtils.with(node && frame.event == :return && frame.fn_info.fn_line) do |fn_line| if !node.fn_line_end.nil? && node.fn_line_end != fn_line end node.fn_line_end = [fn_line, node.fn_line_end.to_i].max end end