Merge lp:~dpb/latch-test/dont-test-so-much into lp:latch-test

Proposed by David Britton
Status: Merged
Approved by: David Britton
Approved revision: 21
Merged at revision: 14
Proposed branch: lp:~dpb/latch-test/dont-test-so-much
Merge into: lp:latch-test
Diff against target: 237 lines (+98/-24)
2 files modified
latch.py (+43/-7)
test_latch.py (+55/-17)
To merge this branch: bzr merge lp:~dpb/latch-test/dont-test-so-much
Reviewer Review Type Date Requested Status
Данило Шеган (community) Approve
🤖 Landscape Builder test results Approve
Benji York (community) Approve
Review via email: mp+290102@code.launchpad.net

Commit message

When the testing starts, set review to Abstain, when scanner runs, don't launch more tests if it notices 'Abstain' on the bot's slot.

Description of the change

When the testing starts, set review to Abstain, when scanner runs, don't launch
more tests if it notices 'Abstain' on the bot's slot.

Testing instructions:

it's not super easy, since you really need an LP project and an MP, but please
feel free to check out this MP, which I used for testing:

https://code.launchpad.net/~davidpbritton/dpb-code/test-8/+merge/214602

Notice the abstain was put there by 'test', and the 'scan' job ignored this MP
because of it. Here is the config I use for testing on the 'dpb-code' project,
and you could set up anything similar on your project as well.

[lp:dpb-code]
verify_command = sleep 60; /bin/false
voting_criteria = Approve >= 1, Disapprove == 0
commit_message_template = Merged <branch_name>. [f=<bugs_fixed>] [r=<approved_by_nicks>]\n<commit_message>
artifacts = tarmac.conf

To post a comment you must log in.
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: make test
Result: Success
Revno: 15
Branch: lp:~davidpbritton/latch-test/dont-test-so-much
Jenkins: https://ci.lscape.net/job/latch-test/4066/

review: Approve (test results)
Revision history for this message
Benji York (benji) wrote :

Given the complexity of setting up a test environment, the low probability of damage due to a bug in this branch, and the fact that misbehavior will be obvious once landed, I did not run the code in this branch.

The code looks good. I had a couple questions/small suggestions that should be addressed before landing, but I'm sure the responses will be land-worthy, so I'm approving presuming the tweaks.

review: Approve
lp:~dpb/latch-test/dont-test-so-much updated
16. By David Britton

revert change of 'config' file, accident.

17. By David Britton

turn add_votes into add_vote and call multiple times to clean up usage.

Revision history for this message
David Britton (dpb) :
Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: make test
Result: Success
Revno: 17
Branch: lp:~davidpbritton/latch-test/dont-test-so-much
Jenkins: https://ci.lscape.net/job/latch-test/4079/

review: Approve (test results)
lp:~dpb/latch-test/dont-test-so-much updated
18. By David Britton

s/with multiple//

Revision history for this message
🤖 Landscape Builder (landscape-builder) wrote :

Command: make test
Result: Success
Revno: 18
Branch: lp:~davidpbritton/latch-test/dont-test-so-much
Jenkins: https://ci.lscape.net/job/latch-test/4080/

review: Approve (test results)
Revision history for this message
Данило Шеган (danilo) wrote :

I am getting a lint error on "make lint":

./latch.py:197:33: E901 SyntaxError: invalid syntax
./test_latch.py:73:1: E302 expected 2 blank lines, found 1
Makefile:8: recipe for target 'lint' failed
make: *** [lint] Error 1

This might be due to python3 being default on xenial, but it's easy enough to fix, so please do that (wrap print parameters on line 197 inside parentheses).

A few other nits inline, but overall a nice change: thanks for doing this work!

review: Approve
lp:~dpb/latch-test/dont-test-so-much updated
19. By David Britton

s/thisvote/this_vote/

20. By David Britton

danilo[diff]: use vote_lookup, not 'Abstain' directly.

21. By David Britton

danilo[diff]: restructure conditional

