Merge lp:~timrchavez/offspring/fix-lp-1095621 into lp:offspring

Proposed by Timothy R. Chavez
Status: Merged
Approved by: Kevin McDermott
Approved revision: 164
Merged at revision: 163
Proposed branch: lp:~timrchavez/offspring/fix-lp-1095621
Merge into: lp:offspring
Diff against target: 374 lines (+246/-13)
9 files modified
lib/offspring/master/master.py (+2/-1)
lib/offspring/master/models.py (+1/-0)
lib/offspring/master/tests/helpers.py (+2/-1)
lib/offspring/master/tests/test_master.py (+21/-7)
lib/offspring/web/queuemanager/admin.py (+5/-2)
lib/offspring/web/queuemanager/migrations/0003_auto__add_field_lexbuilder_is_retired.py (+173/-0)
lib/offspring/web/queuemanager/models.py (+1/-0)
lib/offspring/web/queuemanager/tests/test_views.py (+38/-0)
lib/offspring/web/urls.py (+3/-2)
To merge this branch: bzr merge lp:~timrchavez/offspring/fix-lp-1095621
Reviewer Review Type Date Requested Status
David Murphy (community) Needs Information
Kevin McDermott Approve
Review via email: mp+165286@code.launchpad.net

Description of the change

Introduce a 'is_retired' attribute for Lexbuilder which denotes that the builder has permanently been removed from service. This is different from 'is_active=False' which denotes that a builder is not accepting build jobs due to some intermittent disruption like an on-going upgrade or downtime caused by hardware failure. The "is_retired" flag will hide builders when set to true in the Builders List view and 404 on Builders Detail view. They will not get scanned by the master nor selected for building. They will remain visible in the admin (but the is_retired flag is exposed and filterable for the admin's convenience)

To post a comment you must log in.
Revision history for this message
Kevin McDermott (bigkevmcd) wrote :

Looks good to me, +1

review: Approve
Revision history for this message
David Murphy (schwuk) wrote :

81 + def test_create_builders_does_not_return_retired_builders(self):

Should that not be "test_get_builders_does_not_return_retired_builders"?

review: Needs Information
Revision history for this message
Timothy R. Chavez (timrchavez) wrote :

Good catch Dave. Yep.

165. By Timothy R. Chavez

Fix sed replace error in test name.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'lib/offspring/master/master.py'
2--- lib/offspring/master/master.py 2013-03-06 21:42:53 +0000
3+++ lib/offspring/master/master.py 2013-05-23 13:57:23 +0000
4@@ -97,7 +97,7 @@
5 self.is_online = False
6
7 def _get_builders(self):
8- return self.db_store.find(Lexbuilder)
9+ return self.db_store.find(Lexbuilder, Lexbuilder.is_retired == False)
10
11 def scanSlaves(self):
12 """
13@@ -190,6 +190,7 @@
14 Lexbuilder.current_state == LexbuilderSlave.STATE_IDLE,
15 Lexbuilder.is_active == True,
16 Lexbuilder.is_okay == True,
17+ Lexbuilder.is_retired == False,
18 Lexbuilder.machine_type.is_in(builder_types)
19 ).order_by(Lexbuilder.id).first()
20 if builder is not None:
21
22=== modified file 'lib/offspring/master/models.py'
23--- lib/offspring/master/models.py 2012-03-08 18:30:04 +0000
24+++ lib/offspring/master/models.py 2013-05-23 13:57:23 +0000
25@@ -34,6 +34,7 @@
26 updated_at = DateTime()
27 is_active = Bool(default=True)
28 is_okay = Bool(default=True)
29+ is_retired = Bool(default=False)
30 current_job_id = Int()
31 current_job = Reference(current_job_id, "BuildResult.id")
32 notes = Unicode()
33
34=== modified file 'lib/offspring/master/tests/helpers.py'
35--- lib/offspring/master/tests/helpers.py 2013-03-05 11:31:40 +0000
36+++ lib/offspring/master/tests/helpers.py 2013-05-23 13:57:23 +0000
37@@ -177,7 +177,8 @@
38 "'UTC'), "
39 "current_job_id INTEGER, "
40 "is_okay BOOLEAN NOT NULL, "
41- "is_active BOOLEAN NOT NULL DEFAULT TRUE)")
42+ "is_active BOOLEAN NOT NULL DEFAULT TRUE, "
43+ "is_retired BOOLEAN NOT NULL DEFAULT FALSE)")
44
45 self.connection.execute(
46 "CREATE TABLE buildrequests ("
47
48=== modified file 'lib/offspring/master/tests/test_master.py'
49--- lib/offspring/master/tests/test_master.py 2013-03-06 21:42:53 +0000
50+++ lib/offspring/master/tests/test_master.py 2013-05-23 13:57:23 +0000
51@@ -29,17 +29,18 @@
52 return LexbuilderMaster(self.config, self.db_store,
53 mailer=self.mailer.mail)
54
55- def create_builder(self, current_state=Slave.STATE_IDLE, arch=None):
56+ def create_builder(self, **kwargs):
57 """
58 Create and add a Lexbuilder to the store.
59 """
60- builder = Lexbuilder(u"http://myhost/")
61- builder.name = u"test-builder"
62+ builder = Lexbuilder(kwargs.get("uri", u"http://myhost/"))
63+ builder.name = unicode(kwargs.get("name", "test-builder"))
64 builder.previous_state = Slave.STATE_IDLE
65- builder.current_state = current_state
66- builder.is_active = True
67- builder.is_okay = True
68- builder.machine_type = arch or self.project.arch
69+ builder.current_state = kwargs.get("current_state", Slave.STATE_IDLE)
70+ builder.is_active = kwargs.get("is_active", True)
71+ builder.is_okay = kwargs.get("is_okay", True)
72+ builder.is_retired = kwargs.get("is_retired", False)
73+ builder.machine_type = kwargs.get("arch", self.project.arch)
74 self.db_store.add(builder)
75 return builder
76
77@@ -218,6 +219,19 @@
78 "Scan cycle completed\n" % {"builder": builder.name},
79 log_file.getvalue())
80
81+ def test_get_builders_does_not_return_retired_builders(self):
82+ """
83+ Test that retired builders are not returned by _get_builders() which
84+ is the function the scanner uses to get a list of builders to scan.
85+ """
86+ master = self.get_master()
87+ builder1 = self.create_builder(name="BuilderA", is_retired=True)
88+ builder2 = self.create_builder(name="BuilderB", is_active=False)
89+ builder3 = self.create_builder(name="BuilderC")
90+ builders = master._get_builders()
91+ self.assertEqual(2, builders.count())
92+ self.assertEqual(["BuilderB", "BuilderC"], list(builders.values(Lexbuilder.name)))
93+
94 def test_dispatch_builds(self):
95 """
96 dispatchBuilds sends BuildRequests to a slave.
97
98=== modified file 'lib/offspring/web/queuemanager/admin.py'
99--- lib/offspring/web/queuemanager/admin.py 2013-05-09 14:27:56 +0000
100+++ lib/offspring/web/queuemanager/admin.py 2013-05-23 13:57:23 +0000
101@@ -19,8 +19,11 @@
102
103
104 class LexbuilderAdmin(admin.ModelAdmin):
105- list_display = ('name', 'machine_type', 'is_active', 'is_okay', 'current_state', 'current_build', 'updated_at')
106- list_filter = ['current_state', 'machine_type', 'is_active', 'is_okay']
107+ list_display = ('name', 'machine_type', 'is_active', 'is_okay',
108+ 'is_retired', 'current_state', 'current_build',
109+ 'updated_at')
110+ list_filter = ['current_state', 'machine_type', 'is_active',
111+ 'is_okay', 'is_retired']
112 actions=['make_enabled', 'make_disabled']
113
114 def make_disabled(self, request, queryset):
115
116=== added file 'lib/offspring/web/queuemanager/migrations/0003_auto__add_field_lexbuilder_is_retired.py'
117--- lib/offspring/web/queuemanager/migrations/0003_auto__add_field_lexbuilder_is_retired.py 1970-01-01 00:00:00 +0000
118+++ lib/offspring/web/queuemanager/migrations/0003_auto__add_field_lexbuilder_is_retired.py 2013-05-23 13:57:23 +0000
119@@ -0,0 +1,173 @@
120+# encoding: utf-8
121+import datetime
122+from south.db import db
123+from south.v2 import SchemaMigration
124+from django.db import models
125+
126+class Migration(SchemaMigration):
127+
128+ def forwards(self, orm):
129+
130+ # Adding field 'Lexbuilder.is_retired'
131+ db.add_column('lexbuilders', 'is_retired', self.gf('django.db.models.fields.BooleanField')(default=False), keep_default=False)
132+
133+
134+ def backwards(self, orm):
135+
136+ # Deleting field 'Lexbuilder.is_retired'
137+ db.delete_column('lexbuilders', 'is_retired')
138+
139+
140+ models = {
141+ 'auth.group': {
142+ 'Meta': {'object_name': 'Group'},
143+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
144+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
145+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
146+ },
147+ 'auth.permission': {
148+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
149+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
150+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
151+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
152+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
153+ },
154+ 'auth.user': {
155+ 'Meta': {'object_name': 'User'},
156+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 5, 22, 4, 7, 28, 104849)'}),
157+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
158+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
159+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
160+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
161+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
162+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
163+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
164+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime(2013, 5, 22, 4, 7, 28, 104782)'}),
165+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
166+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
167+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
168+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
169+ },
170+ 'contenttypes.contenttype': {
171+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
172+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
173+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
174+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
175+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
176+ },
177+ 'django_group_access.accessgroup': {
178+ 'Meta': {'ordering': "('name',)", 'object_name': 'AccessGroup'},
179+ 'auto_share_groups': ('django.db.models.fields.related.ManyToManyField', [], {'related_name': "'auto_share_groups_rel_+'", 'blank': 'True', 'to': "orm['django_group_access.AccessGroup']"}),
180+ 'can_be_shared_with': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
181+ 'can_share_with': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['django_group_access.AccessGroup']", 'symmetrical': 'False', 'blank': 'True'}),
182+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
183+ 'members': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.User']", 'symmetrical': 'False', 'blank': 'True'}),
184+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '64'}),
185+ 'supergroup': ('django.db.models.fields.BooleanField', [], {'default': 'False'})
186+ },
187+ 'queuemanager.buildrequest': {
188+ 'Meta': {'object_name': 'BuildRequest', 'db_table': "'buildrequests'"},
189+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
190+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
191+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.Project']", 'db_column': "'project_name'"}),
192+ 'reason': ('django.db.models.fields.TextField', [], {'max_length': '200', 'blank': 'True'}),
193+ 'requestor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'db_column': "'requestor_id'", 'blank': 'True'}),
194+ 'score': ('django.db.models.fields.IntegerField', [], {'default': '10'})
195+ },
196+ 'queuemanager.buildresult': {
197+ 'Meta': {'object_name': 'BuildResult', 'db_table': "'buildresults'"},
198+ 'builder': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.Lexbuilder']", 'null': 'True', 'blank': 'True'}),
199+ 'dispatched_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
200+ 'finished_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'}),
201+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
202+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
203+ 'notes': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
204+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.Project']", 'db_column': "'project_name'"}),
205+ 'reason': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
206+ 'requested_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'null': 'True', 'blank': 'True'}),
207+ 'requestor': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'null': 'True', 'db_column': "'requestor_id'", 'blank': 'True'}),
208+ 'result': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
209+ 'started_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True', 'blank': 'True'})
210+ },
211+ 'queuemanager.dailybuildorder': {
212+ 'Meta': {'object_name': 'DailyBuildOrder', 'db_table': "'dailybuildorders'"},
213+ 'hour': ('django.db.models.fields.PositiveIntegerField', [], {}),
214+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
215+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
216+ 'projects': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['queuemanager.Project']", 'symmetrical': 'False'})
217+ },
218+ 'queuemanager.launchpadproject': {
219+ 'Meta': {'object_name': 'LaunchpadProject', 'db_table': "'launchpad_projects'"},
220+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200', 'primary_key': 'True'}),
221+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'})
222+ },
223+ 'queuemanager.launchpadprojectmilestone': {
224+ 'Meta': {'object_name': 'LaunchpadProjectMilestone', 'db_table': "'launchpad_project_milestones'"},
225+ 'active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
226+ 'date_targeted': ('django.db.models.fields.DateField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
227+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
228+ 'launchpad_project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.LaunchpadProject']", 'null': 'True', 'blank': 'True'}),
229+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
230+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'})
231+ },
232+ 'queuemanager.lexbuilder': {
233+ 'Meta': {'object_name': 'Lexbuilder', 'db_table': "'lexbuilders'"},
234+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
235+ 'current_job': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.BuildResult']", 'null': 'True', 'db_column': "'current_job_id'", 'blank': 'True'}),
236+ 'current_state': ('django.db.models.fields.CharField', [], {'default': "'UNKNOWN'", 'max_length': '200'}),
237+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
238+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
239+ 'is_okay': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
240+ 'is_retired': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
241+ 'machine_type': ('django.db.models.fields.CharField', [], {'default': "'x86_64'", 'max_length': '200'}),
242+ 'name': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '200', 'db_index': 'True'}),
243+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
244+ 'previous_state': ('django.db.models.fields.CharField', [], {'default': "'UNKNOWN'", 'max_length': '200'}),
245+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
246+ 'uri': ('django.db.models.fields.CharField', [], {'max_length': '200'})
247+ },
248+ 'queuemanager.project': {
249+ 'Meta': {'object_name': 'Project', 'db_table': "'projects'"},
250+ 'access_groups': ('django.db.models.fields.related.ManyToManyField', [], {'symmetrical': 'False', 'to': "orm['django_group_access.AccessGroup']", 'null': 'True', 'blank': 'True'}),
251+ 'arch': ('django.db.models.fields.CharField', [], {'max_length': '10'}),
252+ 'config_url': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
253+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
254+ 'launchpad_project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.LaunchpadProject']", 'null': 'True', 'blank': 'True'}),
255+ 'name': ('django.db.models.fields.SlugField', [], {'unique': 'True', 'max_length': '200', 'primary_key': 'True', 'db_index': 'True'}),
256+ 'notes': ('django.db.models.fields.TextField', [], {'null': 'True', 'blank': 'True'}),
257+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "'project_owner'", 'null': 'True', 'to': "orm['auth.User']"}),
258+ 'priority': ('django.db.models.fields.IntegerField', [], {'default': '50'}),
259+ 'project_group': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.ProjectGroup']", 'null': 'True', 'blank': 'True'}),
260+ 'series': ('django.db.models.fields.CharField', [], {'default': "'lucid'", 'max_length': '200'}),
261+ 'status': ('django.db.models.fields.CharField', [], {'max_length': '200', 'null': 'True'}),
262+ 'suite': ('django.db.models.fields.CharField', [], {'max_length': '200', 'blank': 'True'}),
263+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '30'})
264+ },
265+ 'queuemanager.projectgroup': {
266+ 'Meta': {'object_name': 'ProjectGroup', 'db_table': "'projectgroups'"},
267+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200', 'primary_key': 'True'}),
268+ 'title': ('django.db.models.fields.CharField', [], {'max_length': '200'})
269+ },
270+ 'queuemanager.projectnotificationsubscription': {
271+ 'Meta': {'object_name': 'ProjectNotificationSubscription', 'db_table': "'project_notification_subscriptions'"},
272+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
273+ 'project': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.Project']", 'db_column': "'project_name'"}),
274+ 'user': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']", 'db_column': "'user_id'"})
275+ },
276+ 'queuemanager.release': {
277+ 'Meta': {'object_name': 'Release', 'db_table': "'releases'"},
278+ 'build': ('django.db.models.fields.related.OneToOneField', [], {'to': "orm['queuemanager.BuildResult']", 'unique': 'True', 'primary_key': 'True'}),
279+ 'checklist_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
280+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
281+ 'creator': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
282+ 'milestone': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['queuemanager.LaunchpadProjectMilestone']", 'null': 'True', 'blank': 'True'}),
283+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '200'}),
284+ 'notes': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
285+ 'published_at': ('django.db.models.fields.DateTimeField', [], {'null': 'True'}),
286+ 'status': ('django.db.models.fields.PositiveSmallIntegerField', [], {'default': '0'}),
287+ 'tag': ('django.db.models.fields.CharField', [], {'max_length': '5', 'null': 'True', 'blank': 'True'}),
288+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
289+ }
290+ }
291+
292+ complete_apps = ['queuemanager']
293
294=== modified file 'lib/offspring/web/queuemanager/models.py'
295--- lib/offspring/web/queuemanager/models.py 2013-05-17 13:49:22 +0000
296+++ lib/offspring/web/queuemanager/models.py 2013-05-23 13:57:23 +0000
297@@ -164,6 +164,7 @@
298 updated_at = models.DateTimeField('date updated', auto_now=True)
299 is_active = models.BooleanField(default=True)
300 is_okay = models.BooleanField(default=True, editable=False)
301+ is_retired = models.BooleanField(default=False)
302 machine_type = models.CharField(max_length=200, default="x86_64")
303 current_job = models.ForeignKey("BuildResult", db_column="current_job_id", editable=False, blank=True, null=True)
304 notes = models.TextField('whiteboard', blank=True, null=True)
305
306=== modified file 'lib/offspring/web/queuemanager/tests/test_views.py'
307--- lib/offspring/web/queuemanager/tests/test_views.py 2013-01-31 18:36:58 +0000
308+++ lib/offspring/web/queuemanager/tests/test_views.py 2013-05-23 13:57:23 +0000
309@@ -275,6 +275,44 @@
310 msg_prefix=response.content
311 )
312
313+class BuildersListViewTests(TestCase):
314+ def setUp(self):
315+ user = factory.make_user()
316+ self.builder1 = factory.make_lexbuilder(
317+ name="BuilderA", is_retired=True)
318+ self.builder2 = factory.make_lexbuilder(name="BuilderB")
319+ self.client.login(
320+ username=user.username, password=user.username)
321+
322+ def test_builderslist_does_not_show_retired_builders(self):
323+ """
324+ Test builders list does not show retired builders.
325+ """
326+ response = self.client.get(reverse("builders_list"))
327+ self.assertNotContains(
328+ response, self.builder1.name, status_code=200,
329+ msg_prefix=response.content)
330+ self.assertContains(
331+ response, self.builder2.name, status_code=200,
332+ msg_prefix=response.content)
333+
334+class BuilderDetailsViewTests(TestCase):
335+ def setUp(self):
336+ user = factory.make_user()
337+ self.builder1 = factory.make_lexbuilder(
338+ name="BuilderA", is_retired=True)
339+ self.builder2 = factory.make_lexbuilder(name="BuilderB")
340+ self.client.login(
341+ username=user.username, password=user.username)
342+
343+ def test_builderdetails_404s_for_retired_builders(self):
344+ """
345+ Test builder details are not available for retired builders.
346+ """
347+ response = self.client.get(reverse("builder_details", kwargs={'slug': self.builder1.name}))
348+ self.assertEqual(response.status_code, 404)
349+ response = self.client.get(reverse("builder_details", kwargs={'slug': self.builder2.name}))
350+ self.assertEqual(response.status_code, 200)
351
352 class BuildResultPublishViewTests(TestCase):
353
354
355=== modified file 'lib/offspring/web/urls.py'
356--- lib/offspring/web/urls.py 2013-01-22 10:00:39 +0000
357+++ lib/offspring/web/urls.py 2013-05-23 13:57:23 +0000
358@@ -58,13 +58,14 @@
359 (r'^openid/', include('django_openid_auth.urls')),
360 (r'^logout/', 'django.contrib.auth.views.logout'),
361 (r'^builders/$', secure_object_list, {
362- 'queryset' : Lexbuilder.objects.order_by("-is_active", "-machine_type", "-created_at"),
363+ 'queryset' : Lexbuilder.objects.filter(is_retired=False).order_by(
364+ "-is_active", "-machine_type", "-created_at"),
365 'template_name' : 'queuemanager/builders.html',
366 'template_object_name' : 'builder',
367 'extra_context' : { 'pillar' : 'builders', },
368 }, 'builders_list'),
369 (r'^builders/(?P<slug>[^/]+)/$', secure_object_detail, {
370- 'queryset' : Lexbuilder.objects.all(),
371+ 'queryset' : Lexbuilder.objects.filter(is_retired=False),
372 'slug_field' : 'name',
373 'template_name' : 'queuemanager/builder_details.html',
374 'template_object_name' : 'builder',

Subscribers

People subscribed via source and target branches