request-log-analyzer 1.1.2 → 1.2.0

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.
Files changed (58) hide show
  1. data/DESIGN +24 -10
  2. data/README.rdoc +1 -1
  3. data/Rakefile +1 -2
  4. data/bin/request-log-analyzer +4 -27
  5. data/lib/cli/progressbar.rb +2 -19
  6. data/lib/cli/tools.rb +46 -0
  7. data/lib/request_log_analyzer/aggregator/database.rb +33 -8
  8. data/lib/request_log_analyzer/aggregator/echo.rb +1 -0
  9. data/lib/request_log_analyzer/aggregator/summarizer.rb +15 -13
  10. data/lib/request_log_analyzer/controller.rb +8 -4
  11. data/lib/request_log_analyzer/file_format/merb.rb +17 -4
  12. data/lib/request_log_analyzer/file_format/rails.rb +2 -2
  13. data/lib/request_log_analyzer/file_format/rails_development.rb +30 -92
  14. data/lib/request_log_analyzer/file_format.rb +8 -4
  15. data/lib/request_log_analyzer/filter/anonymize.rb +0 -3
  16. data/lib/request_log_analyzer/filter/field.rb +6 -1
  17. data/lib/request_log_analyzer/filter/timespan.rb +7 -1
  18. data/lib/request_log_analyzer/filter.rb +0 -4
  19. data/lib/request_log_analyzer/line_definition.rb +12 -2
  20. data/lib/request_log_analyzer/output/fixed_width.rb +14 -3
  21. data/lib/request_log_analyzer/output/html.rb +1 -0
  22. data/lib/request_log_analyzer/request.rb +6 -0
  23. data/lib/request_log_analyzer/source/database.rb +76 -0
  24. data/lib/request_log_analyzer/source/log_parser.rb +101 -48
  25. data/lib/request_log_analyzer/source.rb +28 -6
  26. data/lib/request_log_analyzer/tracker/duration.rb +90 -15
  27. data/lib/request_log_analyzer/tracker/frequency.rb +22 -10
  28. data/lib/request_log_analyzer/tracker/hourly_spread.rb +20 -9
  29. data/lib/request_log_analyzer/tracker/timespan.rb +15 -8
  30. data/lib/request_log_analyzer.rb +29 -16
  31. data/spec/integration/command_line_usage_spec.rb +71 -0
  32. data/spec/lib/helper.rb +33 -0
  33. data/spec/lib/mocks.rb +47 -0
  34. data/spec/{file_formats/spec_format.rb → lib/testing_format.rb} +6 -1
  35. data/spec/spec_helper.rb +5 -41
  36. data/spec/{database_inserter_spec.rb → unit/aggregator/database_inserter_spec.rb} +40 -37
  37. data/spec/unit/aggregator/summarizer_spec.rb +28 -0
  38. data/spec/unit/controller/controller_spec.rb +43 -0
  39. data/spec/{log_processor_spec.rb → unit/controller/log_processor_spec.rb} +4 -3
  40. data/spec/{file_format_spec.rb → unit/file_format/file_format_api_spec.rb} +16 -4
  41. data/spec/{line_definition_spec.rb → unit/file_format/line_definition_spec.rb} +13 -6
  42. data/spec/{merb_format_spec.rb → unit/file_format/merb_format_spec.rb} +2 -2
  43. data/spec/{rails_format_spec.rb → unit/file_format/rails_format_spec.rb} +19 -11
  44. data/spec/unit/filter/anonymize_filter_spec.rb +22 -0
  45. data/spec/unit/filter/field_filter_spec.rb +69 -0
  46. data/spec/unit/filter/timespan_filter_spec.rb +61 -0
  47. data/spec/{log_parser_spec.rb → unit/source/log_parser_spec.rb} +7 -7
  48. data/spec/{request_spec.rb → unit/source/request_spec.rb} +5 -5
  49. data/spec/unit/tracker/duration_tracker_spec.rb +99 -0
  50. data/spec/unit/tracker/frequency_tracker_spec.rb +83 -0
  51. data/spec/unit/tracker/hourly_spread_spec.rb +75 -0
  52. data/spec/unit/tracker/timespan_tracker_spec.rb +65 -0
  53. data/spec/unit/tracker/tracker_api_test.rb +45 -0
  54. data/tasks/rspec.rake +12 -0
  55. metadata +54 -26
  56. data/spec/controller_spec.rb +0 -64
  57. data/spec/filter_spec.rb +0 -157
  58. data/spec/summarizer_spec.rb +0 -9
@@ -21,36 +21,48 @@ module RequestLogAnalyzer::Tracker
21
21
  # DELETE | 512 hits (1.1%) |
22
22
  class Frequency < Base
23
23
 
24
- attr_reader :categories
24
+ attr_reader :frequencies
25
25
 
26
26
  def prepare
27
27
  raise "No categorizer set up for category tracker #{self.inspect}" unless options[:category]
28
- @categories = {}
28
+ @frequencies = {}
29
29
  if options[:all_categories].kind_of?(Enumerable)
30
- options[:all_categories].each { |cat| @categories[cat] = 0 }
30
+ options[:all_categories].each { |cat| @frequencies[cat] = 0 }
31
31
  end
32
32
  end
33
33
 
34
34
  def update(request)
35
35
  cat = options[:category].respond_to?(:call) ? options[:category].call(request) : request[options[:category]]
36
36
  if !cat.nil? || options[:nils]
37
- @categories[cat] ||= 0
38
- @categories[cat] += 1
37
+ @frequencies[cat] ||= 0
38
+ @frequencies[cat] += 1
39
39
  end
40
40
  end
41
41
 
42
+ def frequency(cat)
43
+ frequencies[cat] || 0
44
+ end
45
+
46
+ def overall_frequency
47
+ frequencies.inject(0) { |carry, item| carry + item[1] }
48
+ end
49
+
50
+ def sorted_by_frequency
51
+ @frequencies.sort { |a, b| b[1] <=> a[1] }
52
+ end
53
+
42
54
  def report(output)
43
55
  output.title(options[:title]) if options[:title]
44
56
 
45
- if @categories.empty?
57
+ if @frequencies.empty?
46
58
  output << "None found.\n"
47
59
  else
48
- sorted_categories = @categories.sort { |a, b| b[1] <=> a[1] }
49
- total_hits = sorted_categories.inject(0) { |carry, item| carry + item[1] }
50
- sorted_categories = sorted_categories.slice(0...options[:amount]) if options[:amount]
60
+ sorted_frequencies = @frequencies.sort { |a, b| b[1] <=> a[1] }
61
+ total_hits = sorted_frequencies.inject(0) { |carry, item| carry + item[1] }
62
+ sorted_frequencies = sorted_frequencies.slice(0...options[:amount]) if options[:amount]
51
63
 
52
64
  output.table({:align => :left}, {:align => :right }, {:align => :right}, {:type => :ratio, :width => :rest}) do |rows|
53
- sorted_categories.each do |(cat, count)|
65
+ sorted_frequencies.each do |(cat, count)|
54
66
  rows << [cat, "#{count} hits", '%0.1f%%' % ((count.to_f / total_hits.to_f) * 100.0), (count.to_f / total_hits.to_f)]
55
67
  end
56
68
  end
@@ -44,25 +44,36 @@ module RequestLogAnalyzer::Tracker
44
44
  @last = timestamp if @last.nil? || timestamp > @last
45
45
  end
46
46
 
47
+ def total_requests
48
+ @request_time_graph.inject(0) { |sum, value| sum + value }
49
+ end
50
+
51
+ def first_timestamp
52
+ DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
53
+ end
54
+
55
+ def last_timestamp
56
+ DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
57
+ end
58
+
59
+ def timespan
60
+ last_timestamp - first_timestamp
61
+ end
62
+
47
63
  def report(output)
48
64
  output.title("Requests graph - average per day per hour")
49
65
 