Revision history for this message
David Britton (dpb) :

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'latch.py'
2--- latch.py 2015-10-01 16:16:38 +0000
3+++ latch.py 2016-03-28 14:06:24 +0000
4@@ -205,6 +205,7 @@
5 self.lp_candidate = lp_candidate
6 self.readonly = readonly
7 self.vote_lookup = {
8+ "Testing": "Abstain",
9 "Fail": "Needs Fixing",
10 "Success": "Approve"}
11
12@@ -235,8 +236,27 @@
13 return True
14 return False
15
16- def add_result(self, result):
17- """Add this test result to the launchpad candidate."""
18+ def get_my_vote(self):
19+ """Return my most recent vote, or None, if I have not voted."""
20+ for vote in fetch_collection(self.lp, self.lp_candidate.votes):
21+ if vote.reviewer != self.lp.me:
22+ continue
23+ if vote.comment and vote.comment.vote:
24+ return vote.comment.vote
25+ else:
26+ break
27+ return None
28+
29+ def add_result(self, result, content=None, review_type="test results"):
30+ """
31+ Add this test result to the launchpad candidate.
32+
33+ @param content: if None, add the default comment content, which is a
34+ combination of test results and metadata. Otherwise,
35+ add content given to the comment.
36+ @param review_type: add this string as the review_type given.
37+ @param result: dict containing the test result.
38+ """
39 if not self.readonly:
40 log.debug("-> Adding result: %s to %s" % (
41 result['status'], self.lp_candidate.web_link))
42@@ -244,11 +264,13 @@
43 # my results don't claim a team membership review, for instance.
44 if not self.is_reviewer_added():
45 self.add_reviewer()
46+ if content is None:
47+ content = format_test_result(result)
48 self.lp_candidate.createComment(
49- content=format_test_result(result),
50+ content=content,
51 vote=self.vote_lookup[result["status"]],
52 subject="Latch Results: %(branch)s r%(revno)s" % result,
53- review_type="test results")
54+ review_type=review_type)
55 else:
56 log.debug("-> Would be adding result: %s to %s" % (
57 result['status'], self.lp_candidate.web_link))
58@@ -298,6 +320,12 @@
59 log.warning("Skipping candidate: %s")
60 return False
61
62+ # Results are currently being tested.
63+ if self.get_my_vote() == self.vote_lookup["Testing"]:
64+ log.debug("-> Already being tested, vote == %s" % (
65+ self.vote_lookup["Testing"]))
66+ return False
67+
68 if revision_tested == 0:
69 log.debug("-> results are stale, tested_revision == 0")
70 return True
71@@ -371,13 +399,16 @@
72 "%s 2>&1" % command, shell=True,
73 cwd=self.source_dir, env=self.environ).decode('utf-8')
74
75- def _verify(self):
76- """Run the tests in this environment, returns result dict."""
77- result = {
78+ def _get_base_result(self):
79+ return {
80 "status": u"Fail",
81 "command": self.verify_command,
82 "branch": self.lp_candidate.source_branch.bzr_identity,
83 "output": u""}
84+
85+ def _verify(self):
86+ """Run the tests in this environment, returns result dict."""
87+ result = self._get_base_result()
88 result["revno"] = self._get_revno(self.source_dir)
89 log.info("Running: %s" % result["command"])
90 try:
91@@ -407,6 +438,11 @@
92
93 def execute_test(self):
94 """Test the local copy of the code, report on results in the MP."""
95+ result = self._get_base_result()
96+ result["status"] = "Testing"
97+ result["revno"] = 0
98+ self.candidate.add_result(
99+ result=result, content="", review_type="executing tests")
100 result = self._verify()
101 self._copy_artifacts()
102 self.candidate.add_result(result)
103
104=== modified file 'test_latch.py'
105--- test_latch.py 2015-10-01 16:16:38 +0000
106+++ test_latch.py 2016-03-28 14:06:24 +0000
107@@ -61,17 +61,16 @@
108 candidate.all_comments.append(comment)
109
110
111-def add_votes(candidate, user=None):
112- """
113- Add some fake votes to a candidate. The last vote will be
114- assigned to the specified user.
115- """
116- candidate.votes = [MagicMock(), MagicMock(), MagicMock()]
117- if user is not None:
118- candidate.votes[-1].reviewer = user
119-
120-
121-def get_candidate(user):
122+def add_vote(candidate, reviewer="nobody", vote="Approved"):
123+ """Add a fake vote to a candidate."""
124+ this_vote = MagicMock()
125+ this_vote.reviewer = reviewer
126+ this_vote.comment.vote = vote
127+ if not candidate.votes:
128+ candidate.votes = []
129+ candidate.votes.append(this_vote)
130+
131+def get_candidate(reviewer):
132 """Return a fake candidate that needs testing."""
133 candidate = MagicMock()
134 candidate.self_link = "self_link"
135@@ -79,8 +78,10 @@
136 candidate.source_branch.revision_count = 2
137 candidate.target_branch.bzr_identity = "target_branch_id"
138 candidate.source_branch.bzr_identity = "source_branch_id"
139- add_results(candidate, 1, user)
140- add_votes(candidate, user)
141+ add_results(candidate, 1, reviewer)
142+ add_vote(candidate)
143+ add_vote(candidate)
144+ add_vote(candidate, reviewer)
145 return candidate
146
147
148@@ -251,6 +252,7 @@
149 self.lp = MagicMock()
150 self.lp.me = FAKE_ME
151 self.candidate = latch.Candidate(self.lp, MagicMock())
152+ self.candidate.lp_candidate.votes = []
153
154 def test_add_reviewer_readonly(self):
155 """If readonly is set, nothing should be returned."""
156@@ -266,27 +268,35 @@
157
158 def test_is_reviewer_added(self):
159 """lp user is added to a candidate."""
160- add_votes(self.candidate.lp_candidate, self.lp.me)
161+ add_vote(self.candidate.lp_candidate)
162+ add_vote(self.candidate.lp_candidate)
163+ add_vote(self.candidate.lp_candidate, self.lp.me)
164 self.assertTrue(self.candidate.is_reviewer_added())
165
166 def test_is_reviewer_added_negative(self):
167 """lp user is not added to a candidate."""
168 not_me = MagicMock()
169 not_me.name = "another-fake-user"
170- add_votes(self.candidate.lp_candidate, not_me)
171+ add_vote(self.candidate.lp_candidate)
172+ add_vote(self.candidate.lp_candidate)
173+ add_vote(self.candidate.lp_candidate, not_me)
174 self.assertFalse(self.candidate.is_reviewer_added())
175
176 def test_does_candidate_need_testing_stale_revision(self):
177 """Test results revno < source_branch, multiple comments."""
178 self.candidate.lp_candidate.source_branch.revision_count = 2
179- add_votes(self.candidate.lp_candidate, self.lp.me)
180+ add_vote(self.candidate.lp_candidate)
181+ add_vote(self.candidate.lp_candidate)
182+ add_vote(self.candidate.lp_candidate, self.lp.me)
183 add_results(self.candidate.lp_candidate, 1, self.lp.me)
184 self.assertTrue(self.candidate.needs_testing())
185
186 def test_does_candidate_need_testing_false(self):
187 """Test results revno == source branch, multiple comments."""
188 self.candidate.lp_candidate.source_branch.revision_count = 3
189- add_votes(self.candidate.lp_candidate, self.lp.me)
190+ add_vote(self.candidate.lp_candidate)
191+ add_vote(self.candidate.lp_candidate)
192+ add_vote(self.candidate.lp_candidate, self.lp.me)
193 add_results(self.candidate.lp_candidate, 3, self.lp.me)
194 self.assertFalse(self.candidate.needs_testing())
195
196@@ -325,6 +335,18 @@
197 "This is a test.")
198 self.assertTrue(self.candidate.are_test_results_stale())
199
200+ def test_are_test_results_stale_currently_testing(self):
201+ """My vote is abstain, which means I'm testing."""
202+ self.candidate.lp_candidate.source_branch.revision_count = 1
203+ add_vote(self.candidate.lp_candidate)
204+ add_vote(self.candidate.lp_candidate)
205+ add_vote(
206+ self.candidate.lp_candidate,
207+ vote="Abstain",
208+ reviewer=self.lp.me)
209+ self.assertFalse(self.candidate.are_test_results_stale())
210+ self.assertInLogs("Already being tested")
211+
212 def test_are_test_results_stale_lp_error(self):
213 """Test results revno == source branch."""
214 self.candidate.lp_candidate.source_branch.revision_count = 1
215@@ -362,6 +384,22 @@
216 self.assertEqual(self.candidate._get_revision_from_comment(comment), 0)
217 self.assertInLogs("revno parse error, skipping")
218
219+ def test_get_my_vote_none(self):
220+ """Test none is returned if I have not voted, others have."""
221+ add_vote(self.candidate.lp_candidate)
222+ add_vote(self.candidate.lp_candidate)
223+ add_vote(self.candidate.lp_candidate)
224+ vote = self.candidate.get_my_vote()
225+ self.assertIsNone(vote)
226+
227+ def test_get_my_vote_exists_multiple_votes(self):
228+ """Test vote is returned if I have voted."""
229+ add_vote(self.candidate.lp_candidate)
230+ add_vote(self.candidate.lp_candidate)
231+ add_vote(self.candidate.lp_candidate, self.lp.me)
232+ vote = self.candidate.get_my_vote()
233+ self.assertEqual(vote, "Approved")
234+
235 def test_add_result_readonly(self):
236 """if readonly, should NOT try to create a comment."""
237 result = {

Subscribers

People subscribed via source and target branches

to all changes: