request-log-analyzer 1.2.9 → 1.3.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.
- data/bin/request-log-analyzer +33 -19
- data/lib/cli/database_console.rb +26 -0
- data/lib/cli/database_console_init.rb +42 -0
- data/lib/cli/tools.rb +1 -1
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +81 -0
- data/lib/request_log_analyzer/aggregator/summarizer.rb +2 -2
- data/lib/request_log_analyzer/aggregator.rb +4 -0
- data/lib/request_log_analyzer/controller.rb +23 -7
- data/lib/request_log_analyzer/database/base.rb +114 -0
- data/lib/request_log_analyzer/database/connection.rb +38 -0
- data/lib/request_log_analyzer/database.rb +177 -0
- data/lib/request_log_analyzer/file_format.rb +6 -3
- data/lib/request_log_analyzer/mailer.rb +46 -0
- data/lib/request_log_analyzer/request.rb +2 -1
- data/lib/request_log_analyzer/source/{database.rb → database_loader.rb} +1 -1
- data/lib/request_log_analyzer/source/log_parser.rb +28 -15
- data/lib/request_log_analyzer/source.rb +7 -2
- data/lib/request_log_analyzer.rb +5 -8
- data/request-log-analyzer.gemspec +8 -8
- data/spec/database.yml +17 -0
- data/spec/fixtures/rails.db +0 -0
- data/spec/integration/command_line_usage_spec.rb +14 -9
- data/spec/lib/macros.rb +16 -0
- data/spec/lib/mocks.rb +18 -6
- data/spec/unit/aggregator/database_inserter_spec.rb +93 -0
- data/spec/unit/database/base_class_spec.rb +190 -0
- data/spec/unit/database/connection_spec.rb +34 -0
- data/spec/unit/database/database_spec.rb +138 -0
- data/spec/unit/source/log_parser_spec.rb +12 -0
- metadata +29 -16
- data/lib/request_log_analyzer/aggregator/database.rb +0 -220
- data/spec/spec.opts +0 -3
- data/spec/unit/aggregator/database_spec.rb +0 -245
| @@ -0,0 +1,93 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/../../spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe RequestLogAnalyzer::Aggregator::DatabaseInserter do
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              before(:all) do
         | 
| 6 | 
            +
                @log_parser = RequestLogAnalyzer::Source::LogParser.new(testing_format)
         | 
| 7 | 
            +
              end
         | 
| 8 | 
            +
              
         | 
| 9 | 
            +
              # The prepare method is called before the parsing starts. It should establish a connection
         | 
| 10 | 
            +
              # to a database that is suitable for inserting requests later on.
         | 
| 11 | 
            +
              describe '#prepare' do
         | 
| 12 | 
            +
              
         | 
| 13 | 
            +
                before(:each) do
         | 
| 14 | 
            +
                  @database = mock_database(:create_database_schema!, :drop_database_schema!, :file_format=)
         | 
| 15 | 
            +
                  @database_inserter = RequestLogAnalyzer::Aggregator::DatabaseInserter.new(@log_parser)
         | 
| 16 | 
            +
                  RequestLogAnalyzer::Database.stub!(:new).and_return(@database)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
              
         | 
| 19 | 
            +
                it 'should establish the database connection' do
         | 
| 20 | 
            +
                  RequestLogAnalyzer::Database.should_receive(:new).and_return(@database)
         | 
| 21 | 
            +
                  @database_inserter.prepare
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
                
         | 
| 24 | 
            +
                it "should set the file_format" do
         | 
| 25 | 
            +
                  @database.should_receive(:file_format=).with(testing_format)
         | 
| 26 | 
            +
                  @database_inserter.prepare
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
              
         | 
| 29 | 
            +
                it 'should create the database schema during preparation' do
         | 
| 30 | 
            +
                  @database.should_receive(:create_database_schema!)
         | 
| 31 | 
            +
                  @database_inserter.prepare
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                it 'should not drop the database schema during preparation if not requested' do
         | 
| 35 | 
            +
                  @database.should_not_receive(:drop_database_schema!)
         | 
| 36 | 
            +
                  @database_inserter.prepare
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                it 'should drop the database schema during preparation if requested' do
         | 
| 40 | 
            +
                  @database_inserter.options[:reset_database] = true
         | 
| 41 | 
            +
                  @database.should_receive(:drop_database_schema!)
         | 
| 42 | 
            +
                  @database_inserter.prepare
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              test_databases.each do |name, connection|
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                context "using a #{name} database" do
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  before(:each) do
         | 
| 51 | 
            +
                    @database_inserter = RequestLogAnalyzer::Aggregator::DatabaseInserter.new(@log_parser, :database => connection, :reset_database => true)
         | 
| 52 | 
            +
                    @database_inserter.prepare
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                    @incomplete_request = testing_format.request( {:line_type => :first, :request_no => 564})
         | 
| 55 | 
            +
                    @completed_request  = testing_format.request( {:line_type => :first, :request_no => 564}, 
         | 
| 56 | 
            +
                                          {:line_type => :test, :test_capture => "awesome"},
         | 
| 57 | 
            +
                                          {:line_type => :test, :test_capture => "indeed"}, 
         | 
| 58 | 
            +
                                          {:line_type => :eval, :evaluated => { :greating => 'howdy'}, :greating => 'howdy' }, 
         | 
| 59 | 
            +
                                          {:line_type => :last, :request_no   => 564})
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
                  
         | 
| 62 | 
            +
                  after(:each) do
         | 
| 63 | 
            +
                    @database_inserter.database.send :remove_orm_classes!
         | 
| 64 | 
            +
                  end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                  it "should insert a record in the request table" do
         | 