50
- if @request_time_graph == [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
66
+ if total_requests == 0
51
67
  output << "None found.\n"
52
68
  return
53
69
  end
54
70
 
55
- first_date = DateTime.parse(@first.to_s, '%Y%m%d%H%M%S')
56
- last_date = DateTime.parse(@last.to_s, '%Y%m%d%H%M%S')
57
- days = (@last && @first) ? (last_date - first_date).ceil : 1
58
- total_requests = @request_time_graph.inject(0) { |sum, value| sum + value }
59
-
71
+ days = [1, timespan].max
60
72
  output.table({}, {:align => :right}, {:type => :ratio, :width => :rest, :treshold => 0.15}) do |rows|
61
73
  @request_time_graph.each_with_index do |requests, index|
62
74
  ratio = requests.to_f / total_requests.to_f
63
- requests_per_day = requests / days
64
-
65
- rows << ["#{index.to_s.rjust(3)}:00", "#{requests_per_day} hits", ratio]
75
+ requests_per_day = (requests / days).ceil
76
+ rows << ["#{index.to_s.rjust(3)}:00", "%d hits" % requests_per_day, ratio]
66
77
  end
67
78
  end
68
79
  end
@@ -31,20 +31,27 @@ module RequestLogAnalyzer::Tracker
31
31
  @last = timestamp if @last.nil? || timestamp > @last
32
32
  end
33
33
 
34
+ def first_timestamp
35
+ DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
36
+ end
37
+
38
+ def last_timestamp
39
+ DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
40
+ end
41
+
42
+ def timespan
43
+ last_timestamp - first_timestamp
44
+ end
45
+
34
46
  def report(output)
35
47
  output.title(options[:title]) if options[:title]
36
48
 
37
- first_date = DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
38
- last_date = DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
39
-
40
49
  if @last && @first
41
- days = (@last && @first) ? (last_date - first_date).ceil : 1
42
-
43
50
  output.with_style(:cell_separator => false) do
44
51
  output.table({:width => 20}, {}) do |rows|
45
- rows << ['First request:', first_date.strftime('%Y-%m-%d %H:%M:%I')]
46
- rows << ['Last request:', last_date.strftime('%Y-%m-%d %H:%M:%I')]
47
- rows << ['Total time analyzed:', "#{days} days"]
52
+ rows << ['First request:', first_timestamp.strftime('%Y-%m-%d %H:%M:%I')]
53
+ rows << ['Last request:', last_timestamp.strftime('%Y-%m-%d %H:%M:%I')]
54
+ rows << ['Total time analyzed:', "#{timespan.ceil} days"]
48
55
  end
49
56
  end
50
57
  end
@@ -1,11 +1,30 @@
1
1
  require 'date'
2
- require File.dirname(__FILE__) + '/cli/progressbar'
3
2
 
3
+ # Satisfy ruby 1.9 sensitivity about encoding.
4
+ if defined? Encoding and Encoding.respond_to? 'default_external='
5
+ Encoding.default_external = 'binary'
6
+ end
7
+
8
+ # RequestLogAnalyzer is the base namespace in which all functionality of RequestLogAnalyzer is implemented.
9
+ #
10
+ # - This module itselfs contains some functions to help with class and source file loading.
11
+ # - The actual application resides in the RequestLogAnalyzer::Controller class.
4
12
  module RequestLogAnalyzer
5
-
6
- VERSION = '1.1'
13
+
14
+ # The current version of request-log-analyzer.
15
+ # This will be diplayed in output reports etc.
16
+ VERSION = '1.1.7'
17
+
18
+ # Loads constants in the RequestLogAnalyzer namespace using self.load_default_class_file(base, const)
19
+ # <tt>const</tt>:: The constant that is not yet loaded in the RequestLogAnalyzer namespace. This should be passed as a string or symbol.
20
+ def self.const_missing(const)
21
+ load_default_class_file(RequestLogAnalyzer, const)
22
+ end
7
23
 
8
- # Function to implement
24
+ # Loads constants that reside in the RequestLogAnalyzer tree using the constant name
25
+ # and its base constant to determine the filename.
26
+ # <tt>base</tt>:: The base constant to load the constant from. This should be Foo when the constant Foo::Bar is being loaded.
27
+ # <tt>const</tt>:: The constant to load from the base constant as a string or symbol. This should be 'Bar' or :Bar when the constant Foo::Bar is being loaded.
9
28
  def self.load_default_class_file(base, const)
10
29
  path = to_underscore(base.to_s)
11
30
  basename = to_underscore(const.to_s)
@@ -15,22 +34,16 @@ module RequestLogAnalyzer
15
34
  end
16
35
 
17
36
  # Convert a string/symbol in camelcase (RequestLogAnalyzer::Controller) to underscores (request_log_analyzer/controller)
37
+ # This function can be used to load the file (using require) in which the given constant is defined.
38
+ # <tt>str</tt>:: The string to convert in the following format: <tt>ModuleName::ClassName</tt>
18
39
  def self.to_underscore(str)
19
40
  str.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
20
41
  end
21
42
 
22
- # Convert a string/symbol in underscores (request_log_analyzer/controller) to camelcase (RequestLogAnalyzer::Controller)
43
+ # Convert a string/symbol in underscores (<tt>request_log_analyzer/controller</tt>) to camelcase
44
+ # (<tt>RequestLogAnalyzer::Controller</tt>). This can be used to find the class that is defined in a given filename.
45
+ # <tt>str</tt>:: The string to convert in the following format: <tt>module_name/class_name</tt>
23
46
  def self.to_camelcase(str)
24
- str.to_s.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
47
+ str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
25
48
  end
26
49
  end
27
-
28
- require File.dirname(__FILE__) + '/request_log_analyzer/file_format'
29
- require File.dirname(__FILE__) + '/request_log_analyzer/line_definition'
30
- require File.dirname(__FILE__) + '/request_log_analyzer/request'
31
- require File.dirname(__FILE__) + '/request_log_analyzer/aggregator'
32
- require File.dirname(__FILE__) + '/request_log_analyzer/filter'
33
- require File.dirname(__FILE__) + '/request_log_analyzer/controller'
34
- require File.dirname(__FILE__) + '/request_log_analyzer/source'
35
- require File.dirname(__FILE__) + '/request_log_analyzer/output'
36
-
@@ -0,0 +1,71 @@
1
+ require File.dirname(__FILE__) + '/../spec_helper.rb'
2
+
3
+ describe RequestLogAnalyzer, 'running from command line' do
4
+
5
+ include RequestLogAnalyzer::Spec::Helper
6
+
7
+ TEMPORARY_DIRECTORY = "#{File.dirname(__FILE__)}/../fixtures"
8
+ TEMP_DATABASE_FILE = TEMPORARY_DIRECTORY + "/output.db"
9
+ TEMP_REPORT_FILE = TEMPORARY_DIRECTORY + "/report"
10
+
11
+ before(:each) do
12
+ File.unlink(TEMP_DATABASE_FILE) if File.exist?(TEMP_DATABASE_FILE)
13
+ File.unlink(TEMP_REPORT_FILE) if File.exist?(TEMP_REPORT_FILE)
14
+ end
15
+
16
+ after(:each) do
17
+ File.unlink(TEMP_DATABASE_FILE) if File.exist?(TEMP_DATABASE_FILE)
18
+ File.unlink(TEMP_REPORT_FILE) if File.exist?(TEMP_REPORT_FILE)
19
+ end
20
+
21
+ it "should find 4 requests in default mode" do
22
+ output = run("#{log_fixture(:rails_1x)}")
23
+ output.detect { |line| /Parsed requests\:\s*4/ =~ line }.should_not be_nil
24
+ end
25
+
26
+ it "should find 3 requests with a --select option" do
27
+ output = run("#{log_fixture(:rails_1x)} --select controller PeopleController")
28
+ output.detect { |line| /Parsed requests\:\s*4/ =~ line }.should_not be_nil
29
+ end
30
+
31
+ it "should find 1 requests with a --reject option" do
32
+ output = run("#{log_fixture(:rails_1x)} --reject controller PeopleController")
33
+ output.detect { |line| /Parsed requests\:\s*4/ =~ line }.should_not be_nil
34
+ end
35
+
36
+ it "should write output to a file with the --file option" do
37
+ run("#{log_fixture(:rails_1x)} --file #{TEMP_REPORT_FILE}")
38
+ File.exist?(TEMP_REPORT_FILE).should be_true
39
+ end
40
+
41
+ it "should write only ASCII characters to a file with the --file option" do
42
+ run("#{log_fixture(:rails_1x)} --file #{TEMP_REPORT_FILE}")
43
+ /^[\x00-\x7F]*$/.match(File.read(TEMP_REPORT_FILE)).should_not be_nil
44
+ end
45
+
46
+ it "should write HTML if --output HTML is provided" do
47
+ output = run("#{log_fixture(:rails_1x)} --output HTML")
48
+ output.any? { |line| /<html.*>/ =~ line}
49
+ end
50
+
51
+ it "should run with the --database option" do
52
+ run("#{log_fixture(:rails_1x)} --database #{TEMP_DATABASE_FILE}")
53
+ File.exist?(TEMP_DATABASE_FILE).should be_true
54
+ end
55
+
56
+ it "should use no colors in the report with the --boring option" do
57
+ output = run("#{log_fixture(:rails_1x)} --boring")
58
+ output.any? { |line| /\e/ =~ line }.should be_false
59
+ end
60
+
61
+ it "should use only ASCII characters in the report with the --boring option" do
62
+ output = run("#{log_fixture(:rails_1x)} --boring")
63
+ output.all? { |line| /^[\x00-\x7F]*$/ =~ line }.should be_true
64
+ end
65
+
66
+ it "should parse a Merb file if --format merb is set" do
67
+ output = run("#{log_fixture(:merb)} --format merb")
68
+ output.detect { |line| /Parsed requests\:\s*11/ =~ line }.should_not be_nil
69
+ end
70
+
71
+ end
@@ -0,0 +1,33 @@
1
+ module RequestLogAnalyzer::Spec::Helper
2
+
3
+ include RequestLogAnalyzer::Spec::Mocks
4
+
5
+
6
+ def testing_format
7
+ @testing_format ||= TestingFormat.new
8
+ end
9
+
10
+ def log_fixture(name)
11
+ File.dirname(__FILE__) + "/../fixtures/#{name}.log"
12
+ end
13
+
14
+ def request(fields, format = testing_format)
15
+ if fields.kind_of?(Array)
16
+ format.request(*fields)
17
+ else
18
+ format.request(fields)
19
+ end
20
+ end
21
+
22
+ def run(arguments)
23
+ binary = "#{File.dirname(__FILE__)}/../../bin/request-log-analyzer"
24
+ arguments = arguments.join(' ') if arguments.kind_of?(Array)
25
+
26
+ output = []
27
+ IO.popen("#{binary} #{arguments}") do |pipe|
28
+ output = pipe.readlines
29
+ end
30
+ $?.exitstatus.should == 0
31
+ output
32
+ end
33
+ end
data/spec/lib/mocks.rb ADDED
@@ -0,0 +1,47 @@
1
+ module RequestLogAnalyzer::Spec::Mocks
2
+
3
+ def mock_source
4
+ source = mock('RequestLogAnalyzer::Source::Base')
5
+ source.stub!(:file_format).and_return(testing_format)
6
+ source.stub!(:parsed_requests).and_return(2)
7
+ source.stub!(:skipped_requests).and_return(1)
8
+ source.stub!(:parse_lines).and_return(10)
9
+
10
+ source.stub!(:warning=)
11
+ source.stub!(:progress=)
12
+
13
+ source.stub!(:prepare)
14
+ source.stub!(:finalize)
15
+
16
+ source.stub!(:each_request).and_return do |block|
17
+ block.call(testing_format.request(:field => 'value1'))
18
+ block.call(testing_format.request(:field => 'value2'))
19
+ end
20
+
21
+ return source
22
+ end
23
+
24
+ def mock_io
25
+ mio = mock('IO')
26
+ mio.stub!(:print)
27
+ mio.stub!(:puts)
28
+ mio.stub!(:write)
29
+ return mio
30
+ end
31
+
32
+ def mock_output
33
+ output = mock('RequestLogAnalyzer::Output::Base')
34
+ output.stub!(:header)
35
+ output.stub!(:footer)
36
+ output.stub!(:puts)
37
+ output.stub!(:<<)
38
+ output.stub!(:title)
39
+ output.stub!(:line)
40
+ output.stub!(:with_style)
41
+ output.stub!(:table) { yield [] }
42
+ output.stub!(:io).and_return(mock_io)
43
+ return output
44
+ end
45
+
46
+
47
+ end
@@ -1,4 +1,4 @@
1
- class SpecFormat < RequestLogAnalyzer::FileFormat::Base
1
+ class TestingFormat < RequestLogAnalyzer::FileFormat::Base
2
2
 
3
3
  format_definition.first do |line|
4
4
  line.header = true
@@ -14,6 +14,11 @@ class SpecFormat < RequestLogAnalyzer::FileFormat::Base
14
14
  { :name => :duration, :type => :duration, :unit => :msec }]
