Merge lp:~michael.nelson/ubuntu-webcatalog/953306-display-app-version into lp:ubuntu-webcatalog
- 953306-display-app-version
- Merge into trunk
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 | ||||
Related bugs: |
|
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.
`fab test`
- 82. By Michael Nelson
-
Moved inline immport.
Anthony Lenton (elachuni) wrote : | # |
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_
>
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_
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_
Yeah, with test_existing_
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!
Anthony Lenton (elachuni) wrote : | # |
Hah, yep, I missed the test completely and thought that the form update was for import_
Thanks!
Preview Diff
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 |
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.