| 67 | 
            +
                    lambda { 
         | 
| 68 | 
            +
                      @database_inserter.aggregate(@incomplete_request)
         | 
| 69 | 
            +
                    }.should change(@database_inserter.database.request_class, :count).from(0).to(1)
         | 
| 70 | 
            +
                  end
         | 
| 71 | 
            +
                  
         | 
| 72 | 
            +
                  it "should insert a record in the first_lines table" do
         | 
| 73 | 
            +
                    lambda { 
         | 
| 74 | 
            +
                      @database_inserter.aggregate(@incomplete_request)
         | 
| 75 | 
            +
                    }.should change(@database_inserter.database.get_class(:first), :count).from(0).to(1)
         | 
| 76 | 
            +
                  end      
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  it "should insert records in all relevant line tables" do
         | 
| 79 | 
            +
                    @database_inserter.aggregate(@completed_request)
         | 
| 80 | 
            +
                    request = @database_inserter.database.request_class.first
         | 
| 81 | 
            +
                    request.should have(2).test_lines
         | 
| 82 | 
            +
                    request.should have(1).first_lines
         | 
| 83 | 
            +
                    request.should have(1).eval_lines
         | 
| 84 | 
            +
                    request.should have(1).last_lines
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  it "should log a warning in the warnings table" do
         | 
| 88 | 
            +
                    @database_inserter.database.warning_class.should_receive(:create!).with(hash_including(:warning_type => 'test_warning'))
         | 
| 89 | 
            +
                    @database_inserter.warning(:test_warning, "Testing the warning system", 12)
         | 
| 90 | 
            +
                  end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
              end
         | 
| 93 | 
            +
            end
         | 
| @@ -0,0 +1,190 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/../../spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe RequestLogAnalyzer::Database::Base do
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              describe '.subclass_from_line_definition' do
         | 
| 6 | 
            +
                before(:all) do
         | 
| 7 | 
            +
                  @line_definition = RequestLogAnalyzer::LineDefinition.new(:test, { :regexp   => /Testing (\w+), tries\: (\d+)/,
         | 
| 8 | 
            +
                                      :captures => [{ :name => :what, :type => :string }, { :name => :tries, :type => :integer },
         | 
| 9 | 
            +
                                        { :name => :evaluated, :type => :hash, :provides => {:evaluated_field => :duration} }]})
         | 
| 10 | 
            +
                end
         | 
| 11 | 
            +
                
         | 
| 12 | 
            +
                before(:each) do
         | 
| 13 | 
            +
                  @orm_class = mock('Line ActiveRecord::Base class')
         | 
| 14 | 
            +
                  @orm_class.stub!(:set_table_name)
         | 
| 15 | 
            +
                  @orm_class.stub!(:belongs_to)
         | 
| 16 | 
            +
                  @orm_class.stub!(:serialize)
         | 
| 17 | 
            +
                  @orm_class.stub!(:line_definition=)
         | 
| 18 | 
            +
                  Class.stub!(:new).with(RequestLogAnalyzer::Database::Base).and_return(@orm_class)
         | 
| 19 | 
            +
                  
         | 
| 20 | 
            +
                  @request_class = mock('Request ActiveRecord::Base class')
         | 
| 21 | 
            +
                  @request_class.stub!(:has_many)
         | 
| 22 | 
            +
                  @source_class = mock('Source ActiveRecord::Base class')
         | 
| 23 | 
            +
                  @source_class.stub!(:has_many)      
         | 
| 24 | 
            +
                  
         | 
| 25 | 
            +
                  @database = mock_database
         | 
| 26 | 
            +
                  @database.stub!(:request_class).and_return(@request_class)
         | 
| 27 | 
            +
                  @database.stub!(:source_class).and_return(@source_class)
         | 
| 28 | 
            +
                  RequestLogAnalyzer::Database::Base.stub!(:database).and_return(@database)
         | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                it "should create a new subclass using the Base class as parent" do
         | 
| 32 | 
            +
                  Class.should_receive(:new).with(RequestLogAnalyzer::Database::Base).and_return(@orm_class)
         | 
| 33 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_line_definition(@line_definition)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
                
         | 
| 36 | 
            +
                it "should store the LineDefinition" do
         | 
| 37 | 
            +
                  @orm_class.should_receive(:line_definition=).with(@line_definition)
         | 
| 38 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_line_definition(@line_definition)
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                it "should set the table name for the subclass" do
         | 
| 42 | 
            +
                  @orm_class.should_receive(:set_table_name).with('test_lines')
         | 
| 43 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_line_definition(@line_definition)
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                it "should set the :belongs_to relationship with the Request class" do
         | 
| 47 | 
            +
                  @orm_class.should_receive(:belongs_to).with(:request)
         | 
| 48 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_line_definition(@line_definition)
         | 
| 49 | 
            +
                end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                it "should set a :has_many relationship in the request class" do
         | 
| 52 | 
            +
                  @request_class.should_receive(:has_many).with(:test_lines)
         | 
| 53 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_line_definition(@line_definition)
         | 
| 54 | 
            +
                end
         | 
| 55 | 
            +
             | 
| 56 | 
            +
                it "should set a :has_many relationship in the source class" do
         | 
| 57 | 
            +
                  @source_class.should_receive(:has_many).with(:test_lines)
         | 
| 58 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_line_definition(@line_definition)
         | 
| 59 | 
            +
                end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                it "should set the :belongs_to relationship with the Source class" do
         | 
| 62 | 
            +
                  @orm_class.should_receive(:belongs_to).with(:source)
         | 
| 63 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_line_definition(@line_definition)
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                it "should serialize a complex field" do
         | 