15
15
  end
16
16
 
17
+ format_definition.eval do |line|
18
+ line.regexp = /evaluation (\{.*\})/
19
+ line.captures = [{ :name => :evaluated, :type => :eval, :provides => { :greating => :string, :what => :string } }]
20
+ end
21
+
17
22
  format_definition.last do |line|
18
23
  line.footer = true
19
24
  line.teaser = /finishing /
data/spec/spec_helper.rb CHANGED
@@ -1,49 +1,13 @@
1
+ $:.reject! { |e| e.include? 'TextMate' }
1
2
  $: << File.join(File.dirname(__FILE__), '..', 'lib')
2
3
 
3
4
  require 'rubygems'
4
5
  require 'spec'
5
6
  require 'request_log_analyzer'
6
7
 
7
- module RequestLogAnalyzerSpecHelper
8
-
9
- def format_file(format)
10
- File.dirname(__FILE__) + "/file_formats/#{format}.rb"
11
- end
12
-
13
- def spec_format
14
- @spec_format ||= begin
15
- require format_file(:spec_format)
16
- SpecFormat.new
17
- end
18
- end
19
-
20
- def log_fixture(name)
21
- File.dirname(__FILE__) + "/fixtures/#{name}.log"
22
- end
23
-
24
- def request(fields, format = spec_format)
25
- if fields.kind_of?(Array)
26
- format.create_request(*fields)
27
- else
28
- format.create_request(fields)
29
- end
30
- end
31
-
32
- def mock_io
33
- mio = mock('IO')
34
- mio.stub!(:print)
35
- mio.stub!(:puts)
36
- mio.stub!(:write)
37
- return mio
38
- end
39
-
40
- def mock_output
41
- output = mock('RequestLogAnalyzer::Output')
42
- output.stub!(:header)
43
- output.stub!(:footer)
44
- output.stub!(:io).and_return(mock_io)
45
- return output
46
- end
47
-
8
+ module RequestLogAnalyzer::Spec
48
9
  end
