Code review comment for lp:~julian-edwards/launchpad/buildd-failure-counting

Revision history for this message
Julian Edwards (julian-edwards) wrote :

On Monday 23 August 2010 18:34:43 Jonathan Lange wrote:
> I would argue that most things that manipulate state on object X
> should be methods of object X. I would not say it's a universal rule.

If we boil it down to the basic manipulation required, I completely agree.

> I think you have, in this case, particularly given the concessions
> below to have methods on Job (however it's spelled) and Builder that
> do the failure incrementing. That seems like a clean division of
> responsibility.

Woot! :)

> > I'd prefer to have a gotFailure() on each of Builder and BuildFarmJob and
> > have the build manager call each in turn.
> >
> > Let me know if you think that is acceptable and I'll do that change (it's
> > not in the attached diff).
>
> I think that's a great idea.

Ok it's done.

> Re robustness, I think you lose one kind of robustness and gain another.

I guess there are different ways of looking at it...

> "Was this method called?" tests are robust against behaviour change.
> If you change what assessFailureCounts is supposed to do, then you
> won't have to change these tests, only the assessFailureCounts ones.
> (Some people call this "Mockist")
>
> Tests that check state are robust against implementation change. If
> you change the details of how you've implemented the code (as you've
> done during this review process), you won't have to change any tests.
> (Some people call this "Classic")
>
> As a rule, I lean heavily toward the latter, since I change
> implementation details much more frequently than behaviour. I use
> mocks in situations where there's a very clearly defined, fairly
> stable interface and when using some other kind of double would be
> prohibitively difficult.
>
> See http://martinfowler.com/articles/mocksArentStubs.html for a good
> discussion on the whole topic.
>
> As far as this diff goes, I think using a mock is less preferable but
> still sound, and I'm happy to see it merged.

I think I'm in total agreement with the sentiment above. In my case here I am
trying to abstract away from the "how failures are counted" as much as
possible since I forsee some changes in how we make it work. I suspect that
this branch will not be the final word on the matter :)

> It seems to me that Builder.currentjob ought to be replaced with a
> method asap, since it's doing a query, and naive readers might well
> miss that fact.

Agreed, I've filed a bug though as after grepping around, it will be a big
diff and I don't want to pollute this branch.

> If it's doing dupe queries and you aren't going to change currentjob
> to a method in this branch, then please add a comment saying something
> like:
>
> # builder.currentjob runs a query. Don't run it twice.

Done!

See partial diff.

Thanks for sticking with me :)

1=== modified file 'lib/lp/buildmaster/interfaces/builder.py'
2--- lib/lp/buildmaster/interfaces/builder.py 2010-08-20 13:47:47 +0000
3+++ lib/lp/buildmaster/interfaces/builder.py 2010-08-24 09:55:13 +0000
4@@ -154,6 +154,12 @@
5 title=u"The current behavior of the builder for the current job.",
6 required=False)
7
8+ def gotFailure():
9+ """Increment failure_count on the builder."""
10+
11+ def resetFailureCount():
12+ """Set the failure_count back to zero."""
13+
14 def checkSlaveAlive():
15 """Check that the buildd slave is alive.
16
17
18=== modified file 'lib/lp/buildmaster/interfaces/buildfarmjob.py'
19--- lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-07-23 20:27:27 +0000
20+++ lib/lp/buildmaster/interfaces/buildfarmjob.py 2010-08-24 10:01:21 +0000
21@@ -270,6 +270,9 @@
22 returned.
23 """
24
25+ def gotFailure():
26+ """Increment the failure_count for this job."""
27+
28 title = exported(TextLine(title=_("Title"), required=False))
29
30 was_built = Attribute("Whether or not modified by the builddfarm.")
31
32=== modified file 'lib/lp/buildmaster/manager.py'
33--- lib/lp/buildmaster/manager.py 2010-08-20 13:42:19 +0000
34+++ lib/lp/buildmaster/manager.py 2010-08-24 10:27:37 +0000
35@@ -150,6 +150,8 @@
36
37 def assessFailureCounts(builder, fail_notes):
38 """View builder/job failure_count and work out which needs to die. """
39+ # builder.currentjob hides a complicated query, don't run it twice.
40+ # See bug 623281.
41 current_job = builder.currentjob
42 build_job = current_job.specific_job.build
43
44@@ -361,7 +363,7 @@
45 if self.builder.currentjob is not None:
46 # After a successful dispatch we can reset the
47 # failure_count.
48- self.builder.failure_count = 0
49+ self.builder.resetFailureCount()
50 transaction.commit()
51 return slave
52
53@@ -493,8 +495,8 @@
54 return self.reset_result(slave, error_text)
55
56 def _incrementFailureCounts(self, builder):
57- builder.failure_count += 1
58- builder.getCurrentBuildFarmJob().failure_count += 1
59+ builder.gotFailure()
60+ builder.getCurrentBuildFarmJob().gotFailure()
61
62 def checkDispatch(self, response, method, slave):
63 """Verify the results of a slave xmlrpc call.
64
65=== modified file 'lib/lp/buildmaster/model/builder.py'
66--- lib/lp/buildmaster/model/builder.py 2010-08-20 13:47:47 +0000
67+++ lib/lp/buildmaster/model/builder.py 2010-08-24 10:15:31 +0000
68@@ -294,6 +294,14 @@
69 current_build_behavior = property(
70 _getCurrentBuildBehavior, _setCurrentBuildBehavior)
71
72+ def gotFailure(self):
73+ """See `IBuilder`."""
74+ self.failure_count += 1
75+
76+ def resetFailureCount(self):
77+ """See `IBuilder`."""
78+ self.failure_count = 0
79+
80 def checkSlaveAlive(self):
81 """See IBuilder."""
82 if self.slave.echo("Test")[0] != "Test":
83@@ -311,6 +319,8 @@
84 """See IBuilder."""
85 return self.slave.clean()
86
87+ # XXX 2010-08-24 Julian bug=623281
88+ # This should not be a property! It's masking a complicated query.
89 @property
90 def currentjob(self):
91 """See IBuilder"""
92
93=== modified file 'lib/lp/buildmaster/model/buildfarmjob.py'
94--- lib/lp/buildmaster/model/buildfarmjob.py 2010-08-17 15:04:47 +0000
95+++ lib/lp/buildmaster/model/buildfarmjob.py 2010-08-24 10:00:34 +0000
96@@ -344,6 +344,10 @@
97
98 return build_without_outer_proxy
99
100+ def gotFailure(self):
101+ """See `IBuildFarmJob`."""
102+ self.failure_count += 1
103+
104
105 class BuildFarmJobDerived:
106 implements(IBuildFarmJob)

« Back to merge proposal