| 67 | 
            +
                  @orm_class.should_receive(:serialize).with(:evaluated, Hash)
         | 
| 68 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_line_definition(@line_definition)
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              describe '.subclass_from_table' do
         | 
| 74 | 
            +
                before(:each) do
         | 
| 75 | 
            +
                  
         | 
| 76 | 
            +
                  @request_class = mock('Request ActiveRecord::Base class')
         | 
| 77 | 
            +
                  @request_class.stub!(:has_many)
         | 
| 78 | 
            +
                  @source_class = mock('Source ActiveRecord::Base class')
         | 
| 79 | 
            +
                  @source_class.stub!(:has_many)      
         | 
| 80 | 
            +
                  
         | 
| 81 | 
            +
                  @database = mock_database
         | 
| 82 | 
            +
                  @database.stub!(:request_class).and_return(@request_class)
         | 
| 83 | 
            +
                  @database.stub!(:source_class).and_return(@source_class)
         | 
| 84 | 
            +
                  @database.connection.stub!(:table_exists?).and_return(true)
         | 
| 85 | 
            +
                  RequestLogAnalyzer::Database::Base.stub!(:database).and_return(@database)
         | 
| 86 | 
            +
                  
         | 
| 87 | 
            +
                  @klass = mock('ActiveRecord ORM class')
         | 
| 88 | 
            +
                  @klass.stub!(:column_names).and_return(['id', 'request_id', 'source_id', 'lineno', 'duration']) 
         | 
| 89 | 
            +
                  @klass.stub!(:set_table_name)
         | 
| 90 | 
            +
                  @klass.stub!(:belongs_to)
         | 
| 91 | 
            +
                  Class.stub!(:new).with(RequestLogAnalyzer::Database::Base).and_return(@klass)
         | 
| 92 | 
            +
                end
         | 
| 93 | 
            +
                
         | 
| 94 | 
            +
                it "should create a new subclass using the Base class as parent" do
         | 
| 95 | 
            +
                  Class.should_receive(:new).with(RequestLogAnalyzer::Database::Base).and_return(@klass)
         | 
| 96 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_table('completed_lines')
         | 
| 97 | 
            +
                end    
         | 
| 98 | 
            +
                
         | 
| 99 | 
            +
                it "should set the table name" do
         | 
| 100 | 
            +
                  @klass.should_receive(:set_table_name).with('completed_lines')
         | 
| 101 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_table('completed_lines')
         | 
| 102 | 
            +
                end
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                it "should create the :belongs_to relation to the request class" do
         | 
| 105 | 
            +
                  @klass.should_receive(:belongs_to).with(:request)
         | 
| 106 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_table('completed_lines')
         | 
| 107 | 
            +
                end
         | 
| 108 | 
            +
                
         | 
| 109 | 
            +
                it "should create the :has_many relation in the request class" do
         | 
| 110 | 
            +
                  @request_class.should_receive(:has_many).with(:completed_lines)
         | 
| 111 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_table('completed_lines')
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                it "should create the :belongs_to relation to the source class" do
         | 
| 115 | 
            +
                  @klass.should_receive(:belongs_to).with(:source)
         | 
| 116 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_table('completed_lines')
         | 
| 117 | 
            +
                end
         | 
| 118 | 
            +
                
         | 
| 119 | 
            +
                it "should create the :has_many relation in the request class" do
         | 
| 120 | 
            +
                  @source_class.should_receive(:has_many).with(:completed_lines)
         | 
| 121 | 
            +
                  RequestLogAnalyzer::Database::Base.subclass_from_table('completed_lines')
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
              end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
              describe '#create_table' do
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                before(:all) do
         | 
| 129 | 
            +
                  @line_definition = RequestLogAnalyzer::LineDefinition.new(:test, { :regexp   => /Testing (\w+), tries\: (\d+)/,
         | 
| 130 | 
            +
                                        :captures => [{ :name => :what, :type => :string }, { :name => :tries, :type => :integer },
         | 
| 131 | 
            +
                                          { :name => :evaluated, :type => :hash, :provides => {:evaluated_field => :duration} }]})
         | 
| 132 | 
            +
                end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                before(:each) do
         | 
| 135 | 
            +
                  @database = RequestLogAnalyzer::Database.new
         | 
| 136 | 
            +
                  @database.stub!(:connection).and_return(mock_connection)
         | 
| 137 | 
            +
                  @klass = @database.load_activerecord_class(@line_definition)
         | 
| 138 | 
            +
                  @klass.stub!(:table_exists?).and_return(false)
         | 
| 139 | 
            +
                end
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                after(:each) do 
         | 
| 142 | 
            +
                  @klass.drop_table!
         | 
| 143 | 
            +
                  @database.remove_orm_classes!
         | 
| 144 | 
            +
                end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                it "should call create_table with the correct table name" do
         | 
| 147 | 
            +
                  @database.connection.should_receive(:create_table).with(:test_lines)
         | 
| 148 | 
            +
                  @klass.create_table!
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                it "should not create a table based on the line type name if it already exists" do
         | 
| 152 | 
            +
                  @klass.stub!(:table_exists?).and_return(true)
         | 
| 153 | 
            +
                  @database.connection.should_not_receive(:create_table).with(:test_lines)
         | 
| 154 | 
            +
                  @klass.create_table!
         | 
| 155 | 
            +
                end
         | 
| 156 | 
            +
             | 
| 157 | 
            +
                it "should create an index on the request_id field" do
         | 
| 158 | 
            +
                  @database.connection.should_receive(:add_index).with(:test_lines, [:request_id])
         | 
| 159 | 
            +
                  @klass.create_table!
         | 