49
10
 
11
+ require File.dirname(__FILE__) + '/lib/testing_format'
12
+ require File.dirname(__FILE__) + '/lib/mocks'
13
+ require File.dirname(__FILE__) + '/lib/helper'
@@ -1,45 +1,41 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
2
- require 'request_log_analyzer/aggregator/database'
3
-
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
4
2
 
5
3
  describe RequestLogAnalyzer::Aggregator::Database, "schema creation" do
6
4
 
7
- TEST_DATABASE_FILE = File.dirname(__FILE__) + "/fixtures/requests.db"
8
- include RequestLogAnalyzerSpecHelper
9
-
5
+ include RequestLogAnalyzer::Spec::Helper
6
+
10
7
  before(:each) do
11
- log_parser = RequestLogAnalyzer::Source::LogParser.new(spec_format)
12
- @database_inserter = RequestLogAnalyzer::Aggregator::Database.new(log_parser, :database => TEST_DATABASE_FILE)
13
- end
14
-
15
- after(:each) do
16
- File.unlink(TEST_DATABASE_FILE) if File.exist?(TEST_DATABASE_FILE)
8
+ log_parser = RequestLogAnalyzer::Source::LogParser.new(testing_format)
9
+ @database_inserter = RequestLogAnalyzer::Aggregator::Database.new(log_parser, :database => ':memory:')
17
10
  end
