Commit 2e283c5d667f0c9324b06a78454b651eca481e4f
1 parent
a3ed065c
Exists in
master
and in
1 other branch
Refactor the problem merge system
* Extract the Problem#merge! in his own class * Extract the update cache system from problem in his own class * Welcome back to the backtrace_line_spec not found by a rspec spec because no end by _spec.rb
Showing
11 changed files
with
365 additions
and
84 deletions
Show diff stats
| @@ -0,0 +1,26 @@ | @@ -0,0 +1,26 @@ | ||
| 1 | +require 'problem_destroy' | ||
| 2 | + | ||
| 3 | +class ProblemMerge | ||
| 4 | + def initialize(*problems) | ||
| 5 | + problems = problems.flatten.uniq | ||
| 6 | + @merged_problem = problems[0] | ||
| 7 | + @child_problems = problems[1..-1] | ||
| 8 | + raise ArgumentError.new("need almost 2 uniq different problems") if @child_problems.empty? | ||
| 9 | + end | ||
| 10 | + attr_reader :merged_problem, :child_problems | ||
| 11 | + | ||
| 12 | + def merge | ||
| 13 | + child_problems.each do |problem| | ||
| 14 | + merged_problem.errs.concat Err.where(:problem_id => problem.id) | ||
| 15 | + ProblemDestroy.execute(problem) | ||
| 16 | + end | ||
| 17 | + reset_cached_attributes | ||
| 18 | + merged_problem | ||
| 19 | + end | ||
| 20 | + | ||
| 21 | + private | ||
| 22 | + | ||
| 23 | + def reset_cached_attributes | ||
| 24 | + ProblemUpdaterCache.new(merged_problem).update | ||
| 25 | + end | ||
| 26 | +end |
| @@ -0,0 +1,90 @@ | @@ -0,0 +1,90 @@ | ||
| 1 | +class ProblemUpdaterCache | ||
| 2 | + def initialize(problem, notice=nil) | ||
| 3 | + @problem = problem | ||
| 4 | + @notice = notice | ||
| 5 | + end | ||
| 6 | + attr_reader :problem | ||
| 7 | + | ||
| 8 | + ## | ||
| 9 | + # Update cache information about child associate to this problem | ||
| 10 | + # | ||
| 11 | + # update the notices count, and some notice informations | ||
| 12 | + # | ||
| 13 | + # @return [ Problem ] the problem with this update | ||
| 14 | + # | ||
| 15 | + def update | ||
| 16 | + update_notices_count | ||
| 17 | + update_notices_cache | ||
| 18 | + problem | ||
| 19 | + end | ||
| 20 | + | ||
| 21 | + private | ||
| 22 | + | ||
| 23 | + def update_notices_count | ||
| 24 | + if @notice | ||
| 25 | + problem.inc(:notices_count, 1) | ||
| 26 | + else | ||
| 27 | + problem.update_attribute( | ||
| 28 | + :notices_count, problem.notices.count | ||
| 29 | + ) | ||
| 30 | + end | ||
| 31 | + end | ||
| 32 | + | ||
| 33 | + ## | ||
| 34 | + # Update problem statistique from some notice information | ||
| 35 | + # | ||
| 36 | + def update_notices_cache | ||
| 37 | + first_notice = notices.first | ||
| 38 | + last_notice = notices.last | ||
| 39 | + notice ||= @notice || first_notice | ||
| 40 | + | ||
| 41 | + attrs = {} | ||
| 42 | + attrs[:first_notice_at] = first_notice.created_at if first_notice | ||
| 43 | + attrs[:last_notice_at] = last_notice.created_at if last_notice | ||
| 44 | + attrs.merge!( | ||
| 45 | + :message => notice.message, | ||
| 46 | + :environment => notice.environment_name, | ||
| 47 | + :error_class => notice.error_class, | ||
| 48 | + :where => notice.where, | ||
| 49 | + :messages => attribute_count(:message, messages), | ||
| 50 | + :hosts => attribute_count(:host, hosts), | ||
| 51 | + :user_agents => attribute_count(:user_agent_string, user_agents) | ||
| 52 | + ) if notice | ||
| 53 | + problem.update_attributes!(attrs) | ||
| 54 | + end | ||
| 55 | + | ||
| 56 | + def notices | ||
| 57 | + @notices ||= @notice ? [@notice].sort(&:created_at) : problem.notices.order_by([:created_at, :asc]) | ||
| 58 | + end | ||
| 59 | + | ||
| 60 | + def messages | ||
| 61 | + @notice ? problem.messages : {} | ||
| 62 | + end | ||
| 63 | + | ||
| 64 | + def hosts | ||
| 65 | + @notice ? problem.hosts : {} | ||
| 66 | + end | ||
| 67 | + | ||
| 68 | + def user_agents | ||
| 69 | + @notice ? problem.user_agents : {} | ||
| 70 | + end | ||
| 71 | + | ||
| 72 | + private | ||
| 73 | + | ||
| 74 | + def attribute_count(value, init) | ||
| 75 | + init.tap do |counts| | ||
| 76 | + notices.each do |notice| | ||
| 77 | + counts[attribute_index(notice.send(value))] ||= { | ||
| 78 | + 'value' => notice.send(value), | ||
| 79 | + 'count' => 0 | ||
| 80 | + } | ||
| 81 | + counts[attribute_index(notice.send(value))]['count'] += 1 | ||
| 82 | + end | ||
| 83 | + end | ||
| 84 | + end | ||
| 85 | + | ||
| 86 | + def attribute_index(value) | ||
| 87 | + @attributes_index ||= {} | ||
| 88 | + @attributes_index[value.to_s] ||= Digest::MD5.hexdigest(value.to_s) | ||
| 89 | + end | ||
| 90 | +end |
app/models/notice.rb
| @@ -26,7 +26,7 @@ class Notice | @@ -26,7 +26,7 @@ class Notice | ||
| 26 | ] | 26 | ] |
| 27 | ) | 27 | ) |
| 28 | 28 | ||
| 29 | - after_create :increase_counter_cache, :cache_attributes_on_problem, :unresolve_problem | 29 | + after_create :cache_attributes_on_problem, :unresolve_problem |
| 30 | before_save :sanitize | 30 | before_save :sanitize |
| 31 | before_destroy :decrease_counter_cache, :remove_cached_attributes_from_problem | 31 | before_destroy :decrease_counter_cache, :remove_cached_attributes_from_problem |
| 32 | 32 | ||
| @@ -116,10 +116,6 @@ class Notice | @@ -116,10 +116,6 @@ class Notice | ||
| 116 | 116 | ||
| 117 | protected | 117 | protected |
| 118 | 118 | ||
| 119 | - def increase_counter_cache | ||
| 120 | - problem.inc(:notices_count, 1) | ||
| 121 | - end | ||
| 122 | - | ||
| 123 | def decrease_counter_cache | 119 | def decrease_counter_cache |
| 124 | problem.inc(:notices_count, -1) if err | 120 | problem.inc(:notices_count, -1) if err |
| 125 | end | 121 | end |
| @@ -133,7 +129,7 @@ class Notice | @@ -133,7 +129,7 @@ class Notice | ||
| 133 | end | 129 | end |
| 134 | 130 | ||
| 135 | def cache_attributes_on_problem | 131 | def cache_attributes_on_problem |
| 136 | - problem.cache_notice_attributes(self) | 132 | + ProblemUpdaterCache.new(problem, self).update |
| 137 | end | 133 | end |
| 138 | 134 | ||
| 139 | def sanitize | 135 | def sanitize |
app/models/problem.rb
| @@ -83,15 +83,7 @@ class Problem | @@ -83,15 +83,7 @@ class Problem | ||
| 83 | 83 | ||
| 84 | 84 | ||
| 85 | def self.merge!(*problems) | 85 | def self.merge!(*problems) |
| 86 | - problems = problems.flatten.uniq | ||
| 87 | - merged_problem = problems.shift | ||
| 88 | - problems.each do |problem| | ||
| 89 | - merged_problem.errs.concat Err.where(:problem_id => problem.id) | ||
| 90 | - problem.errs(true) # reload problem.errs (should be empty) before problem.destroy | ||
| 91 | - problem.destroy | ||
| 92 | - end | ||
| 93 | - merged_problem.reset_cached_attributes | ||
| 94 | - merged_problem | 86 | + ProblemMerge.new(problems).merge |
| 95 | end | 87 | end |
| 96 | 88 | ||
| 97 | def merged? | 89 | def merged? |
| @@ -128,9 +120,7 @@ class Problem | @@ -128,9 +120,7 @@ class Problem | ||
| 128 | 120 | ||
| 129 | 121 | ||
| 130 | def reset_cached_attributes | 122 | def reset_cached_attributes |
| 131 | - update_attribute(:notices_count, notices.count) | ||
| 132 | - cache_app_attributes | ||
| 133 | - cache_notice_attributes | 123 | + ProblemUpdaterCache.new(self).update |
| 134 | end | 124 | end |
| 135 | 125 | ||
| 136 | def cache_app_attributes | 126 | def cache_app_attributes |
| @@ -145,26 +135,6 @@ class Problem | @@ -145,26 +135,6 @@ class Problem | ||
| 145 | end | 135 | end |
| 146 | end | 136 | end |
| 147 | 137 | ||
| 148 | - def cache_notice_attributes(notice=nil) | ||
| 149 | - first_notice = notices.order_by([:created_at, :asc]).first | ||
| 150 | - last_notice = notices.order_by([:created_at, :asc]).last | ||
| 151 | - notice ||= first_notice | ||
| 152 | - | ||
| 153 | - attrs = {} | ||
| 154 | - attrs[:first_notice_at] = first_notice.created_at if first_notice | ||
| 155 | - attrs[:last_notice_at] = last_notice.created_at if last_notice | ||
| 156 | - attrs.merge!( | ||
| 157 | - :message => notice.message, | ||
| 158 | - :environment => notice.environment_name, | ||
| 159 | - :error_class => notice.error_class, | ||
| 160 | - :where => notice.where, | ||
| 161 | - :messages => attribute_count_increase(:messages, notice.message), | ||
| 162 | - :hosts => attribute_count_increase(:hosts, notice.host), | ||
| 163 | - :user_agents => attribute_count_increase(:user_agents, notice.user_agent_string) | ||
| 164 | - ) if notice | ||
| 165 | - update_attributes!(attrs) | ||
| 166 | - end | ||
| 167 | - | ||
| 168 | def remove_cached_notice_attributes(notice) | 138 | def remove_cached_notice_attributes(notice) |
| 169 | update_attributes!( | 139 | update_attributes!( |
| 170 | :messages => attribute_count_descrease(:messages, notice.message), | 140 | :messages => attribute_count_descrease(:messages, notice.message), |
| @@ -184,15 +154,6 @@ class Problem | @@ -184,15 +154,6 @@ class Problem | ||
| 184 | end | 154 | end |
| 185 | 155 | ||
| 186 | private | 156 | private |
| 187 | - def attribute_count_increase(name, value) | ||
| 188 | - counter, index = send(name), attribute_index(value) | ||
| 189 | - if counter[index].nil? | ||
| 190 | - counter[index] = {'value' => value, 'count' => 1} | ||
| 191 | - else | ||
| 192 | - counter[index]['count'] += 1 | ||
| 193 | - end | ||
| 194 | - counter | ||
| 195 | - end | ||
| 196 | 157 | ||
| 197 | def attribute_count_descrease(name, value) | 158 | def attribute_count_descrease(name, value) |
| 198 | counter, index = send(name), attribute_index(value) | 159 | counter, index = send(name), attribute_index(value) |
lib/tasks/errbit/database.rake
| @@ -6,7 +6,9 @@ namespace :errbit do | @@ -6,7 +6,9 @@ namespace :errbit do | ||
| 6 | desc "Updates cached attributes on Problem" | 6 | desc "Updates cached attributes on Problem" |
| 7 | task :update_problem_attrs => :environment do | 7 | task :update_problem_attrs => :environment do |
| 8 | puts "Updating problems" | 8 | puts "Updating problems" |
| 9 | - Problem.all.each(&:cache_notice_attributes) | 9 | + Problem.all.each{|problem| |
| 10 | + ProblemUpdaterCache.new(self).update | ||
| 11 | + } | ||
| 10 | end | 12 | end |
| 11 | 13 | ||
| 12 | desc "Updates Problem#notices_count" | 14 | desc "Updates Problem#notices_count" |
spec/fabricators/problem_fabricator.rb
| @@ -10,3 +10,13 @@ Fabricator(:problem_with_comments, :from => :problem) do | @@ -10,3 +10,13 @@ Fabricator(:problem_with_comments, :from => :problem) do | ||
| 10 | end | 10 | end |
| 11 | } | 11 | } |
| 12 | end | 12 | end |
| 13 | + | ||
| 14 | +Fabricator(:problem_with_errs, :from => :problem) do | ||
| 15 | + after_create { |parent| | ||
| 16 | + 3.times do | ||
| 17 | + Fabricate(:err, :problem => parent) | ||
| 18 | + end | ||
| 19 | + } | ||
| 20 | +end | ||
| 21 | + | ||
| 22 | + |
| @@ -0,0 +1,48 @@ | @@ -0,0 +1,48 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe ProblemMerge do | ||
| 4 | + let(:problem) { Fabricate(:problem_with_errs) } | ||
| 5 | + let(:problem_1) { Fabricate(:problem_with_errs) } | ||
| 6 | + | ||
| 7 | + describe "#initialize" do | ||
| 8 | + it 'failed if less than 2 uniq problem pass in args' do | ||
| 9 | + expect { | ||
| 10 | + ProblemMerge.new(problem) | ||
| 11 | + }.to raise_error(ArgumentError) | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + it 'extract first problem like merged_problem' do | ||
| 15 | + problem_merge = ProblemMerge.new(problem, problem, problem_1) | ||
| 16 | + expect(problem_merge.merged_problem).to eql problem | ||
| 17 | + end | ||
| 18 | + it 'extract other problem like child_problems' do | ||
| 19 | + problem_merge = ProblemMerge.new(problem, problem, problem_1) | ||
| 20 | + expect(problem_merge.child_problems).to eql [problem_1] | ||
| 21 | + end | ||
| 22 | + end | ||
| 23 | + | ||
| 24 | + describe "#merge" do | ||
| 25 | + let!(:problem_merge) { | ||
| 26 | + ProblemMerge.new(problem, problem_1) | ||
| 27 | + } | ||
| 28 | + let(:first_errs) { problem.errs } | ||
| 29 | + let(:merged_errs) { problem_1.errs } | ||
| 30 | + let!(:notice) { Fabricate(:notice, :err => first_errs.first) } | ||
| 31 | + let!(:notice_1) { Fabricate(:notice, :err => merged_errs.first) } | ||
| 32 | + it 'delete one of problem' do | ||
| 33 | + expect { | ||
| 34 | + problem_merge.merge | ||
| 35 | + }.to change(Problem, :count).by(-1) | ||
| 36 | + end | ||
| 37 | + | ||
| 38 | + it 'move all err in one problem' do | ||
| 39 | + problem_merge.merge | ||
| 40 | + problem.reload.errs.should eq (first_errs | merged_errs) | ||
| 41 | + end | ||
| 42 | + | ||
| 43 | + it 'update problem cache' do | ||
| 44 | + ProblemUpdaterCache.should_receive(:new).with(problem).and_return(mock(:update => true)) | ||
| 45 | + problem_merge.merge | ||
| 46 | + end | ||
| 47 | + end | ||
| 48 | +end |
| @@ -0,0 +1,153 @@ | @@ -0,0 +1,153 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe ProblemUpdaterCache do | ||
| 4 | + let(:problem) { Fabricate(:problem_with_errs) } | ||
| 5 | + let(:first_errs) { problem.errs } | ||
| 6 | + let!(:notice) { Fabricate(:notice, :err => first_errs.first) } | ||
| 7 | + | ||
| 8 | + describe "#update" do | ||
| 9 | + context "without notice pass args" do | ||
| 10 | + before do | ||
| 11 | + problem.update_attribute(:notices_count, 0) | ||
| 12 | + end | ||
| 13 | + | ||
| 14 | + it 'update the notice_count' do | ||
| 15 | + expect { | ||
| 16 | + ProblemUpdaterCache.new(problem).update | ||
| 17 | + }.to change{ | ||
| 18 | + problem.notices_count | ||
| 19 | + }.from(0).to(1) | ||
| 20 | + end | ||
| 21 | + | ||
| 22 | + context "with only one notice" do | ||
| 23 | + before do | ||
| 24 | + problem.update_attributes!(:messages => {}) | ||
| 25 | + ProblemUpdaterCache.new(problem).update | ||
| 26 | + end | ||
| 27 | + | ||
| 28 | + it 'update information about this notice' do | ||
| 29 | + expect(problem.message).to eq notice.message | ||
| 30 | + expect(problem.environment).to eq notice.environment_name | ||
| 31 | + expect(problem.error_class).to eq notice.error_class | ||
| 32 | + expect(problem.where).to eq notice.where | ||
| 33 | + end | ||
| 34 | + | ||
| 35 | + it 'update first_notice_at' do | ||
| 36 | + expect(problem.first_notice_at).to eq notice.created_at | ||
| 37 | + end | ||
| 38 | + | ||
| 39 | + it 'update last_notice_at' do | ||
| 40 | + expect(problem.last_notice_at).to eq notice.created_at | ||
| 41 | + end | ||
| 42 | + | ||
| 43 | + it 'update stats messages' do | ||
| 44 | + expect(problem.messages).to eq({ | ||
| 45 | + Digest::MD5.hexdigest(notice.message) => {'value' => notice.message, 'count' => 1} | ||
| 46 | + }) | ||
| 47 | + end | ||
| 48 | + | ||
| 49 | + it 'update stats hosts' do | ||
| 50 | + expect(problem.hosts).to eq({ | ||
| 51 | + Digest::MD5.hexdigest(notice.host) => {'value' => notice.host, 'count' => 1} | ||
| 52 | + }) | ||
| 53 | + end | ||
| 54 | + | ||
| 55 | + it 'update stats user_agents' do | ||
| 56 | + expect(problem.user_agents).to eq({ | ||
| 57 | + Digest::MD5.hexdigest(notice.user_agent_string) => {'value' => notice.user_agent_string, 'count' => 1} | ||
| 58 | + }) | ||
| 59 | + end | ||
| 60 | + end | ||
| 61 | + | ||
| 62 | + context "with several notices" do | ||
| 63 | + let!(:notice_2) { Fabricate(:notice, :err => first_errs.first) } | ||
| 64 | + let!(:notice_3) { Fabricate(:notice, :err => first_errs.first) } | ||
| 65 | + before do | ||
| 66 | + problem.update_attributes!(:messages => {}) | ||
| 67 | + ProblemUpdaterCache.new(problem).update | ||
| 68 | + end | ||
| 69 | + it 'update information about this notice' do | ||
| 70 | + expect(problem.message).to eq notice.message | ||
| 71 | + expect(problem.environment).to eq notice.environment_name | ||
| 72 | + expect(problem.error_class).to eq notice.error_class | ||
| 73 | + expect(problem.where).to eq notice.where | ||
| 74 | + end | ||
| 75 | + | ||
| 76 | + it 'update first_notice_at' do | ||
| 77 | + expect(problem.first_notice_at.to_time).to eq notice.created_at.to_time | ||
| 78 | + end | ||
| 79 | + | ||
| 80 | + it 'update last_notice_at' do | ||
| 81 | + expect(problem.last_notice_at.to_i).to be_within(1).of(notice.created_at.to_i) | ||
| 82 | + end | ||
| 83 | + | ||
| 84 | + it 'update stats messages' do | ||
| 85 | + expect(problem.messages).to eq({ | ||
| 86 | + Digest::MD5.hexdigest(notice.message) => {'value' => notice.message, 'count' => 3} | ||
| 87 | + }) | ||
| 88 | + end | ||
| 89 | + | ||
| 90 | + it 'update stats hosts' do | ||
| 91 | + expect(problem.hosts).to eq({ | ||
| 92 | + Digest::MD5.hexdigest(notice.host) => {'value' => notice.host, 'count' => 3} | ||
| 93 | + }) | ||
| 94 | + end | ||
| 95 | + | ||
| 96 | + it 'update stats user_agents' do | ||
| 97 | + expect(problem.user_agents).to eq({ | ||
| 98 | + Digest::MD5.hexdigest(notice.user_agent_string) => {'value' => notice.user_agent_string, 'count' => 3} | ||
| 99 | + }) | ||
| 100 | + end | ||
| 101 | + | ||
| 102 | + end | ||
| 103 | + end | ||
| 104 | + | ||
| 105 | + context "with notice pass in args" do | ||
| 106 | + | ||
| 107 | + before do | ||
| 108 | + ProblemUpdaterCache.new(problem, notice).update | ||
| 109 | + end | ||
| 110 | + | ||
| 111 | + it 'increase notices_count by 1' do | ||
| 112 | + expect { | ||
| 113 | + ProblemUpdaterCache.new(problem, notice).update | ||
| 114 | + }.to change{ | ||
| 115 | + problem.notices_count | ||
| 116 | + }.by(1) | ||
| 117 | + end | ||
| 118 | + | ||
| 119 | + it 'update information about this notice' do | ||
| 120 | + expect(problem.message).to eq notice.message | ||
| 121 | + expect(problem.environment).to eq notice.environment_name | ||
| 122 | + expect(problem.error_class).to eq notice.error_class | ||
| 123 | + expect(problem.where).to eq notice.where | ||
| 124 | + end | ||
| 125 | + | ||
| 126 | + it 'update first_notice_at' do | ||
| 127 | + expect(problem.first_notice_at).to eq notice.created_at | ||
| 128 | + end | ||
| 129 | + | ||
| 130 | + it 'update last_notice_at' do | ||
| 131 | + expect(problem.last_notice_at).to eq notice.created_at | ||
| 132 | + end | ||
| 133 | + | ||
| 134 | + it 'inc stats messages' do | ||
| 135 | + expect(problem.messages).to eq({ | ||
| 136 | + Digest::MD5.hexdigest(notice.message) => {'value' => notice.message, 'count' => 2} | ||
| 137 | + }) | ||
| 138 | + end | ||
| 139 | + | ||
| 140 | + it 'inc stats hosts' do | ||
| 141 | + expect(problem.hosts).to eq({ | ||
| 142 | + Digest::MD5.hexdigest(notice.host) => {'value' => notice.host, 'count' => 2} | ||
| 143 | + }) | ||
| 144 | + end | ||
| 145 | + | ||
| 146 | + it 'inc stats user_agents' do | ||
| 147 | + expect(problem.user_agents).to eq({ | ||
| 148 | + Digest::MD5.hexdigest(notice.user_agent_string) => {'value' => notice.user_agent_string, 'count' => 2} | ||
| 149 | + }) | ||
| 150 | + end | ||
| 151 | + end | ||
| 152 | + end | ||
| 153 | +end |
spec/models/backtrace_line.rb
| @@ -1,12 +0,0 @@ | @@ -1,12 +0,0 @@ | ||
| 1 | -require 'spec_helper' | ||
| 2 | - | ||
| 3 | -describe BacktraceLine do | ||
| 4 | - subject { described_class.new(raw_line) } | ||
| 5 | - | ||
| 6 | - describe "root at the start of decorated filename" do | ||
| 7 | - let(:raw_line) { { 'number' => rand(999), 'file' => '[PROJECT_ROOT]/app/controllers/pages_controller.rb', 'method' => ActiveSupport.methods.shuffle.first.to_s } } | ||
| 8 | - it "should leave leading root symbol in filepath" do | ||
| 9 | - subject.decorated_path.should == '/app/controllers/' | ||
| 10 | - end | ||
| 11 | - end | ||
| 12 | -end |
| @@ -0,0 +1,12 @@ | @@ -0,0 +1,12 @@ | ||
| 1 | +require 'spec_helper' | ||
| 2 | + | ||
| 3 | +describe BacktraceLine do | ||
| 4 | + subject { described_class.new(raw_line) } | ||
| 5 | + | ||
| 6 | + describe "root at the start of decorated filename" do | ||
| 7 | + let(:raw_line) { { 'number' => rand(999), 'file' => '[PROJECT_ROOT]/app/controllers/pages_controller.rb', 'method' => ActiveSupport.methods.shuffle.first.to_s } } | ||
| 8 | + it "should leave leading root symbol in filepath" do | ||
| 9 | + subject.decorated_path.should == 'app/controllers/' | ||
| 10 | + end | ||
| 11 | + end | ||
| 12 | +end |
spec/models/problem_spec.rb
| @@ -23,6 +23,17 @@ describe Problem do | @@ -23,6 +23,17 @@ describe Problem do | ||
| 23 | end.should change(Comment, :count).by(3) | 23 | end.should change(Comment, :count).by(3) |
| 24 | end | 24 | end |
| 25 | end | 25 | end |
| 26 | + | ||
| 27 | + context "Fabricate(:problem_with_errs)" do | ||
| 28 | + it 'should be valid' do | ||
| 29 | + Fabricate.build(:problem_with_errs).should be_valid | ||
| 30 | + end | ||
| 31 | + it 'should have 3 errs' do | ||
| 32 | + lambda do | ||
| 33 | + Fabricate(:problem_with_errs) | ||
| 34 | + end.should change(Err, :count).by(3) | ||
| 35 | + end | ||
| 36 | + end | ||
| 26 | end | 37 | end |
| 27 | 38 | ||
| 28 | context '#last_notice_at' do | 39 | context '#last_notice_at' do |
| @@ -49,7 +60,7 @@ describe Problem do | @@ -49,7 +60,7 @@ describe Problem do | ||
| 49 | problem.first_notice_at.should == notice1.created_at | 60 | problem.first_notice_at.should == notice1.created_at |
| 50 | 61 | ||
| 51 | notice2 = Fabricate(:notice, :err => err) | 62 | notice2 = Fabricate(:notice, :err => err) |
| 52 | - problem.first_notice_at.should == notice1.created_at | 63 | + problem.first_notice_at.to_time.should eq notice1.created_at |
| 53 | end | 64 | end |
| 54 | end | 65 | end |
| 55 | 66 | ||
| @@ -134,22 +145,6 @@ describe Problem do | @@ -134,22 +145,6 @@ describe Problem do | ||
| 134 | end | 145 | end |
| 135 | end | 146 | end |
| 136 | 147 | ||
| 137 | - | ||
| 138 | - context ".merge!" do | ||
| 139 | - it "collects the Errs from several problems into one and deletes the other problems" do | ||
| 140 | - problem1 = Fabricate(:err).problem | ||
| 141 | - problem2 = Fabricate(:err).problem | ||
| 142 | - problem1.errs.length.should == 1 | ||
| 143 | - problem2.errs.length.should == 1 | ||
| 144 | - | ||
| 145 | - lambda { | ||
| 146 | - merged_problem = Problem.merge!(problem1, problem2) | ||
| 147 | - merged_problem.reload.errs.length.should == 2 | ||
| 148 | - }.should change(Problem, :count).by(-1) | ||
| 149 | - end | ||
| 150 | - end | ||
| 151 | - | ||
| 152 | - | ||
| 153 | context "#unmerge!" do | 148 | context "#unmerge!" do |
| 154 | it "creates a separate problem for each err" do | 149 | it "creates a separate problem for each err" do |
| 155 | problem1 = Fabricate(:notice).problem | 150 | problem1 = Fabricate(:notice).problem |
| @@ -188,17 +183,17 @@ describe Problem do | @@ -188,17 +183,17 @@ describe Problem do | ||
| 188 | 183 | ||
| 189 | context "searching" do | 184 | context "searching" do |
| 190 | it 'finds the correct record' do | 185 | it 'finds the correct record' do |
| 191 | - find = Fabricate(:problem, :resolved => false, :error_class => 'theErrorclass::other', | 186 | + find = Fabricate(:problem, :resolved => false, :error_class => 'theErrorclass::other', |
| 192 | :message => "other", :where => 'errorclass', :environment => 'development', :app_name => 'other') | 187 | :message => "other", :where => 'errorclass', :environment => 'development', :app_name => 'other') |
| 193 | - dont_find = Fabricate(:problem, :resolved => false, :error_class => "Batman", | 188 | + dont_find = Fabricate(:problem, :resolved => false, :error_class => "Batman", |
| 194 | :message => 'todo', :where => 'classerror', :environment => 'development', :app_name => 'other') | 189 | :message => 'todo', :where => 'classerror', :environment => 'development', :app_name => 'other') |
| 195 | Problem.search("theErrorClass").unresolved.should include(find) | 190 | Problem.search("theErrorClass").unresolved.should include(find) |
| 196 | Problem.search("theErrorClass").unresolved.should_not include(dont_find) | 191 | Problem.search("theErrorClass").unresolved.should_not include(dont_find) |
| 197 | end | 192 | end |
| 198 | end | 193 | end |
| 199 | end | 194 | end |
| 200 | - | ||
| 201 | - | 195 | + |
| 196 | + | ||
| 202 | context "notice counter cache" do | 197 | context "notice counter cache" do |
| 203 | before do | 198 | before do |
| 204 | @app = Fabricate(:app) | 199 | @app = Fabricate(:app) |
| @@ -213,15 +208,15 @@ describe Problem do | @@ -213,15 +208,15 @@ describe Problem do | ||
| 213 | it "adding a notice increases #notices_count by 1" do | 208 | it "adding a notice increases #notices_count by 1" do |
| 214 | lambda { | 209 | lambda { |
| 215 | Fabricate(:notice, :err => @err, :message => 'ERR 1') | 210 | Fabricate(:notice, :err => @err, :message => 'ERR 1') |
| 216 | - }.should change(@problem, :notices_count).from(0).to(1) | 211 | + }.should change(@problem.reload, :notices_count).from(0).to(1) |
| 217 | end | 212 | end |
| 218 | 213 | ||
| 219 | it "removing a notice decreases #notices_count by 1" do | 214 | it "removing a notice decreases #notices_count by 1" do |
| 220 | notice1 = Fabricate(:notice, :err => @err, :message => 'ERR 1') | 215 | notice1 = Fabricate(:notice, :err => @err, :message => 'ERR 1') |
| 221 | - lambda { | 216 | + expect { |
| 222 | @err.notices.first.destroy | 217 | @err.notices.first.destroy |
| 223 | @problem.reload | 218 | @problem.reload |
| 224 | - }.should change(@problem, :notices_count).from(1).to(0) | 219 | + }.to change(@problem, :notices_count).from(1).to(0) |
| 225 | end | 220 | end |
| 226 | end | 221 | end |
| 227 | 222 |