| 160 | 
            +
                end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                it "should create an index on the source_id field" do
         | 
| 163 | 
            +
                  @database.connection.should_receive(:add_index).with(:test_lines, [:source_id])
         | 
| 164 | 
            +
                  @klass.create_table!
         | 
| 165 | 
            +
                end
         | 
| 166 | 
            +
             | 
| 167 | 
            +
                it "should create a request_id field to link the requests together" do
         | 
| 168 | 
            +
                  @database.connection.table_creator.should_receive(:column).with(:request_id, :integer)
         | 
| 169 | 
            +
                  @klass.create_table!
         | 
| 170 | 
            +
                end
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                it "should create a lineno field to save the location of the line in the original file" do
         | 
| 173 | 
            +
                  @database.connection.table_creator.should_receive(:column).with(:lineno, :integer)
         | 
| 174 | 
            +
                  @klass.create_table!
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                it "should create a field of the correct type for every defined capture field" do
         | 
| 178 | 
            +
                  @database.connection.table_creator.should_receive(:column).with(:what, :string)
         | 
| 179 | 
            +
                  @database.connection.table_creator.should_receive(:column).with(:tries, :integer)
         | 
| 180 | 
            +
                  @database.connection.table_creator.should_receive(:column).with(:evaluated, :text) 
         | 
| 181 | 
            +
                  @klass.create_table!
         | 
| 182 | 
            +
                end
         | 
| 183 | 
            +
             | 
| 184 | 
            +
                it "should create a field of the correct type for every provided field" do
         | 
| 185 | 
            +
                  @database.connection.table_creator.should_receive(:column).with(:evaluated_field, :double) 
         | 
| 186 | 
            +
                  @klass.create_table!
         | 
| 187 | 
            +
                end
         | 
| 188 | 
            +
              end
         | 
| 189 | 
            +
            end
         | 
| 190 | 
            +
             | 
| @@ -0,0 +1,34 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/../../spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe RequestLogAnalyzer::Database::Connection do
         | 
| 4 | 
            +
              describe '.from_string' do
         | 
| 5 | 
            +
             | 
| 6 | 
            +
                it "should parse a name-value based string" do
         | 
| 7 | 
            +
                  string = 'adapter=sqlite3;database=filename.db'
         | 
| 8 | 
            +
                  RequestLogAnalyzer::Database::Connection.from_string(string).should == {:adapter => 'sqlite3', :database => 'filename.db'}
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                it "should parse an URI-based string for SQLite3" do
         | 
| 12 | 
            +
                  string = 'sqlite3://filename.db'
         | 
| 13 | 
            +
                  RequestLogAnalyzer::Database::Connection.from_string(string).should == {:adapter => 'sqlite3', :database => 'filename.db'}
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                it "should parse an URI-based string for MySQL" do
         | 
| 17 | 
            +
                  string = 'mysql://localhost.local/database'
         | 
| 18 | 
            +
                  RequestLogAnalyzer::Database::Connection.from_string(string).should == 
         | 
| 19 | 
            +
                          { :adapter => 'mysql', :database => 'database', :host => 'localhost.local' }
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                it "should parse an URI-based string for MySQL with only username" do
         | 
| 23 | 
            +
                  string = 'mysql://username@localhost.local/database'
         | 
| 24 | 
            +
                  RequestLogAnalyzer::Database::Connection.from_string(string).should == 
         | 
| 25 | 
            +
                          { :adapter => 'mysql', :database => 'database', :host => 'localhost.local', :username => 'username' }
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                it "should parse an URI-based string for MySQL with username and password" do
         | 
| 29 | 
            +
                  string = 'mysql://username:password@localhost.local/database'
         | 
| 30 | 
            +
                  RequestLogAnalyzer::Database::Connection.from_string(string).should == 
         | 
| 31 | 
            +
                          { :adapter => 'mysql', :database => 'database', :host => 'localhost.local', :username => 'username', :password => 'password' }
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
            end
         | 
| @@ -0,0 +1,138 @@ | |
| 1 | 
            +
            require File.dirname(__FILE__) + '/../../spec_helper'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            describe RequestLogAnalyzer::Database do
         | 
| 4 | 
            +
              
         | 
| 5 | 
            +
              describe '#load_database_schema!' do
         | 
| 6 | 
            +
                
         | 
| 7 | 
            +
                context 'for a Rails request database' do
         | 
| 8 | 
            +
                  before(:each) do
         | 
| 9 | 
            +
                    @database = RequestLogAnalyzer::Database.new(log_fixture(:rails, :db))
         | 
| 10 | 
            +
                    @database.load_database_schema!
         | 
| 11 | 
            +
                  end
         | 
| 12 | 
            +
                
         | 
| 13 | 
            +
                  after(:each) { @database.remove_orm_classes! }
         | 
| 14 | 
            +
                
         | 
| 15 | 
            +
                  # FileFormat-agnostic classes
         | 
| 16 | 
            +
                  default_orm_class_names.each do |const|
         | 
| 17 | 
            +
                    it "should create the default #{const} constant" do
         | 
| 18 | 
            +
                      Object.const_defined?(const).should be_true
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                    it "should create the default #{const} class inheriting from ActiveRecord::Base and RequestLogAnalyzer::Database::Base" do
         | 
| 22 | 
            +
                      Object.const_get(const).ancestors.should include(ActiveRecord::Base, RequestLogAnalyzer::Database::Base)
         | 
| 23 | 
            +
                    end
         | 
| 24 | 
            +
                  end
         | 
| 25 | 
            +
                
         | 
| 26 | 
            +
                  # Some Fileformat-specific classes
         | 
