+#!/usr/bin/env rspec
+
+require 'spec_helper'
+
+module MCollective
+ module RPC
+ describe Stats do
+ before(:each) do
+ @expected = {:discoverytime => 0,
+ :okcount => 0,
+ :blocktime => 0,
+ :failcount => 0,
+ :noresponsefrom => [],
+ :responses => 0,
+ :totaltime => 0,
+ :discovered => 0,
+ :starttime => 1300031826.0,
+ :requestid => nil,
+ :aggregate_summary => [],
+ :aggregate_failures => [],
+ :discovered_nodes => []}
+
+ @stats = Stats.new
+ end
+
+ describe "#initialize" do
+ it "should reset stats on creation" do
+ Stats.any_instance.stubs(:reset).returns(true).once
+ s = Stats.new
+ end
+ end
+
+ describe "#reset" do
+ it "should initialize data correctly" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+ s = Stats.new
+
+ @expected.keys.each do |k|
+ @expected[k].should == s.send(k)
+ end
+ end
+ end
+
+ describe "#to_hash" do
+ it "should return correct stats" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+ s = Stats.new
+
+ s.to_hash.should == @expected
+ end
+ end
+
+ describe "#[]" do
+ it "should return stat values" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+ s = Stats.new
+
+ @expected.keys.each do |k|
+ @expected[k].should == s[k]
+ end
+ end
+
+ it "should return nil for unknown values" do
+ @stats["foo"].should == nil
+ end
+ end
+
+ describe "#ok" do
+ it "should increment stats" do
+ @stats.ok
+ @stats[:okcount].should == 1
+ end
+ end
+
+ describe "#fail" do
+ it "should increment stats" do
+ @stats.fail
+ @stats.failcount.should == 1
+ end
+ end
+
+ describe "#time_discovery" do
+ it "should set start time correctly" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+
+ @stats.time_discovery(:start)
+
+ @stats.instance_variable_get("@discovery_start").should == 1300031826.0
+ end
+
+ it "should record the difference correctly" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+ @stats.time_discovery(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031827))
+ @stats.time_discovery(:end)
+
+ @stats.discoverytime.should == 1.0
+ end
+
+ it "should handle unknown actions and set discovery time to 0" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+ @stats.time_discovery(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031827))
+ @stats.time_discovery(:stop)
+
+ @stats.discoverytime.should == 0
+ end
+
+ end
+
+ describe "#client_stats=" do
+ it "should store stats correctly" do
+ data = {}
+ keys = [:noresponsefrom, :responses, :starttime, :blocktime, :totaltime, :discoverytime]
+ keys.each {|k| data[k] = k}
+
+ @stats.client_stats = data
+
+ keys.each do |k|
+ @stats[k].should == data[k]
+ end
+ end
+
+ it "should not store discovery time if it was already stored" do
+ data = {}
+ keys = [:noresponsefrom, :responses, :starttime, :blocktime, :totaltime, :discoverytime]
+ keys.each {|k| data[k] = k}
+
+ Time.stubs(:now).returns(Time.at(1300031826))
+ @stats.time_discovery(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031827))
+ @stats.time_discovery(:end)
+
+ dtime = @stats.discoverytime
+
+ @stats.client_stats = data
+
+ @stats.discoverytime.should == dtime
+ end
+ end
+
+ describe "#time_block_execution" do
+ it "should set start time correctly" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+
+ @stats.time_block_execution(:start)
+
+ @stats.instance_variable_get("@block_start").should == 1300031826.0
+ end
+
+ it "should record the difference correctly" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+ @stats.time_block_execution(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031827))
+ @stats.time_block_execution(:end)
+
+ @stats.blocktime.should == 1
+ end
+
+ it "should handle unknown actions and set discovery time to 0" do
+ Time.stubs(:now).returns(Time.at(1300031826))
+ @stats.time_block_execution(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031827))
+ @stats.time_block_execution(:stop)
+
+ @stats.blocktime.should == 0
+ end
+ end
+
+ describe "#discovered_agents" do
+ it "should set discovered_nodes" do
+ nodes = ["one", "two"]
+ @stats.discovered_agents(nodes)
+ @stats.discovered_nodes.should == nodes
+ end
+
+ it "should set discovered count" do
+ nodes = ["one", "two"]
+ @stats.discovered_agents(nodes)
+ @stats.discovered.should == 2
+ end
+ end
+
+ describe "#finish_request" do
+ it "should calculate totaltime correctly" do
+ Time.stubs(:now).returns(Time.at(1300031824))
+ @stats.time_discovery(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031825))
+ @stats.time_discovery(:end)
+
+ Time.stubs(:now).returns(Time.at(1300031826))
+ @stats.time_block_execution(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031827))
+ @stats.time_block_execution(:end)
+
+ @stats.discovered_agents(["one", "two", "three"])
+ @stats.node_responded("one")
+ @stats.node_responded("two")
+
+ @stats.finish_request
+
+ @stats.totaltime.should == 2
+ end
+
+ it "should calculate no responses correctly" do
+ Time.stubs(:now).returns(Time.at(1300031824))
+ @stats.time_discovery(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031825))
+ @stats.time_discovery(:end)
+
+ Time.stubs(:now).returns(Time.at(1300031826))
+ @stats.time_block_execution(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031827))
+ @stats.time_block_execution(:end)
+
+ @stats.discovered_agents(["one", "two", "three"])
+ @stats.node_responded("one")
+ @stats.node_responded("two")
+
+ @stats.finish_request
+
+ @stats.noresponsefrom.should == ["three"]
+ end
+
+ it "should recover from failure correctly" do
+ Time.stubs(:now).returns(Time.at(1300031824))
+ @stats.time_discovery(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031825))
+ @stats.time_discovery(:end)
+
+ Time.stubs(:now).returns(Time.at(1300031826))
+ @stats.time_block_execution(:start)
+
+ Time.stubs(:now).returns(Time.at(1300031827))
+ @stats.time_block_execution(:end)
+
+ # cause the .each to raise an exception
+ @stats.instance_variable_set("@responsesfrom", nil)
+ @stats.finish_request
+
+ @stats.noresponsefrom.should == []
+ @stats.totaltime.should == 0
+ end
+ end
+
+ describe "#node_responded" do
+ it "should append to the list of nodes" do
+ @stats.node_responded "foo"
+ @stats.responsesfrom.should == ["foo"]
+ end
+
+ it "should create a new array if adding fails" do
+ # cause the << to fail
+ @stats.instance_variable_set("@responsesfrom", nil)
+
+ @stats.node_responded "foo"
+ @stats.responsesfrom.should == ["foo"]
+ end
+ end
+
+ describe "#no_response_report" do
+ it "should create an empty report if all nodes responded" do
+ @stats.discovered_agents ["foo"]
+ @stats.node_responded "foo"
+ @stats.finish_request
+
+ @stats.no_response_report.should == ""
+ end
+
+ it "should list all nodes that did not respond" do
+ @stats.discovered_agents ["foo", "bar"]
+ @stats.finish_request
+
+ @stats.no_response_report.should match(Regexp.new(/No response from.+bar\s+foo/m))
+ end
+ end
+
+ describe "#text_for_aggregates" do
+ let(:aggregate){mock()}
+
+ before :each do
+ aggregate.stubs(:result).returns({:output => "success"})
+ aggregate.stubs(:action).returns("action")
+ end
+
+ it "should create the correct output text for aggregate functions" do
+ @stats.aggregate_summary = [aggregate]
+ aggregate.stubs(:is_a?).returns(true)
+ @stats.text_for_aggregates.should =~ /Summary of.*/
+ end
+
+ it "should display an error message for a failed statup hook" do
+ @stats.aggregate_failures = [{:name => "rspec", :type => :startup}]
+ @stats.text_for_aggregates.should =~ /exception raised while processing startup hook/
+ end
+
+ it "should display an error message for an unspecified output" do
+ @stats.aggregate_failures = [{:name => "rspec", :type => :create}]
+ @stats.text_for_aggregates.should =~ /unspecified output 'rspec' for the action/
+ end
+
+ it "should display an error message for a failed process_result" do
+ @stats.aggregate_failures = [{:name => "rspec", :type => :process_result}]
+ @stats.text_for_aggregates.should =~ /exception raised while processing result data/
+ end
+
+ it "should display an error message for a failed summarize" do
+ @stats.aggregate_failures = [{:name => "rspec", :type => :summarize}]
+ @stats.text_for_aggregates.should =~ /exception raised while summarizing/
+ end
+ end
+ end
+ end
+end