11
+
18
12
 
19
13
  it "should create the correct tables" do
20
14
  ActiveRecord::Migration.should_receive(:create_table).with("warnings")
21
15
  ActiveRecord::Migration.should_receive(:create_table).with("requests")
22
16
  ActiveRecord::Migration.should_receive(:create_table).with("first_lines")
23
17
  ActiveRecord::Migration.should_receive(:create_table).with("test_lines")
24
- ActiveRecord::Migration.should_receive(:create_table).with("last_lines")
18
+ ActiveRecord::Migration.should_receive(:create_table).with("eval_lines")
19
+ ActiveRecord::Migration.should_receive(:create_table).with("last_lines")
25
20
 
21
+ ActiveRecord::Migration.should_receive(:add_index).with("eval_lines", [:request_id])
26
22
  ActiveRecord::Migration.should_receive(:add_index).with("first_lines", [:request_id])
27
- ActiveRecord::Migration.should_receive(:add_index).with("test_lines", [:request_id])
28
- ActiveRecord::Migration.should_receive(:add_index).with("last_lines", [:request_id])
23
+ ActiveRecord::Migration.should_receive(:add_index).with("test_lines", [:request_id])
24
+ ActiveRecord::Migration.should_receive(:add_index).with("last_lines", [:request_id])
29
25
 
30
26
  @database_inserter.prepare
31
27
  end
32
28
 
33
29
  it "should create a default Request class" do
34
30
  @database_inserter.prepare
35
- SpecFormat::Database::Request.ancestors.should include(ActiveRecord::Base)
36
- SpecFormat::Database::Request.column_names.should include('first_lineno')
37
- SpecFormat::Database::Request.column_names.should include('last_lineno')
31
+ TestingFormat::Database::Request.ancestors.should include(ActiveRecord::Base)
32
+ TestingFormat::Database::Request.column_names.should include('first_lineno')
33
+ TestingFormat::Database::Request.column_names.should include('last_lineno')
38
34
  end