| 27 | 
            +
                  ['CompletedLine', 'ProcessingLine'].each do |const|
         | 
| 28 | 
            +
                    it "should create the #{const} constant" do
         | 
| 29 | 
            +
                      Object.const_defined?(const).should be_true
         | 
| 30 | 
            +
                    end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    it "should create the #{const} class inheriting from ActiveRecord::Base and RequestLogAnalyzer::Database::Base" do
         | 
| 33 | 
            +
                      Object.const_get(const).ancestors.should include(ActiveRecord::Base, RequestLogAnalyzer::Database::Base)
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  
         | 
| 36 | 
            +
                    it "should create a :belongs_to relation from the #{const} class to Request and Source" do
         | 
| 37 | 
            +
                      Object.const_get(const).send(:reflections).should include(:request, :source)
         | 
| 38 | 
            +
                    end
         | 
| 39 | 
            +
                    
         | 
| 40 | 
            +
                    it "should create a :has_many relation from the Request and Source class to the #{const} class" do
         | 
| 41 | 
            +
                      @database.request_class.send(:reflections).should include(const.underscore.pluralize.to_sym)
         | 
| 42 | 
            +
                      @database.source_class.send(:reflections).should include(const.underscore.pluralize.to_sym)
         | 
| 43 | 
            +
                    end
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
                end
         | 
| 46 | 
            +
              end
         | 
| 47 | 
            +
              
         | 
| 48 | 
            +
              describe '#create_database_schema!' do
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                before(:each) do
         | 
| 51 | 
            +
                  @database = RequestLogAnalyzer::Database.new
         | 
| 52 | 
            +
                  @database.file_format = testing_format
         | 
| 53 | 
            +
                  @database.stub!(:connection).and_return(mock_connection)
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  # Stub the expected method calls for the preparation, these will be tested separately
         | 
| 56 | 
            +
                  @mock_class = Class.new(RequestLogAnalyzer::Database::Base)
         | 
| 57 | 
            +
                  @mock_class.stub!(:create_table!)
         | 
| 58 | 
            +
                end
         | 
| 59 | 
            +
                
         | 
| 60 | 
            +
                after(:each) { @database.remove_orm_classes! }
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                default_orm_class_names.each do |klass|
         | 
| 63 | 
            +
                  it "should create a table for the default #{klass} class" do
         | 
| 64 | 
            +
                    @database.connection.should_receive(:create_table).with(klass.underscore.pluralize.to_sym)
         | 
| 65 | 
            +
                    @database.send :create_database_schema!
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                  it "should create a #{klass} class inheriting from ActiveRecord and the base class of the ORM module" do
         | 
| 69 | 
            +
                    @database.send :create_database_schema!
         | 
| 70 | 
            +
                    @database.send("#{klass.underscore}_class".to_sym).ancestors.should include(ActiveRecord::Base, RequestLogAnalyzer::Database::Base)
         | 
| 71 | 
            +
                  end
         | 
| 72 | 
            +
                end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                testing_format.line_definitions.each do |name, definition|
         | 
| 75 | 
            +
                  
         | 
| 76 | 
            +
                  it "should create the #{(name.to_s + '_line').camelize} class for #{name.inspect} lines" do
         | 
| 77 | 
            +
                    @database.send :create_database_schema!
         | 
| 78 | 
            +
                    Object.const_defined?("#{name}_line".camelize).should be_true
         | 
| 79 | 
            +
                  end
         | 
| 80 | 
            +
                  
         | 
| 81 | 
            +
                  it "should create the #{name.to_s + '_lines'} table for the parsed #{name.inspect} lines" do
         | 
| 82 | 
            +
                    @database.connection.should_receive(:create_table).with("#{name}_lines".to_sym)
         | 
| 83 | 
            +
                    @database.send :create_database_schema!
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
                end
         | 
| 86 | 
            +
              end
         | 
| 87 | 
            +
              
         | 
| 88 | 
            +
              describe '#load_activerecord_class' do
         | 
| 89 | 
            +
                
         | 
| 90 | 
            +
                before(:each) do 
         | 
| 91 | 
            +
                  @database = RequestLogAnalyzer::Database.new
         | 
| 92 | 
            +
                  @connection = mock_connection
         | 
| 93 | 
            +
                  @database.stub!(:connection).and_return(@connection)
         | 
| 94 | 
            +
                  
         | 
| 95 | 
            +
                  # Mock the request ORM class
         | 
| 96 | 
            +
                  @request_class = mock('Request ActiveRecord::Base class')
         | 
| 97 | 
            +
                  @request_class.stub!(:has_many)
         | 
| 98 | 
            +
                
         | 
| 99 | 
            +
                  @source_class = mock('Source ActiveRecord::Base class')
         | 
| 100 | 
            +
                  @source_class.stub!(:has_many)
         | 
| 101 | 
            +
                
         | 
| 102 | 
            +
                  @database.stub!(:request_class).and_return(@request_class)
         | 
| 103 | 
            +
                  @database.stub!(:source_class).and_return(@source_class)
         | 
| 104 | 
            +
                  
         | 
| 105 | 
            +
                  @mock_class = Class.new(RequestLogAnalyzer::Database::Base)
         | 
| 106 | 
            +
                  
         | 
| 107 | 
            +
                  RequestLogAnalyzer::Database::Base.stub!(:subclass_from_table).and_return(@mock_class)
         | 
| 108 | 
            +
                  RequestLogAnalyzer::Database::Base.stub!(:subclass_from_line_definition).and_return(@mock_class)
         | 
| 109 | 
            +
                end
         | 
| 110 | 
            +
                
         | 
| 111 | 
            +
                after(:each) { @database.remove_orm_classes! }
         | 
| 112 | 
            +
                
         | 
| 113 | 
            +
                it "should call :subclass_from_table when a table name is given as string" do
         | 
| 114 | 
            +
                  RequestLogAnalyzer::Database::Base.should_receive(:subclass_from_table).and_return(@mock_class)
         | 
| 115 | 
            +
                  @database.load_activerecord_class('test_lines')
         | 
| 116 | 
            +
                end
         | 
| 117 | 
            +
                
         | 
| 118 | 
            +
                it "should call :subclass_from_table when a table name is given as symbol" do
         | 
| 119 | 
            +
                  RequestLogAnalyzer::Database::Base.should_receive(:subclass_from_table).and_return(@mock_class)
         | 
| 120 | 
            +
                  @database.load_activerecord_class(:test_lines)
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
                
         | 
| 123 | 
            +
                it "should call :subclass_from_table when a LineDefinition is given" do
         | 
| 124 | 
            +
                  RequestLogAnalyzer::Database::Base.should_receive(:subclass_from_line_definition).and_return(@mock_class)
         | 
| 125 | 
            +
                  @database.load_activerecord_class(RequestLogAnalyzer::LineDefinition.new(:test))
         | 
| 126 | 
            +
                end    
         | 
| 127 | 
            +
                
         | 
| 128 | 
            +
                it "should define the class in the ORM module" do
         | 
| 129 | 
            +
                  @database.load_activerecord_class(:test_lines)
         | 
| 130 | 
            +
                  Object.const_defined?('TestLine').should be_true
         | 
| 131 | 
            +
                end
         | 
| 132 | 
            +
                
         | 
| 133 | 
            +
                it "should add the class to the line_classes array of the database" do
         | 
| 134 | 
            +
                  @database.load_activerecord_class(:test_lines)
         | 
| 135 | 
            +
                  @database.line_classes.should include(TestLine)
         | 
| 136 | 
            +
                end
         | 
| 137 | 
            +
              end
         | 
| 138 | 
            +
            end
         | 
| @@ -14,6 +14,18 @@ describe RequestLogAnalyzer::Source::LogParser, :requests do | |
| 14 14 | 
             
                @log_parser.file_format.should be_valid
         | 
| 15 15 | 
             
              end
         | 
| 16 16 |  | 
| 17 | 
            +
              it "should set the :source for every parsed line" do
         | 
| 18 | 
            +
                @log_parser.parse_file(log_fixture(:rails_22)) do |request|
         | 
| 19 | 
            +
                  request.lines.all? { |line| line[:source] == log_fixture(:rails_22) }.should be_true
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
              end
         | 
| 22 | 
            +
              
         | 
| 23 | 
            +
              it "should set the :lineno for every parsed line" do
         | 
| 24 | 
            +
                @log_parser.parse_file(log_fixture(:rails_22)) do |request|
         | 
| 25 | 
            +
                  request.lines.all? { |line| line.has_key?(:lineno) }.should be_true
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
              end
         | 
| 28 | 
            +
              
         | 
| 17 29 | 
             
              it "should parse more lines than requests" do
         | 
| 18 30 | 
             
                @log_parser.should_receive(:handle_request).with(an_instance_of(TestingFormat::Request)).twice
         | 
| 19 31 | 
             
                @log_parser.parse_file(log_fixture(:test_language_combined))
         | 
    
        metadata
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification 
         | 
| 2 2 | 
             
            name: request-log-analyzer
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version 
         | 
| 4 | 
            -
              version: 1. | 
| 4 | 
            +
              version: 1.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors: 
         | 
| 7 7 | 
             
            - Willem van Bergen
         | 
| @@ -10,7 +10,7 @@ autorequire: | |
| 10 10 | 
             
            bindir: bin
         | 
| 11 11 | 
             
            cert_chain: []
         | 
| 12 12 |  | 
| 13 | 
            -
            date: 2009-09- | 
| 13 | 
            +
            date: 2009-09-12 00:00:00 +02:00
         | 
| 14 14 | 
             
            default_executable: request-log-analyzer
         | 
| 15 15 | 
             
            dependencies: 
         | 
| 16 16 | 
             
            - !ruby/object:Gem::Dependency 
         | 
| @@ -33,7 +33,7 @@ dependencies: | |
| 33 33 | 
             
                  - !ruby/object:Gem::Version 
         | 
| 34 34 | 
             
                    version: 1.1.0
         | 
| 35 35 | 
             
                version: 
         | 
| 36 | 
            -
            description: "    Request log analyzer's purpose is to find ot how your web application is being used and to focus your optimization efforts.\n    This tool will parse all requests in the application's log file and aggregate the information. Once it is finished parsing \n    the log file(s), it will show the requests that take op most server time using various metrics. It can also insert all \n    parsed request information into a database so you can roll your own analysis. It supports Rails- and Merb-based applications \n    out of the box, but file formats of other applications can easily be supported by supplying an easy to write log file format  | 
| 36 | 
            +
            description: "    Request log analyzer's purpose is to find ot how your web application is being used and to focus your optimization efforts.\n    This tool will parse all requests in the application's log file and aggregate the information. Once it is finished parsing \n    the log file(s), it will show the requests that take op most server time using various metrics. It can also insert all \n    parsed request information into a database so you can roll your own analysis. It supports Rails- and Merb-based applications \n    and Apache access log files out of the box, but file formats of other applications can easily be supported by supplying an \n    easy to write log file format definition.\n"
         | 
| 37 37 | 
             
            email: 
         | 
| 38 38 | 
             
            - willem@railsdoctors.com
         | 
| 39 39 | 
             
            - bart@railsdoctors.com
         | 
