Merge lp:~michael.nelson/ubuntu-webcatalog/953306-display-app-version into lp:ubuntu-webcatalog

Proposed by Michael Nelson
Status: Merged
Approved by: Anthony Lenton
Approved revision: 82
Merged at revision: 78
Proposed branch: lp:~michael.nelson/ubuntu-webcatalog/953306-display-app-version
Merge into: lp:ubuntu-webcatalog
Diff against target: 448 lines (+237/-43)
9 files modified
src/webcatalog/forms.py (+5/-0)
src/webcatalog/management/commands/import_app_install_data.py (+3/-0)
src/webcatalog/migrations/0010_add_app_version.py (+154/-0)
src/webcatalog/models/applications.py (+1/-0)
src/webcatalog/templates/webcatalog/application_detail.html (+6/-0)
src/webcatalog/tests/factory.py (+4/-2)
src/webcatalog/tests/test_commands.py (+41/-40)
src/webcatalog/tests/test_data/sca_apps.txt (+2/-1)
src/webcatalog/tests/test_views.py (+21/-0)
To merge this branch: bzr merge lp:~michael.nelson/ubuntu-webcatalog/953306-display-app-version
Reviewer Review Type Date Requested Status
Anthony Lenton (community) Approve
Review via email: mp+97230@code.launchpad.net

Commit message

Import and display application versions.

Description of the change

Overiew
=======

Adds Application.version, ensures it's imported for both archive and purchase apps, and displays it on the details page under the license (similar to USC).

`fab test`

To post a comment you must log in.
82. By Michael Nelson

Moved inline immport.

Revision history for this message
Anthony Lenton (elachuni) wrote :

Hi Michael,

Thanks for the branch! The only thing I think would be missing would be to also import the version for for-purchase apps, within the import_for_purchase_apps command.

About rev. 77, I think it's neat if the tests can all work with the same mock_response. Why is test_app_is_not_created_if_already_in_webcatalog removed though? Was that already tested by a different test?

Cheers,

achuni.

Revision history for this message
Michael Nelson (michael.nelson) wrote :

On Wed, Mar 14, 2012 at 11:11 PM, Anthony Lenton
<email address hidden> wrote:
> Hi Michael,
>
> Thanks for the branch!  The only thing I think would be missing would be to also import the version for for-purchase apps, within the import_for_purchase_apps command.
>

Sheesh - you had me worried there for a second. It is there, you can
see it being tested line 389 of the MP diff, it's just that
import_for_purchase_apps didn't contain the change, it uses a form to
clean the data and the form was updated (first part of the diff).

> About rev. 77, I think it's neat if the tests can all work with the same mock_response.  Why is test_app_is_not_created_if_already_in_webcatalog removed though? Was that already tested by a different test?

Yeah, with test_existing_app_gets_updated_by_archive_id, it made sense
that part of this test was to ensure not only that the existing app is
updated, but that the number of apps didn't change. If you think it
should be separate, just let me know.

Thanks!

Revision history for this message
Anthony Lenton (elachuni) wrote :

Hah, yep, I missed the test completely and thought that the form update was for import_app_install_data.

Thanks!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/webcatalog/forms.py'
2--- src/webcatalog/forms.py 2012-03-06 19:35:00 +0000
3+++ src/webcatalog/forms.py 2012-03-13 15:19:18 +0000
4@@ -22,6 +22,7 @@
5 with_statement,
6 )
7
8+import apt
9 from ConfigParser import ConfigParser
10 from StringIO import StringIO
11
12@@ -108,6 +109,10 @@
13
14 return cls(data=app_data, instance=instance)
15
16+ def clean_version(self):
17+ value = self.cleaned_data['version']
18+ return apt.apt_pkg.upstream_version(value)
19+
20
21 class EmailDownloadLinkForm(forms.Form):
22 email = forms.EmailField()
23
24=== modified file 'src/webcatalog/management/commands/import_app_install_data.py'
25--- src/webcatalog/management/commands/import_app_install_data.py 2012-03-05 09:23:47 +0000
26+++ src/webcatalog/management/commands/import_app_install_data.py 2012-03-13 15:19:18 +0000
27@@ -264,6 +264,7 @@
28 if not app_comment:
29 app_comment = package.name
30
31+ version = apt.apt_pkg.upstream_version(candidate.version)
32 if package.name in prefetched_apps:
33 app = prefetched_apps[package.name]
34 if (app.description == candidate.description and
35@@ -273,6 +274,7 @@
36 continue
37 app.description = candidate.description
38 app.section = candidate.section
39+ app.version = version
40 app.name = app_name
41 app.comment = app_comment
42 app.save()
43@@ -284,6 +286,7 @@
44 description=candidate.description,
45 section=candidate.section,
46 name=app_name,
47+ version=version,
48 comment=app_comment,
49 )
50 if self.verbosity == 1:
51
52=== added file 'src/webcatalog/migrations/0010_add_app_version.py'
53--- src/webcatalog/migrations/0010_add_app_version.py 1970-01-01 00:00:00 +0000
54+++ src/webcatalog/migrations/0010_add_app_version.py 2012-03-13 15:19:18 +0000
55@@ -0,0 +1,154 @@
56+# encoding: utf-8
57+import datetime
58+from south.db import db
59+from south.v2 import SchemaMigration
60+from django.db import models
61+
62+class Migration(SchemaMigration):
63+
64+ def forwards(self, orm):
65+
66+ # Adding field 'Application.version'
67+ db.add_column('webcatalog_application', 'version', self.gf('django.db.models.fields.CharField')(default='', max_length=32, blank=True), keep_default=False)
68+
69+
70+ def backwards(self, orm):
71+
72+ # Deleting field 'Application.version'
73+ db.delete_column('webcatalog_application', 'version')
74+
75+
76+ models = {
77+ 'auth.group': {
78+ 'Meta': {'object_name': 'Group'},
79+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
80+ 'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '80'}),
81+ 'permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'})
82+ },
83+ 'auth.permission': {
84+ 'Meta': {'ordering': "('content_type__app_label', 'content_type__model', 'codename')", 'unique_together': "(('content_type', 'codename'),)", 'object_name': 'Permission'},
85+ 'codename': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
86+ 'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['contenttypes.ContentType']"}),
87+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
88+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '50'})
89+ },
90+ 'auth.user': {
91+ 'Meta': {'object_name': 'User'},
92+ 'date_joined': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
93+ 'email': ('django.db.models.fields.EmailField', [], {'max_length': '75', 'blank': 'True'}),
94+ 'first_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
95+ 'groups': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Group']", 'symmetrical': 'False', 'blank': 'True'}),
96+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
97+ 'is_active': ('django.db.models.fields.BooleanField', [], {'default': 'True'}),
98+ 'is_staff': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
99+ 'is_superuser': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
100+ 'last_login': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.now'}),
101+ 'last_name': ('django.db.models.fields.CharField', [], {'max_length': '30', 'blank': 'True'}),
102+ 'password': ('django.db.models.fields.CharField', [], {'max_length': '128'}),
103+ 'user_permissions': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['auth.Permission']", 'symmetrical': 'False', 'blank': 'True'}),
104+ 'username': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '30'})
105+ },
106+ 'contenttypes.contenttype': {
107+ 'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
108+ 'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
109+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
110+ 'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
111+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
112+ },
113+ 'webcatalog.application': {
114+ 'Meta': {'unique_together': "(('distroseries', 'archive_id'),)", 'object_name': 'Application'},
115+ 'app_type': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'}),
116+ 'architectures': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
117+ 'archive_id': ('django.db.models.fields.CharField', [], {'db_index': 'True', 'max_length': '64', 'null': 'True', 'blank': 'True'}),
118+ 'categories': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
119+ 'channel': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
120+ 'comment': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
121+ 'departments': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.Department']", 'symmetrical': 'False', 'blank': 'True'}),
122+ 'description': ('django.db.models.fields.TextField', [], {'blank': 'True'}),
123+ 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']"}),
124+ 'for_purchase': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
125+ 'icon': ('django.db.models.fields.files.ImageField', [], {'max_length': '200', 'null': 'True', 'blank': 'True'}),
126+ 'icon_name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
127+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
128+ 'keywords': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
129+ 'mimetype': ('django.db.models.fields.CharField', [], {'max_length': '2048', 'blank': 'True'}),
130+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
131+ 'package_name': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
132+ 'popcon': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
133+ 'price': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '7', 'decimal_places': '2', 'blank': 'True'}),
134+ 'ratings_average': ('django.db.models.fields.DecimalField', [], {'null': 'True', 'max_digits': '3', 'decimal_places': '2', 'blank': 'True'}),
135+ 'ratings_histogram': ('django.db.models.fields.CharField', [], {'max_length': '128', 'blank': 'True'}),
136+ 'ratings_total': ('django.db.models.fields.IntegerField', [], {'null': 'True', 'blank': 'True'}),
137+ 'screenshot_url': ('django.db.models.fields.URLField', [], {'max_length': '200', 'blank': 'True'}),
138+ 'section': ('django.db.models.fields.CharField', [], {'max_length': '32'}),
139+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '32', 'blank': 'True'})
140+ },
141+ 'webcatalog.consumer': {
142+ 'Meta': {'object_name': 'Consumer'},
143+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
144+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
145+ 'key': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
146+ 'secret': ('django.db.models.fields.CharField', [], {'default': "'sEjZUPZnEgnDdaBCNkLPXCrLcWBCxu'", 'max_length': '255', 'blank': 'True'}),
147+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
148+ 'user': ('django.db.models.fields.related.OneToOneField', [], {'related_name': "'oauth_consumer'", 'unique': 'True', 'to': "orm['auth.User']"})
149+ },
150+ 'webcatalog.department': {
151+ 'Meta': {'object_name': 'Department'},
152+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
153+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
154+ 'parent': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Department']", 'null': 'True', 'blank': 'True'})
155+ },
156+ 'webcatalog.distroseries': {
157+ 'Meta': {'object_name': 'DistroSeries'},
158+ 'code_name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '20', 'db_index': 'True'}),
159+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
160+ 'version': ('django.db.models.fields.CharField', [], {'max_length': '10', 'blank': 'True'})
161+ },
162+ 'webcatalog.exhibit': {
163+ 'Meta': {'object_name': 'Exhibit'},
164+ 'banner_url': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
165+ 'date_created': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
166+ 'display': ('django.db.models.fields.NullBooleanField', [], {'null': 'True', 'blank': 'True'}),
167+ 'distroseries': ('django.db.models.fields.related.ManyToManyField', [], {'to': "orm['webcatalog.DistroSeries']", 'symmetrical': 'False'}),
168+ 'html': ('django.db.models.fields.TextField', [], {}),
169+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
170+ 'package_names': ('django.db.models.fields.CharField', [], {'max_length': '1024'}),
171+ 'published': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
172+ 'sca_id': ('django.db.models.fields.IntegerField', [], {})
173+ },
174+ 'webcatalog.machine': {
175+ 'Meta': {'unique_together': "(('owner', 'uuid'),)", 'object_name': 'Machine'},
176+ 'hostname': ('django.db.models.fields.CharField', [], {'max_length': '64'}),
177+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
178+ 'logo_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56', 'blank': 'True'}),
179+ 'owner': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['auth.User']"}),
180+ 'package_list': ('django.db.models.fields.TextField', [], {}),
181+ 'packages_checksum': ('django.db.models.fields.CharField', [], {'max_length': '56'}),
182+ 'uuid': ('django.db.models.fields.CharField', [], {'max_length': '32', 'db_index': 'True'})
183+ },
184+ 'webcatalog.nonce': {
185+ 'Meta': {'object_name': 'Nonce'},
186+ 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}),
187+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
188+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
189+ 'nonce': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '255'}),
190+ 'token': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Token']"})
191+ },
192+ 'webcatalog.reviewstatsimport': {
193+ 'Meta': {'object_name': 'ReviewStatsImport'},
194+ 'distroseries': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.DistroSeries']", 'unique': 'True'}),
195+ 'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
196+ 'last_import': ('django.db.models.fields.DateTimeField', [], {'default': 'datetime.datetime.utcnow'})
197+ },
198+ 'webcatalog.token': {
199+ 'Meta': {'object_name': 'Token'},
200+ 'consumer': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['webcatalog.Consumer']"}),
201+ 'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
202+ 'name': ('django.db.models.fields.CharField', [], {'max_length': '255', 'blank': 'True'}),
203+ 'token': ('django.db.models.fields.CharField', [], {'default': "'NmdZZbdybysvASwPmODfOInVgdUrtwQIuGzCBQzZgoRoppjwrK'", 'max_length': '50', 'primary_key': 'True'}),
204+ 'token_secret': ('django.db.models.fields.CharField', [], {'default': "'zXcfbHWuHkeoltnlevFxVswIdDArEKgnTSLZzlkLSHdUCLmluo'", 'max_length': '50'}),
205+ 'updated_at': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'})
206+ }
207+ }
208+
209+ complete_apps = ['webcatalog']
210
211=== modified file 'src/webcatalog/models/applications.py'
212--- src/webcatalog/models/applications.py 2012-03-12 15:30:15 +0000
213+++ src/webcatalog/models/applications.py 2012-03-13 15:19:18 +0000
214@@ -69,6 +69,7 @@
215 # The following fields are extracted from app-install-data.
216 package_name = models.CharField(max_length=100)
217 name = models.CharField(max_length=255)
218+ version = models.CharField(max_length=32, blank=True)
219 comment = models.CharField(max_length=255, blank=True)
220 popcon = models.IntegerField(null=True, blank=True)
221 channel = models.CharField(max_length=255, blank=True)
222
223=== modified file 'src/webcatalog/templates/webcatalog/application_detail.html'
224--- src/webcatalog/templates/webcatalog/application_detail.html 2012-03-08 20:27:19 +0000
225+++ src/webcatalog/templates/webcatalog/application_detail.html 2012-03-13 15:19:18 +0000
226@@ -94,6 +94,12 @@
227 <th>{% trans "License:" %}</th>
228 <td>{{ application.license_type }}</td>
229 </tr>
230+ {% if application.version %}
231+ <tr>
232+ <th>{% trans "Version:" %}</th>
233+ <td>{{ application.version }}</td>
234+ </tr>
235+ {% endif %}
236 </table>
237 </div>
238 <div class="share">
239
240=== modified file 'src/webcatalog/tests/factory.py'
241--- src/webcatalog/tests/factory.py 2012-03-09 15:46:15 +0000
242+++ src/webcatalog/tests/factory.py 2012-03-13 15:19:18 +0000
243@@ -93,7 +93,8 @@
244 def make_application(self, package_name=None, name=None,
245 comment=None, description=None, icon_name='', icon=None,
246 distroseries=None, arch='i686', ratings_average=None,
247- ratings_total=None, ratings_histogram='', screenshot_url=None):
248+ ratings_total=None, ratings_histogram='', screenshot_url=None,
249+ archive_id=None, version=''):
250 if name is None:
251 name = self.get_unique_string(prefix='Readable Name')
252 if package_name is None:
253@@ -110,7 +111,8 @@
254 description=description, popcon=999, icon=icon,
255 icon_name=icon_name, distroseries=distroseries, architectures=arch,
256 ratings_average=ratings_average, ratings_total=ratings_total,
257- ratings_histogram=ratings_histogram, screenshot_url=screenshot_url)
258+ ratings_histogram=ratings_histogram, screenshot_url=screenshot_url,
259+ archive_id=archive_id, version=version)
260
261 def make_department(self, name, parent=None, slug=None):
262 if slug is None:
263
264=== modified file 'src/webcatalog/tests/test_commands.py'
265--- src/webcatalog/tests/test_commands.py 2012-03-06 16:51:27 +0000
266+++ src/webcatalog/tests/test_commands.py 2012-03-13 15:19:18 +0000
267@@ -88,6 +88,7 @@
268 mock_package.name = name
269 mock_package.candidate.section = ''
270 mock_package.candidate.summary = summary
271+ mock_package.candidate.version = '1.2.3-4ubuntu1~dev'
272 return mock_package
273
274 def make_mock_apt_cache(self):
275@@ -381,6 +382,7 @@
276 otherapp = Application.objects.get(package_name='otherapp')
277 self.assertEqual('Otherapp the Internet', otherapp.name)
278 self.assertEqual('A tagline for Otherapp', otherapp.comment)
279+ self.assertEqual('1.2.3', otherapp.version)
280
281 def test_lang_specific_description_added_to_app(self):
282 # Related to bug 879268 - our app server runs on lucid where
283@@ -401,6 +403,7 @@
284 class ImportForPurchaseAppsTestCase(TestCaseWithFactory):
285
286 def setUp(self):
287+ super(ImportForPurchaseAppsTestCase, self).setUp()
288 curdir = os.path.dirname(__file__)
289 sca_apps_file = os.path.join(curdir, 'test_data', 'sca_apps.txt')
290 self.distroseries = DistroSeries.objects.create(code_name='natty')
291@@ -409,69 +412,67 @@
292 mock_response = Mock()
293 mock_response.code = 200
294 mock_response.read.return_value = self.response_content
295- self.mock_response = mock_response
296-
297- @patch('urllib.urlopen')
298- def test_app_for_purchase_is_found(self, mock_urllib):
299- mock_urllib.return_value = self.mock_response
300+
301+ self.patch_urlopen = patch('urllib.urlopen')
302+ mock_urllib = self.patch_urlopen.start()
303+ mock_urllib.return_value = mock_response
304+ self.addCleanup(self.patch_urlopen.stop)
305+
306+ def test_app_for_purchase_is_found(self):
307 apps_for_purchase = Application.objects.filter(for_purchase=True)
308 self.assertEqual(0, len(apps_for_purchase))
309+
310 call_command('import_for_purchase_apps')
311+
312 app_for_purchase = Application.objects.get(name='MyApp',
313 distroseries=self.distroseries)
314 self.assertEqual(True, app_for_purchase.for_purchase)
315 self.assertTrue(app_for_purchase.description.find('hello') > -1)
316
317- @patch('urllib.urlopen')
318- def test_app_is_not_created_if_already_in_webcatalog(self, mock_urllib):
319- mock_urllib.return_value = self.mock_response
320- apps = Application.objects.all()
321- first = len(apps)
322- call_command('import_for_purchase_apps')
323- apps = Application.objects.all()
324- second = len(apps)
325- call_command('import_for_purchase_apps')
326- apps = Application.objects.all()
327- third = len(apps)
328- self.assertTrue(second > first)
329- # number of apps should not increase
330- self.assertEqual(second, third)
331+ def test_app_gets_distroseries(self):
332+ call_command('import_for_purchase_apps')
333
334- @patch('urllib.urlopen')
335- def test_app_gets_distroseries(self, mock_urllib):
336- mock_urllib.return_value = self.mock_response
337- call_command('import_for_purchase_apps')
338 app = Application.objects.get(name='MyApp',
339 distroseries=self.distroseries)
340 self.assertEqual(2, len(app.available_distroseries()))
341
342- @patch('urllib.urlopen')
343- def test_app_gets_price(self, mock_urllib):
344- mock_urllib.return_value = self.mock_response
345+ def test_app_gets_price(self):
346 call_command('import_for_purchase_apps')
347+
348 app = Application.objects.get(name='MyApp',
349 distroseries=self.distroseries)
350 self.assertEqual(Decimal('2.50'), app.price)
351
352- @patch('urllib.urlopen')
353- def test_app_gets_updated(self, mock_urllib):
354- mock_urllib.return_value = self.mock_response
355- call_command('import_for_purchase_apps')
356- updated = self.response_content.replace('hello', 'bye')
357- self.mock_response.read.return_value = updated
358- call_command('import_for_purchase_apps')
359- app = Application.objects.get(name='MyApp',
360+ def test_existing_app_gets_updated_by_archive_id(self):
361+ self.factory.make_application(archive_id='launchpad_zematynnad2/myppa',
362+ package_name='somethingelse',
363+ distroseries=self.factory.make_distroseries(code_name='maverick'))
364+ self.factory.make_application(archive_id='launchpad_zematynnad2/myppa',
365+ package_name='somethingelse',
366 distroseries=self.distroseries)
367- self.assertEqual('bye', app.package_name)
368-
369- @patch('urllib.urlopen')
370- def test_app_gets_icon(self, mock_urllib):
371- mock_urllib.return_value = self.mock_response
372- call_command('import_for_purchase_apps')
373+ self.assertEqual(2, Application.objects.count())
374+
375+ call_command('import_for_purchase_apps')
376+
377+ self.assertEqual(2, Application.objects.count())
378+ for app in Application.objects.all():
379+ self.assertEqual('launchpad_zematynnad2/myppa', app.archive_id)
380+ self.assertEqual('hello', app.package_name)
381+
382+ def test_app_gets_icon(self):
383+ call_command('import_for_purchase_apps')
384+
385 app = Application.objects.get(name='MyApp',
386 distroseries=self.distroseries)
387 self.assertEqual(6461, app.icon.size)
388
389+ def test_app_gets_version(self):
390+ call_command('import_for_purchase_apps')
391+
392+ app = Application.objects.get(package_name='hello',
393+ distroseries=self.distroseries)
394+ self.assertEqual('1.2.3', app.version)
395+
396
397 class ImportRatingsTestCase(TestCaseWithFactory):
398
399
400=== modified file 'src/webcatalog/tests/test_data/sca_apps.txt'
401--- src/webcatalog/tests/test_data/sca_apps.txt 2011-07-02 04:53:26 +0000
402+++ src/webcatalog/tests/test_data/sca_apps.txt 2012-03-13 15:19:18 +0000
403@@ -4,6 +4,7 @@
404 "signing_key_id": "",
405 "description": "MyAppTagline\nThe classic greeting, and a good example\r\n The GNU hello program produces a familiar, friendly greeting. It\r\n allows non-programmers to use a classic computer science tool which\r\n would otherwise be unavailable to them.\r\n .\r\n Seriously, though: this is an example of how to do a Debian package.\r\n It is the Debian version of the GNU Project's `hello world' program\r\n (which is itself an example for the GNU Project).",
406 "package_name": "hello",
407+ "version": "1.2.3-2ubuntu1~dev",
408 "series": {"maverick": ["i386", "amd64"], "natty": ["i386", "amd64"]},
409 "price": "2.50",
410 "archive_id": "launchpad_zematynnad2/myppa",
411@@ -15,4 +16,4 @@
412 "categories": "Audio",
413 "name": "MyApp"
414 }
415-]
416\ No newline at end of file
417+]
418
419=== modified file 'src/webcatalog/tests/test_views.py'
420--- src/webcatalog/tests/test_views.py 2012-03-12 15:43:37 +0000
421+++ src/webcatalog/tests/test_views.py 2012-03-13 15:19:18 +0000
422@@ -282,6 +282,27 @@
423 'has been sent.')
424 self.assertContains(response, 'Enter a valid e-mail address.')
425
426+ def test_version_and_label_displayed(self):
427+ app = self.factory.make_application(version='1.2.3',
428+ distroseries=self.factory.make_distroseries())
429+
430+ url = reverse('wc-package-detail', kwargs=dict(
431+ distro=app.distroseries.code_name, package_name=app.package_name))
432+ response = self.client.get(url)
433+
434+ self.assertContains(response, '<th>Version:</th>')
435+ self.assertContains(response, '<td>1.2.3</td>')
436+
437+ def test_version_label_not_displayed(self):
438+ app = self.factory.make_application(version='',
439+ distroseries=self.factory.make_distroseries())
440+
441+ url = reverse('wc-package-detail', kwargs=dict(
442+ distro=app.distroseries.code_name, package_name=app.package_name))
443+ response = self.client.get(url)
444+
445+ self.assertNotContains(response, '<th>Version</th>')
446+
447
448 class ApplicationDetailNoSeriesTestCase(TestCaseWithFactory):
449

Subscribers

People subscribed via source and target branches