39
35
 
40
36
  it "should create associations for the default Request class" do
41
37
  @database_inserter.prepare
42
- @request = SpecFormat::Database::Request.new
38
+ @request = TestingFormat::Database::Request.new
43
39
  @request.should respond_to(:test_lines)
44
40
  @request.test_lines.should
45
41
  end
@@ -47,7 +43,7 @@ describe RequestLogAnalyzer::Aggregator::Database, "schema creation" do
47
43
  it "should create the default table names" do
48
44
  @database_inserter.prepare
49
45
  @database_inserter.file_format.line_definitions.each do |name, definition|
50
- klass = SpecFormat::Database.const_get("#{name}_line".camelize)
46
+ klass = TestingFormat::Database.const_get("#{name}_line".camelize)
51
47
  klass.column_names.should include('id')
52
48
  klass.column_names.should include('lineno')
53
49
  klass.column_names.should include('request_id')
@@ -57,46 +53,53 @@ describe RequestLogAnalyzer::Aggregator::Database, "schema creation" do
57
53
  it "should create the correct fields in the table" do
58
54
  @database_inserter.prepare
59
55
 
60
- SpecFormat::Database::FirstLine.column_names.should include('request_no')
61
- SpecFormat::Database::LastLine.column_names.should include('request_no')
62
- SpecFormat::Database::TestLine.column_names.should include('test_capture')
56
+ TestingFormat::Database::FirstLine.column_names.should include('request_no')
57
+ TestingFormat::Database::LastLine.column_names.should include('request_no')
58
+ TestingFormat::Database::TestLine.column_names.should include('test_capture')
59
+ end
60
+
61
+ it "should create fields for provides" do
62
+ @database_inserter.prepare
63
+ TestingFormat::Database::EvalLine.column_names.should include('evaluated')
64
+ TestingFormat::Database::EvalLine.column_names.should include('greating')
65
+ TestingFormat::Database::EvalLine.column_names.should include('what')
63
66
  end
64
67
 
65
68
  end
66
69
 
67
70
  describe RequestLogAnalyzer::Aggregator::Database, "record insertion" do
68
- include RequestLogAnalyzerSpecHelper
71
+ include RequestLogAnalyzer::Spec::Helper
69
72
 
70
73
  before(:each) do
71
- log_parser = RequestLogAnalyzer::Source::LogParser.new(spec_format)
72
- @database_inserter = RequestLogAnalyzer::Aggregator::Database.new(log_parser, :database => TEST_DATABASE_FILE)
74
+ log_parser = RequestLogAnalyzer::Source::LogParser.new(testing_format)
75
+ @database_inserter = RequestLogAnalyzer::Aggregator::Database.new(log_parser, :database => ':memory:')
73
76
  @database_inserter.prepare
74
77
 
75
- @incomplete_request = spec_format.create_request( {:line_type => :first, :request_no => 564})
76
- @completed_request = spec_format.create_request( {:line_type => :first, :request_no => 564}, {:line_type => :test, :test_capture => "awesome"},
77
- {:line_type => :test, :test_capture => "indeed"}, {:line_type => :last, :request_no => 564})
78
+ @incomplete_request = testing_format.request( {:line_type => :first, :request_no => 564})
79
+ @completed_request = testing_format.request( {:line_type => :first, :request_no => 564},
80
+ {:line_type => :test, :test_capture => "awesome"},
81
+ {:line_type => :test, :test_capture => "indeed"},
82
+ {:line_type => :eval, :evaluated => { :greating => 'howdy'}, :greating => 'howdy' },
83
+ {:line_type => :last, :request_no => 564})
78
84
  end
79
85
 
80
- after(:each) do
81
- File.unlink(TEST_DATABASE_FILE) if File.exist?(TEST_DATABASE_FILE)
82
- end
83
-
84
86
  it "should insert a record in the request table" do
85
- SpecFormat::Database::Request.count.should == 0
87
+ TestingFormat::Database::Request.count.should == 0
86
88
  @database_inserter.aggregate(@incomplete_request)
87
- SpecFormat::Database::Request.count.should == 1
89
+ TestingFormat::Database::Request.count.should == 1
88
90
  end
89
91
 
90
92
  it "should insert records in all relevant line tables" do
91
93
  @database_inserter.aggregate(@completed_request)
92
- request = SpecFormat::Database::Request.first
94
+ request = TestingFormat::Database::Request.first
93
95
  request.should have(2).test_lines