| @@ -49,8 +49,8 @@ files: | |
| 49 49 | 
             
            - lib/request_log_analyzer/output/html.rb
         | 
| 50 50 | 
             
            - lib/request_log_analyzer/controller.rb
         | 
| 51 51 | 
             
            - spec/fixtures/rails_22_cached.log
         | 
| 52 | 
            -
            - lib/request_log_analyzer/file_format/rails_development.rb
         | 
| 53 52 | 
             
            - spec/lib/macros.rb
         | 
| 53 | 
            +
            - lib/request_log_analyzer/file_format/rails_development.rb
         | 
| 54 54 | 
             
            - spec/fixtures/apache_combined.log
         | 
| 55 55 | 
             
            - spec/fixtures/apache_common.log
         | 
| 56 56 | 
             
            - spec/fixtures/merb_prefixed.log
         | 
| @@ -58,6 +58,7 @@ files: | |
| 58 58 | 
             
            - spec/unit/file_format/file_format_api_spec.rb
         | 
| 59 59 | 
             
            - spec/unit/file_format/apache_format_spec.rb
         | 
| 60 60 | 
             
            - spec/integration/command_line_usage_spec.rb
         | 
| 61 | 
            +
            - lib/request_log_analyzer/database.rb
         | 
| 61 62 | 
             
            - spec/fixtures/decompression.log.bz2
         | 
| 62 63 | 
             
            - lib/request_log_analyzer/log_processor.rb
         | 
| 63 64 | 
             
            - lib/request_log_analyzer/tracker.rb
         | 
| @@ -67,18 +68,22 @@ files: | |
| 67 68 | 
             
            - request-log-analyzer.gemspec
         | 
| 68 69 | 
             
            - DESIGN.rdoc
         | 
| 69 70 | 
             
            - spec/unit/filter/timespan_filter_spec.rb
         | 
| 71 | 
            +
            - spec/unit/aggregator/database_inserter_spec.rb
         | 
| 72 | 
            +
            - spec/lib/matchers.rb
         | 
| 70 73 | 
             
            - lib/request_log_analyzer/filter/field.rb
         | 
| 71 74 | 
             
            - lib/request_log_analyzer/tracker/frequency.rb
         | 
| 72 75 | 
             
            - spec/fixtures/decompression.log.gz
         | 
| 73 76 | 
             
            - spec/fixtures/decompression.log
         | 
| 74 | 
            -
            - spec/lib/ | 
| 77 | 
            +
            - spec/lib/testing_format.rb
         | 
| 75 78 | 
             
            - spec/fixtures/test_order.log
         | 
| 79 | 
            +
            - spec/fixtures/rails.db
         | 
| 76 80 | 
             
            - lib/request_log_analyzer/output/fixed_width.rb
         | 
| 77 81 | 
             
            - lib/request_log_analyzer/filter/anonymize.rb
         | 
| 78 | 
            -
            - spec/lib/testing_format.rb
         | 
| 79 82 | 
             
            - lib/request_log_analyzer/tracker/timespan.rb
         | 
| 83 | 
            +
            - lib/request_log_analyzer/database/base.rb
         | 
| 80 84 | 
             
            - lib/request_log_analyzer/aggregator.rb
         | 
| 81 85 | 
             
            - lib/cli/progressbar.rb
         | 
| 86 | 
            +
            - lib/request_log_analyzer/mailer.rb
         | 
| 82 87 | 
             
            - README.rdoc
         | 
| 83 88 | 
             
            - spec/fixtures/merb.log
         | 
| 84 89 | 
             
            - lib/request_log_analyzer/tracker/hourly_spread.rb
         | 
| @@ -89,15 +94,17 @@ files: | |
| 89 94 | 
             
            - spec/unit/controller/log_processor_spec.rb
         | 
| 90 95 | 
             
            - spec/spec_helper.rb
         | 
| 91 96 | 
             
            - lib/request_log_analyzer.rb
         | 
| 97 | 
            +
            - spec/database.yml
         | 
| 92 98 | 
             
            - Rakefile
         | 
| 99 | 
            +
            - lib/request_log_analyzer/database/connection.rb
         | 
| 93 100 | 
             
            - spec/unit/filter/filter_spec.rb
         | 
| 101 | 
            +
            - spec/fixtures/test_language_combined.log
         | 
| 102 | 
            +
            - lib/request_log_analyzer/aggregator/database_inserter.rb
         | 
| 94 103 | 
             
            - lib/request_log_analyzer/aggregator/summarizer.rb
         | 
| 95 104 | 
             
            - lib/request_log_analyzer/file_format/rails.rb
         | 
| 96 | 
            -
            - spec/fixtures/test_language_combined.log
         | 
| 97 105 | 
             
            - spec/fixtures/decompression.tar.gz
         | 
| 98 106 | 
             
            - spec/unit/filter/field_filter_spec.rb
         | 
| 99 | 
            -
            - spec/ | 
| 100 | 
            -
            - lib/request_log_analyzer/aggregator/database.rb
         | 
| 107 | 
            +
            - spec/unit/database/base_class_spec.rb
         | 
| 101 108 | 
             
            - lib/request_log_analyzer/filter/timespan.rb
         | 
| 102 109 | 
             
            - lib/request_log_analyzer/source/log_parser.rb
         | 
| 103 110 | 
             
            - spec/fixtures/decompression.tgz
         | 
| @@ -111,19 +118,21 @@ files: | |
| 111 118 | 
             
            - spec/unit/file_format/line_definition_spec.rb
         | 
| 112 119 | 
             
            - lib/request_log_analyzer/source.rb
         | 
| 113 120 | 
             
            - lib/request_log_analyzer/request.rb
         | 