94
96
  request.should have(1).first_lines
97
+ request.should have(1).eval_lines
95
98
  request.should have(1).last_lines
96
99
  end
97
100
 
98
101
  it "should log a warning in the warnings table" do
99
- SpecFormat::Database::Warning.should_receive(:create!).with(hash_including(:warning_type => 'test_warning'))
102
+ TestingFormat::Database::Warning.should_receive(:create!).with(hash_including(:warning_type => 'test_warning'))
100
103
  @database_inserter.warning(:test_warning, "Testing the warning system", 12)
101
104
  end
102
105
 
@@ -0,0 +1,28 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe RequestLogAnalyzer::Aggregator::Summarizer do
4
+
5
+ include RequestLogAnalyzer::Spec::Helper
6
+
7
+ before(:each) do
8
+ @summarizer = RequestLogAnalyzer::Aggregator::Summarizer.new(mock_source, :output => mock_output)
9
+ @summarizer.prepare
10
+ end
11
+
12
+ it "not raise exception when creating a report after aggregating multiple requests" do
13
+ @summarizer.aggregate(request(:data => 'bluh1'))
14
+ @summarizer.aggregate(request(:data => 'bluh2'))
15
+
16
+ lambda { @summarizer.report(mock_output) }.should_not raise_error
17
+ end
18
+
19
+ it "not raise exception when creating a report after aggregating a single request" do
20
+ @summarizer.aggregate(request(:data => 'bluh1'))
21
+ lambda { @summarizer.report(mock_output) }.should_not raise_error
22
+ end
23
+
24
+ it "not raise exception when creating a report after aggregating no requests" do
25
+ lambda { @summarizer.report(mock_output) }.should_not raise_error
26
+ end
27
+
28
+ end
@@ -0,0 +1,43 @@
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
3
+ describe RequestLogAnalyzer::Controller do
4
+
5
+ include RequestLogAnalyzer::Spec::Helper
6
+
7
+ it "should use a custom output generator correctly" do
8
+
9
+ mock_output = mock('RequestLogAnalyzer::Output::Base')
10
+ mock_output.stub!(:io).and_return(mock_io)
11
+ mock_output.should_receive(:header)
12
+ mock_output.should_receive(:footer)
13
+
14
+ controller = RequestLogAnalyzer::Controller.new(mock_source, :output => mock_output)
15
+
16
+ controller.run!
17
+ end
18
+
19
+ it "should call aggregators correctly when run" do
20
+ controller = RequestLogAnalyzer::Controller.new(mock_source, :output => mock_output)
21
+
22
+ mock_aggregator = mock('RequestLogAnalyzer::Aggregator::Base')
23
+ mock_aggregator.should_receive(:prepare).once.ordered
24
+ mock_aggregator.should_receive(:aggregate).with(an_instance_of(testing_format.request_class)).twice.ordered
25
+ mock_aggregator.should_receive(:finalize).once.ordered
26
+ mock_aggregator.should_receive(:report).once.ordered
27
+
28
+ controller.aggregators << mock_aggregator
29
+ controller.run!
30
+ end
31
+
32
+ it "should call filters when run" do
33
+ controller = RequestLogAnalyzer::Controller.new(mock_source, :output => mock_output)
34
+
35
+ mock_filter = mock('RequestLogAnalyzer::Filter::Base')
36
+ mock_filter.should_receive(:filter).twice.and_return(nil)
37
+ controller.should_receive(:aggregate_request).twice.and_return(nil)
38
+
39
+ controller.filters << mock_filter
40
+ controller.run!
41
+ end
42
+
43
+ end
@@ -1,12 +1,13 @@
1
- require File.dirname(__FILE__) + '/spec_helper'
1
+ require File.dirname(__FILE__) + '/../../spec_helper'
2
+
2
3
  require 'request_log_analyzer/log_processor'
3
4
 
4
5
  describe RequestLogAnalyzer::LogProcessor, 'stripping log files' do
5
6
 
6
- include RequestLogAnalyzerSpecHelper
7
+ include RequestLogAnalyzer::Spec::Helper
7
8
 
8
9
  before(:each) do
9
- @log_stripper = RequestLogAnalyzer::LogProcessor.new(spec_format, :strip, {})
10
+ @log_stripper = RequestLogAnalyzer::LogProcessor.new(testing_format, :strip, {})
10
11
  end
11
12
 
12
13
  it "should remove a junk line" do