| 121 | 
            +
            - lib/cli/database_console.rb
         | 
| 122 | 
            +
            - spec/unit/database/connection_spec.rb
         | 
| 114 123 | 
             
            - spec/unit/controller/controller_spec.rb
         | 
| 124 | 
            +
            - spec/lib/mocks.rb
         | 
| 125 | 
            +
            - spec/lib/helpers.rb
         | 
| 126 | 
            +
            - lib/cli/database_console_init.rb
         | 
| 115 127 | 
             
            - lib/request_log_analyzer/output.rb
         | 
| 116 128 | 
             
            - lib/request_log_analyzer/file_format/apache.rb
         | 
| 117 | 
            -
            - spec/lib/helpers.rb
         | 
| 118 129 | 
             
            - spec/fixtures/rails_1x.log
         | 
| 119 | 
            -
            - spec/lib/mocks.rb
         | 
| 120 130 | 
             
            - spec/fixtures/decompression.log.zip
         | 
| 121 131 | 
             
            - spec/unit/source/request_spec.rb
         | 
| 122 132 | 
             
            - spec/unit/source/log_parser_spec.rb
         | 
| 123 | 
            -
            - spec/unit/aggregator/database_spec.rb
         | 
| 124 133 | 
             
            - spec/fixtures/test_file_format.log
         | 
| 125 | 
            -
            - lib/request_log_analyzer/source/database.rb
         | 
| 126 134 | 
             
            - tasks/github-gem.rake
         | 
| 135 | 
            +
            - spec/unit/database/database_spec.rb
         | 
| 127 136 | 
             
            - lib/request_log_analyzer/tracker/duration.rb
         | 
| 128 137 | 
             
            - lib/request_log_analyzer/file_format.rb
         | 
| 129 138 | 
             
            - spec/unit/aggregator/summarizer_spec.rb
         | 
| @@ -131,6 +140,7 @@ files: | |
| 131 140 | 
             
            - spec/fixtures/multiple_files_2.log
         | 
| 132 141 | 
             
            - spec/fixtures/syslog_1x.log
         | 
| 133 142 | 
             
            - LICENSE
         | 
| 143 | 
            +
            - lib/request_log_analyzer/source/database_loader.rb
         | 
| 134 144 | 
             
            - spec/unit/tracker/frequency_tracker_spec.rb
         | 
| 135 145 | 
             
            - spec/unit/file_format/rails_format_spec.rb
         | 
| 136 146 | 
             
            - lib/cli/command_line_arguments.rb
         | 
| @@ -163,29 +173,32 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 163 173 | 
             
            requirements: 
         | 
| 164 174 | 
             
            - To use the database inserter, ActiveRecord and an appropriate database adapter are required.
         | 
| 165 175 | 
             
            rubyforge_project: r-l-a
         | 
| 166 | 
            -
            rubygems_version: 1.3. | 
| 176 | 
            +
            rubygems_version: 1.3.5
         | 
| 167 177 | 
             
            signing_key: 
         | 
| 168 178 | 
             
            specification_version: 3
         | 
| 169 | 
            -
            summary: A command line tool to analyze request logs for Rails, Merb and other application servers
         | 
| 179 | 
            +
            summary: A command line tool to analyze request logs for Apache, Rails, Merb and other application servers
         | 
| 170 180 | 
             
            test_files: 
         | 
| 171 181 | 
             
            - spec/unit/filter/anonymize_filter_spec.rb
         | 
| 172 182 | 
             
            - spec/unit/file_format/file_format_api_spec.rb
         | 
| 173 183 | 
             
            - spec/unit/file_format/apache_format_spec.rb
         | 
| 174 184 | 
             
            - spec/integration/command_line_usage_spec.rb
         | 
| 175 185 | 
             
            - spec/unit/filter/timespan_filter_spec.rb
         | 
| 186 | 
            +
            - spec/unit/aggregator/database_inserter_spec.rb
         | 
| 176 187 | 
             
            - spec/unit/tracker/tracker_api_spec.rb
         | 
| 177 188 | 
             
            - spec/unit/tracker/duration_tracker_spec.rb
         | 
| 178 189 | 
             
            - spec/unit/controller/log_processor_spec.rb
         | 
| 179 190 | 
             
            - spec/unit/filter/filter_spec.rb
         | 
| 180 191 | 
             
            - spec/unit/filter/field_filter_spec.rb
         | 
| 192 | 
            +
            - spec/unit/database/base_class_spec.rb
         | 
| 181 193 | 
             
            - spec/unit/tracker/timespan_tracker_spec.rb
         | 
| 182 194 | 
             
            - spec/unit/tracker/hourly_spread_spec.rb
         | 
| 183 195 | 
             
            - spec/unit/file_format/merb_format_spec.rb
         | 
| 184 196 | 
             
            - spec/unit/file_format/line_definition_spec.rb
         | 
| 197 | 
            +
            - spec/unit/database/connection_spec.rb
         | 
| 185 198 | 
             
            - spec/unit/controller/controller_spec.rb
         | 
| 186 199 | 
             
            - spec/unit/source/request_spec.rb
         | 
| 187 200 | 
             
            - spec/unit/source/log_parser_spec.rb
         | 
| 188 | 
            -
            - spec/unit/ | 
| 201 | 
            +
            - spec/unit/database/database_spec.rb
         | 
| 189 202 | 
             
            - spec/unit/aggregator/summarizer_spec.rb
         | 
| 190 203 | 
             
            - spec/unit/tracker/frequency_tracker_spec.rb
         | 
| 191 204 | 
             
            - spec/unit/file_format/rails_format_spec.rb
         |