root/trunk/djedna/catalog/tests.py

Revision 400, 48.0 kB (checked in by thomas, 10 months ago)

Added GPLv3 copyright notices

Line 
1 # (c) Copyright 2008 Thomas Bohmbach, Jr.
2 #
3 # This file is part of DJ Edna.
4 #
5 # DJ Edna is free software: you can redistribute it and/or modify it under the
6 # terms of the GNU General Public License as published by the Free
7 # Software Foundation, either version 3 of the License, or (at your option)
8 # any later version.
9 #
10 # DJ Edna is distributed in the hope that it will be useful, but
11 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 # or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
13 # more details.
14 #
15 # You should have received a copy of the GNU General Public License along with
16 # DJ Edna.  If not, see <http://www.gnu.org/licenses/>.
17
18 import os, datetime, urlparse, time
19 import logging as log
20
21 from django.conf import settings
22 from django.contrib.auth.models import User
23 from django.test import TestCase
24 from django.test.client import Client
25
26 try:
27     # The mod_python version is more efficient, so try importing it first.
28     from mod_python.util import parse_qsl
29 except ImportError:
30     from cgi import parse_qsl
31
32 from djedna.catalog.models import CatalogRoot, TrackFile, Track, Artist, Album
33 from djedna.catalog.models import CoverFile, ZipFile
34 from djedna.catalog.models import slugify
35 from djedna.catalog.urls import track_file_url, track_file_secure_url, zip_file_url, zip_file_id_url
36 from djedna.catalog.urls import artist_zip_slug_url, artist_m3u_slug_url, artist_xspf_slug_url
37 from djedna.catalog.urls import album_zip_slug_url, album_m3u_slug_url, album_xspf_slug_url
38 from djedna.catalog.urls import track_zip_slug_url, track_m3u_slug_url, track_xspf_slug_url, track_mp3_slug_url
39 from djedna.catalog.views import CATALOG_STAT_TYPE_ZIP, CATALOG_STAT_TYPE_M3U, CATALOG_STAT_TYPE_XSPF, CATALOG_STAT_TYPE_MP3
40 from djedna.statistic.models import TrackFileStat, ZipFileStat, CatalogStatType, ArtistStat, AlbumStat, TrackStat
41
42
43 class UserTestCase(TestCase):
44     fixtures = ['test/admin_user.json',]
45    
46     def setUp(self):
47         self.users = User.objects.all()
48    
49     def testAdminUser(self):
50         self.assertEquals(self.users.count(), 1)
51    
52
53
54 class CatalogRootTestCase(TestCase):
55     fixtures = []
56    
57     def setUp(self):
58         CatalogRoot.run_update_in_thread = False
59         self.root1 = CatalogRoot(name='catalog_root_1',
60                                 path=os.path.join(settings.FILE_ROOT, 'catalog_root_1'))
61         self.root2 = CatalogRoot(name='catalog_root_2',
62                                 path=os.path.join(settings.FILE_ROOT,'catalog_root_2'))
63    
64     def tearDown(self):
65         try: self.root1.delete()
66         except: pass
67    
68         try: self.root2.delete()
69         except: pass
70        
71     def testSetup(self):
72         self.assertEquals(TrackFile.objects.count(), 0)
73         self.assertEquals(Track.objects.count(), 0)
74         self.assertEquals(Artist.objects.count(), 0)
75         self.assertEquals(Album.objects.count(), 0)
76         self.assertEquals(CoverFile.objects.count(), 0)
77         self.assertEquals(ZipFile.objects.count(), 0)
78    
79     def testRoot1Update(self):
80         self.root1.save()
81
82         self.assertEquals(TrackFile.objects.count(), 11)
83         self.assertEquals(Track.objects.count(), 11)
84         self.assertEquals(Artist.objects.count(), 5)
85         self.assertEquals(Album.objects.count(), 3)
86         self.assertEquals(CoverFile.objects.count(), 7)
87         self.assertEquals(ZipFile.objects.count(), 0)
88        
89         artist1 = Artist.objects.get(name='Artist One')
90         self.assertEquals(artist1.track_count, 5)
91         self.assertEquals(artist1.album_count, 1)
92                
93         album1 = artist1.tracks.get(title='Track One').album
94         self.assertEquals(album1.title, 'Album One')
95         self.assertEquals(album1.track_count, 4)
96         self.assertEquals(album1.tracks.order_by('number')[3].title, 'Track Four')
97
98         vtrack1 = artist1.tracks.get(title='Various Track One')
99         self.assertEquals(vtrack1.album.title, 'Various Album One')
100         self.assertEquals(vtrack1.album.artist.name, settings.DEFAULT_MULTI_ARTIST_ALBUM_ARTIST_NAME)
101
102         artist4 = Artist.objects.get(name='Artist Four')
103         self.assertEquals(artist4.track_count, 4)
104         self.assertEquals(artist4.album_count, 1)
105         self.assertEquals(artist4.albums.all()[0].title, 'Album Two')
106
107     def testRoot2Update(self):
108         self.root2.save()
109        
110         self.assertEquals(TrackFile.objects.count(), 13)
111         self.assertEquals(Track.objects.count(), 13)
112         self.assertEquals(Artist.objects.count(), 5)
113         self.assertEquals(Album.objects.count(), 4)
114         self.assertEquals(CoverFile.objects.count(), 5)
115         self.assertEquals(ZipFile.objects.count(), 0)
116        
117         artist1 = Artist.objects.get(name='Artist One')
118         self.assertEquals(artist1.track_count, 4)
119         self.assertEquals(artist1.album_count, 1)
120        
121         album1 = artist1.tracks.get(title='Track One').album
122         self.assertEquals(album1.title, 'Album One')
123         self.assertEquals(album1.track_count, 4)
124         self.assertEquals(album1.tracks.order_by('number')[3].title, 'Track Four')
125        
126         artist4 = Artist.objects.get(name='Artist Four')
127         self.assertEquals(artist4.track_count, 3)
128         self.assertEquals(artist4.album_count, 1)
129         self.assertEquals(artist4.albums.all()[0].title, 'Album One')
130    
131     def testAllRootUpdate(self):
132         self.root1.save()
133         self.root2.save()
134        
135         self.assertEquals(TrackFile.objects.count(), 24)
136         self.assertEquals(Track.objects.count(), 20)
137         self.assertEquals(Artist.objects.count(), 7)
138         self.assertEquals(Album.objects.count(), 6)
139         self.assertEquals(CoverFile.objects.count(), 11)
140         self.assertEquals(ZipFile.objects.count(), 0)
141        
142         artist1 = Artist.objects.get(name='Artist One')
143         self.assertEquals(artist1.track_count, 5)
144         self.assertEquals(artist1.album_count, 1)
145        
146         album1 = artist1.tracks.get(title='Track One').album
147         self.assertEquals(album1.title, 'Album One')
148         self.assertEquals(album1.track_count, 4)
149         self.assertEquals(album1.tracks.order_by('number')[3].title, 'Track Four')
150        
151         vtrack1 = artist1.tracks.get(title='Various Track One')
152         self.assertEquals(vtrack1.album.title, 'Various Album One')
153         self.assertEquals(vtrack1.album.artist.name, settings.DEFAULT_MULTI_ARTIST_ALBUM_ARTIST_NAME)
154        
155         artist4 = Artist.objects.get(name='Artist Four')
156         self.assertEquals(artist4.track_count, 7)
157         self.assertEquals(artist4.album_count, 2)
158         self.assertEquals(artist4.albums.order_by('title')[0].title, 'Album One')
159         self.assertEquals(artist4.albums.order_by('title')[1].title, 'Album Two')
160
161     def testRoot1Delete(self):
162         self.root1.save()
163         self.root2.save()
164        
165         self.root1.delete()
166        
167         self.assertEquals(TrackFile.objects.count(), 13)
168         self.assertEquals(Track.objects.count(), 13)
169         self.assertEquals(Artist.objects.count(), 5)
170         self.assertEquals(Album.objects.count(), 4)
171         self.assertEquals(CoverFile.objects.count(), 6)
172         self.assertEquals(ZipFile.objects.count(), 0)
173        
174         artist1 = Artist.objects.get(name='Artist One')
175         self.assertEquals(artist1.track_count, 4)
176         self.assertEquals(artist1.album_count, 1)
177        
178         album1 = artist1.tracks.get(title='Track One').album
179         self.assertEquals(album1.title, 'Album One')
180         self.assertEquals(album1.track_count, 4)
181         self.assertEquals(album1.tracks.order_by('number')[3].title, 'Track Four')
182        
183         artist4 = Artist.objects.get(name='Artist Four')
184         self.assertEquals(artist4.track_count, 3)
185         self.assertEquals(artist4.album_count, 1)
186         self.assertEquals(artist4.albums.all()[0].title, 'Album One')
187
188     def testRoot2Delete(self):
189         self.root1.save()
190         self.root2.save()
191        
192         self.root2.delete()
193        
194         self.assertEquals(TrackFile.objects.count(), 11)
195         self.assertEquals(Track.objects.count(), 11)
196         self.assertEquals(Artist.objects.count(), 5)
197         self.assertEquals(Album.objects.count(), 3)
198         self.assertEquals(CoverFile.objects.count(), 7)
199         self.assertEquals(ZipFile.objects.count(), 0)
200        
201         artist1 = Artist.objects.get(name='Artist One')
202         self.assertEquals(artist1.track_count, 5)
203         self.assertEquals(artist1.album_count, 1)
204        
205         album1 = artist1.tracks.get(title='Track One').album
206         self.assertEquals(album1.title, 'Album One')
207         self.assertEquals(album1.track_count, 4)
208         self.assertEquals(album1.tracks.order_by('number')[3].title, 'Track Four')
209        
210         vtrack1 = artist1.tracks.get(title='Various Track One')
211         self.assertEquals(vtrack1.album.title, 'Various Album One')
212         self.assertEquals(vtrack1.album.artist.name, settings.DEFAULT_MULTI_ARTIST_ALBUM_ARTIST_NAME)
213        
214         artist4 = Artist.objects.get(name='Artist Four')
215         self.assertEquals(artist4.track_count, 4)
216         self.assertEquals(artist4.album_count, 1)
217         self.assertEquals(artist4.albums.all()[0].title, 'Album Two')
218
219    
220     def testAllRootDelete(self):
221         self.root1.save()
222         self.root2.save()
223        
224         self.root1.delete()
225         self.root2.delete()
226        
227         self.assertEquals(TrackFile.objects.count(), 0)
228         self.assertEquals(Track.objects.count(), 0)
229         self.assertEquals(Artist.objects.count(), 0)
230         self.assertEquals(Album.objects.count(), 0)
231         self.assertEquals(CoverFile.objects.count(), 1)
232         self.assertEquals(ZipFile.objects.count(), 0)
233
234        
235     def testLatestModifiedForTrackFiles(self):
236         self.root1.save()
237         self.root2.save()
238        
239         for track_file in TrackFile.objects.all():
240             file_mod = datetime.datetime.fromtimestamp(os.path.getmtime(track_file.full_path))
241             self.assertEquals(track_file.file_modified, file_mod)
242        
243     def testLatestModifiedForTracks(self):
244         # NOTE: this test assumes track_file dates are correct (tested above)
245         self.root1.save()
246         self.root2.save()
247        
248         for track in Track.objects.all():
249             file_mod = datetime.datetime.min
250             for track_file in track.track_files.all():
251                 file_mod = max(track_file.file_modified, file_mod)
252             self.assertEquals(track.latest_modified, file_mod)
253        
254     def testLatestModifiedForAlbums(self):
255         # NOTE: this test assumes track dates are correct (tested above)
256         self.root1.save()
257         self.root2.save()
258        
259         for album in Album.objects.all():
260             file_mod = datetime.datetime.min
261             for track in album.tracks.all():
262                 file_mod = max(track.latest_modified, file_mod)
263             self.assertEquals(album.latest_modified, file_mod)
264    
265     def testLatestModifiedForTrackArtists(self):
266         # NOTE: this test assumes track dates are correct (tested above)
267         self.root1.save()
268         self.root2.save()
269        
270         for artist in Artist.objects.all():
271             file_mod = datetime.datetime.min
272             for track in artist.tracks.all():
273                 file_mod = max(track.latest_modified, file_mod)
274                
275             # if this artist has tracks
276             if not file_mod == datetime.datetime.min:
277                 self.assertEquals(artist.latest_track_modified, file_mod)
278    
279     def testLatestModifiedForAlbumArtists(self):
280         # NOTE: this test assumes album dates are correct (tested above)
281         self.root1.save()
282         self.root2.save()
283        
284         for artist in Artist.objects.all():
285             file_mod = datetime.datetime.min
286             for album in artist.albums.all():
287                 file_mod = max(album.latest_modified, file_mod)
288                
289             # if this artist has albums
290             if not file_mod == datetime.datetime.min:
291                 self.assertEquals(artist.latest_album_modified, file_mod)
292    
293
294
295 class ArtistTestCase(TestCase):
296     fixtures = []
297    
298     def testSlug(self):
299         self.artist = Artist.objects.create(name='a')
300         self.assertEquals(self.artist.name, 'a')
301         self.assertEquals(self.artist.slug, 'a')
302         self.artist.name = 'b'
303         self.artist.save()
304         self.assertEquals(self.artist.name, 'b')
305         self.assertEquals(self.artist.slug, 'b')
306        
307     def testDisplayName(self):
308         wilco = Artist.objects.create(name='Wilco')
309         self.assertEquals(wilco.display_name, 'Wilco')
310        
311         winter_hours = Artist.objects.create(name='Winter Hours')
312         self.assertEquals(winter_hours.display_name, 'Winter Hours')
313
314         the_who = Artist.objects.create(name='Who, The')
315         self.assertEquals(the_who.display_name, 'The Who')
316
317         the_tragically_hip = Artist.objects.create(name='Tragically Hip, The')
318         self.assertEquals(the_tragically_hip.display_name, 'The Tragically Hip')
319
320         an_emotional_fish = Artist.objects.create(name='Emotional Fish, An')
321         self.assertEquals(an_emotional_fish.display_name, 'An Emotional Fish')
322        
323         the_the = Artist.objects.create(name='The, The')
324         self.assertEquals(the_the.display_name, 'The The')
325        
326         the_thermals = Artist.objects.create(name='Thermals, The')
327         self.assertEquals(the_thermals.display_name, 'The Thermals')
328        
329         los_lobos = Artist.objects.create(name='Lobos, Los')
330         self.assertEquals(los_lobos.display_name, 'Los Lobos')
331
332         tom_waits = Artist.objects.create(name='Waits, Tom')
333         self.assertEquals(tom_waits.display_name, 'Tom Waits')
334
335         kd_lang = Artist.objects.create(name='Lang, K.D.')
336         self.assertEquals(kd_lang.display_name, 'K.D. Lang')
337
338         sinead_oconnor = Artist.objects.create(name="O'Connor, Sinead")
339         self.assertEquals(sinead_oconnor.display_name, "Sinead O'Connor")
340
341         lou_reed_john_cale = Artist.objects.create(name='Reed, Lou / Cale, John')
342         self.assertEquals(lou_reed_john_cale.display_name, 'Lou Reed / John Cale')
343
344         colin_hay_band = Artist.objects.create(name='Hay, Colin Band')
345         self.assertEquals(colin_hay_band.display_name, 'Colin Hay Band')
346        
347         the_jimi_hendrix_experience = Artist.objects.create(name='Hendrix, Jimi Experience, The')
348         self.assertEquals(the_jimi_hendrix_experience.display_name, 'The Jimi Hendrix Experience')
349
350         neil_young_crazy_horse = Artist.objects.create(name='Young, Neil & Crazy Horse')
351         self.assertEquals(neil_young_crazy_horse.display_name, 'Neil Young & Crazy Horse')
352        
353         # the following are examples that are known to fail when "calculated"
354         # but we can set them manually
355         john_lee_hooker = Artist.objects.create(name='Hooker, John Lee', display_name='John Lee Hooker')
356         maniacs = Artist.objects.create(name='10,000 Maniacs', display_name='10,000 Suckiacs')
357         crosby_stills_nash_young = Artist.objects.create(name='Crosby, Stills, Nash And Young',
358                                                 display_name='Crosby, Stills, Nash And Young')
359         dylan_with_et_al = Artist.objects.create(name='Dylan, Bob with Roger McGuinn, Tom Petty, Neil Young, Eric Clapton, George Harrison',
360                                                 display_name='Bob Dylan with Roger McGuinn, Tom Petty, Neil Young, Eric Clapton, George Harrison')
361
362         maniacs.display_name = '10,000 Maniacs'
363         maniacs.save()
364        
365         john_lee_hooker.delete()
366         maniacs.delete()
367         crosby_stills_nash_young.delete()
368         dylan_with_et_al.delete()
369        
370         john_lee_hooker = Artist.objects.create(name='Hooker, John Lee')
371         self.assertEquals(john_lee_hooker.display_name, 'John Lee Hooker')
372
373         maniacs = Artist.objects.create(name='10,000 Maniacs')
374         self.assertEquals(maniacs.display_name, '10,000 Maniacs')
375
376         crosby_stills_nash_young = Artist.objects.create(name='Crosby, Stills, Nash And Young')
377         self.assertEquals(crosby_stills_nash_young.display_name, 'Crosby, Stills, Nash And Young')
378
379         dylan_with_et_al = Artist.objects.create(name='Dylan, Bob with Roger McGuinn, Tom Petty, Neil Young, Eric Clapton, George Harrison')
380         self.assertEquals(dylan_with_et_al.display_name, 'Bob Dylan with Roger McGuinn, Tom Petty, Neil Young, Eric Clapton, George Harrison')
381        
382 class SlugsTestCase(TestCase):
383     fixtures = []
384    
385     def setUp(self):
386         self.artists = {}
387         self.artists['a'] = Artist.objects.create(name='a').id
388         self.artists['b'] = Artist.objects.create(name='b').id
389         self.artists['c'] = Artist.objects.create(name='c').id
390        
391         # define the multi-artist artist and it's slug
392         from djedna.catalog.models import slugify
393         self.mutlti_artist = Artist.objects.create(name=settings.DEFAULT_MULTI_ARTIST_ALBUM_ARTIST_NAME)
394         self.multi_slug = slugify(settings.DEFAULT_MULTI_ARTIST_ALBUM_ARTIST_NAME)
395        
396         self.albums = {}
397         self.tracks = {}
398        
399         #Only artist 'a' appears on album 'a1'
400         artist_key = 'a'
401         artist = Artist.objects.get(id=self.artists[artist_key])
402         album_key = 'a1'
403         self.albums[album_key] = Album.objects.create(title='a', artist=artist).id
404         album = Album.objects.get(id=self.albums[album_key])
405         title = "%s_%s" % (artist.name, album.title)
406         if not self.tracks.get(artist_key, None):
407             self.tracks[artist_key] = {}
408         track_id = self.tracks[artist_key][album_key] = Track.objects.create(title=title, artist=artist, album=album).id
409         Track.objects.get(id=track_id).update_slug()
410        
411         #Only artist 'b' appears on album 'a2'
412         artist_key = 'b'
413         artist = Artist.objects.get(id=self.artists[artist_key])
414         album_key = 'a2'
415         self.albums[album_key] = Album.objects.create(title='a', artist=artist).id
416         album = Album.objects.get(id=self.albums[album_key])
417         title = "%s_%s" % (artist.name, album.title)
418         if not self.tracks.get(artist_key, None):
419             self.tracks[artist_key] = {}
420         self.tracks[artist_key][album_key] = Track.objects.create(title=title, artist=artist, album=album).id
421         Track.objects.get(id=self.tracks[artist_key][album_key]).update_slug()
422        
423         #Only artist 'b' appears on album 'a3'
424         artist_key = 'b'
425         artist = Artist.objects.get(id=self.artists[artist_key])
426         album_key = 'a3'
427         self.albums[album_key] = Album.objects.create(title='a', artist=artist).id
428         album = Album.objects.get(id=self.albums[album_key])
429         title = "%s_%s" % (artist.name, album.title)
430         if not self.tracks.get(artist_key, None):
431             self.tracks[artist_key] = {}
432         tracks = self.tracks[artist_key][album_key] = [Track.objects.create(title=title, artist=artist, album=album).id,]
433         Track.objects.get(id=tracks[0]).update_slug()
434         self.tracks[artist_key][album_key].append(Track.objects.create(title=title, artist=artist, album=album).id)
435         Track.objects.get(id=tracks[1]).update_slug()
436        
437         #All artists appear on all other albums
438         self.albums['b1'] = Album.objects.create(title='b', artist=self.mutlti_artist).id
439         self.albums['b2'] = Album.objects.create(title='b', artist=self.mutlti_artist).id
440         self.albums['b3'] = Album.objects.create(title='b', artist=self.mutlti_artist).id
441         self.albums['c1'] = Album.objects.create(title='c', artist=self.mutlti_artist).id
442         self.albums['c2'] = Album.objects.create(title='c', artist=self.mutlti_artist).id
443         for artist_id in self.artists.values():
444             artist = Artist.objects.get(id=artist_id)
445             if not self.tracks.get(artist.name, None):
446                 self.tracks[artist.name] = {}
447             for album_key, album_id in self.albums.items():
448                 album = Album.objects.get(id=album_id)
449                 if album.title != 'a':
450                     title = "%s_%s" % (artist.name, album.title)
451                     self.tracks[artist.name][album_key] = Track.objects.create(title=title, artist=artist, album=album).id
452                     Track.objects.get(id=self.tracks[artist.name][album_key]).update_slug()
453    
454     def testSetup(self):
455         #Test artist initial slugs
456         for artist_name in self.artists.keys():
457             self.assertEquals(Artist.objects.get(id=self.artists[artist_name]).slug, artist_name)
458        
459         #Test album initial slugs
460         self.assertEquals(Album.objects.get(id=self.albums['a1']).slug, 'a')
461         self.assertEquals(Album.objects.get(id=self.albums['a2']).slug, 'a-by-b')
462         self.assertEquals(Album.objects.get(id=self.albums['a3']).slug, 'a-by-b-2')
463         self.assertEquals(Album.objects.get(id=self.albums['b1']).slug, 'b')
464         self.assertEquals(Album.objects.get(id=self.albums['b2']).slug, 'b-by-'+self.multi_slug)
465         self.assertEquals(Album.objects.get(id=self.albums['b3']).slug, 'b-by-'+self.multi_slug + '-2')
466         self.assertEquals(Album.objects.get(id=self.albums['c1']).slug, 'c')
467         self.assertEquals(Album.objects.get(id=self.albums['c2']).slug, 'c-by-'+self.multi_slug)
468        
469         #Test track initial slugs
470         self.assertEquals(Track.objects.get(id=self.tracks['a']['a1']).slug, 'a_a')
471         self.assertEquals(Track.objects.get(id=self.tracks['b']['a2']).slug, 'b_a')
472         self.assertEquals(Track.objects.get(id=self.tracks['b']['a3'][0]).slug, 'b_a-from-a-by-b-2')
473         self.assertEquals(Track.objects.get(id=self.tracks['b']['a3'][1]).slug, 'b_a-from-a-by-b-2-2')
474        
475         self.assertEquals(Track.objects.get(id=self.tracks['a']['b1']).slug, 'a_b')
476         self.assertEquals(Track.objects.get(id=self.tracks['b']['b1']).slug, 'b_b')
477         self.assertEquals(Track.objects.get(id=self.tracks['c']['b1']).slug, 'c_b')
478         self.assertEquals(Track.objects.get(id=self.tracks['a']['b2']).slug, 'a_b-from-b-by-'+self.multi_slug)
479         self.assertEquals(Track.objects.get(id=self.tracks['b']['b2']).slug, 'b_b-from-b-by-'+self.multi_slug)
480         self.assertEquals(Track.objects.get(id=self.tracks['c']['b2']).slug, 'c_b-from-b-by-'+self.multi_slug)
481         self.assertEquals(Track.objects.get(id=self.tracks['a']['b3']).slug, 'a_b-from-b-by-'+self.multi_slug+'-2')
482         self.assertEquals(Track.objects.get(id=self.tracks['b']['b3']).slug, 'b_b-from-b-by-'+self.multi_slug+'-2')
483         self.assertEquals(Track.objects.get(id=self.tracks['c']['b3']).slug, 'c_b-from-b-by-'+self.multi_slug+'-2')
484    
485
486 class DownloadTestCase(TestCase):
487     def setUp(self):
488         self.client = Client()
489         CatalogRoot.run_update_in_thread = False
490         self.user_password = 'test'
491         self.user = User.objects.create_user('tester', 'test@gumption.com', password=self.user_password)
492         self.user.save()
493         self.root1 = CatalogRoot(name='catalog_root_1',
494                                  path=os.path.join(settings.FILE_ROOT, 'catalog_root_1'))
495         self.root1.save()
496    
497     def testDownloadTrack(self):
498         track = Track.objects.all()[0]
499         track_m3u_url = os.path.join(track.get_absolute_url(), 'm3u/')
500         track_file = track.track_file
501         #Non-secure URL, not logged in
502         track_file_mp3_url = track_file_url(track_file)
503         response = self.client.get(track_file_mp3_url)
504         self.failUnless(response)
505         self.failUnless(response.status_code==403)
506         #Secure URL, not logged in
507         secure_track_file_mp3_url = track_file_secure_url(track_file, self.user)
508         (scheme, location, path, query, fragment) = urlparse.urlsplit(secure_track_file_mp3_url)
509         response = self.client.get(path, data=parse_qsl(query))
510         self.failUnless(response)
511         self.failUnless(response.status_code==200)
512         #Log in via a secured URL
513         self.failUnless(self.client.login(username=self.user.username, password=self.user_password))
514         response = self.client.get(track_m3u_url)
515         self.failUnless(response)
516         #Non-secure URL, logged in
517         response = self.client.get(track_file_mp3_url)
518         self.failUnless(response.status_code==200)
519         #Secure URL, logged in
520         (scheme, location, path, query, fragment) = urlparse.urlsplit(secure_track_file_mp3_url)
521         response = self.client.get(path, data=parse_qsl(query))
522         self.failUnless(response)
523         self.failUnless(response.status_code==200)
524    
525     def testDownloadZipFileDjangoAuth(self):
526         track = Track.objects.all()[0]
527         track_zip_url = os.path.join(track.get_absolute_url(), 'zip/')
528         (scheme, location, path, query, fragment) = urlparse.urlsplit(track_zip_url)
529         #Not logged in
530         response = self.client.get(path)
531         self.failUnless(response)
532         self.failUnless(response.status_code==302)
533         #Logged in
534         self.failUnless(self.client.login(username=self.user.username, password=self.user_password))
535         response = self.client.get(path)
536         self.failUnless(response)
537         self.failUnless(response.status_code==200)
538    
539
540 class TrackFileStatTestCase(TestCase):
541     def setUp(self):
542         self.client = Client()
543         CatalogRoot.run_update_in_thread = False
544         self.user_password = 'test'
545         self.user = User.objects.create_user('tester', 'test@gumption.com', password=self.user_password)
546         self.user.save()
547         self.root1 = CatalogRoot(name='catalog_root_1',
548                                  path=os.path.join(settings.FILE_ROOT, 'catalog_root_1'))
549         self.root1.save()
550    
551     def testLogTrackFileNonSecureUrlNoLogin(self):
552         track = Track.objects.all()[0]
553         track_file_mp3_url = track_file_url(track.track_file)
554         response = self.client.get(track_file_mp3_url)
555         self.assertTrackFileStat(track_file_mp3_url, track, response)
556    
557     def testLogTrackFileSecureUrlNoLogin(self):
558         track = Track.objects.all()[0]
559         secure_track_file_mp3_url = track_file_secure_url(track.track_file, self.user)
560         (scheme, location, path, query, fragment) = urlparse.urlsplit(secure_track_file_mp3_url)
561         response = self.client.get(path, data=parse_qsl(query))
562         self.assertTrackFileStat(secure_track_file_mp3_url, track, response)
563    
564     def testLogTrackFileNonSecureUrlLogin(self):
565         track = Track.objects.all()[0]
566         track_m3u_url = os.path.join(track.get_absolute_url(), 'm3u/')
567         track_file_mp3_url = track_file_url(track.track_file)
568         #Log in via a secured URL
569         self.failUnless(self.client.login(username=self.user.username, password=self.user_password))
570         response = self.client.get(track_m3u_url)
571         self.failUnless(response)
572         response = self.client.get(track_file_mp3_url)
573         self.assertTrackFileStat(track_file_mp3_url, track, response)
574    
575     def testLogTrackFileSecureUrlLogin(self):
576         track = Track.objects.all()[0]
577         track_m3u_url = os.path.join(track.get_absolute_url(), 'm3u/')
578         secure_track_file_mp3_url = track_file_secure_url(track.track_file, self.user)
579         #Log in via a secured URL
580         self.failUnless(self.client.login(username=self.user.username, password=self.user_password))
581         response = self.client.get(track_m3u_url)
582         self.failUnless(response)
583         (scheme, location, path, query, fragment) = urlparse.urlsplit(secure_track_file_mp3_url)
584         response = self.client.get(path, data=parse_qsl(query))
585         self.assertTrackFileStat(secure_track_file_mp3_url, track, response)
586    
587     def assertTrackFileStat(self, url, track, response):
588         self.failUnless(response, "No response")
589         (scheme, location, path, query, fragment) = urlparse.urlsplit(url)
590         track_file_stat = TrackFileStat.objects.get(track_file=track.track_file)
591         self.assertEqual(track_file_stat.request_stat.path, urlparse.urlunsplit(('', '', path, query, '')))
592         self.assertEqual(track_file_stat.request_stat.http_host, location)
593         self.assertEqual(track_file_stat.request_stat.status_code, response.status_code)
594    
595
596 class ZipFileStatTestCase(TestCase):
597     def setUp(self):
598         self.client = Client()
599         CatalogRoot.run_update_in_thread = False
600         self.user_password = 'test'
601         self.user = User.objects.create_user('tester', 'test@gumption.com', password=self.user_password)
602         self.user.save()
603         self.root1 = CatalogRoot(name='catalog_root_1',
604                                  path=os.path.join(settings.FILE_ROOT, 'catalog_root_1'))
605         self.root1.save()
606    
607     def testLogZipFile(self):
608         track = Track.objects.all()[0]
609         track_zip_url = os.path.join(track.get_absolute_url(), 'zip/')
610         (scheme, location, path, query, fragment) = urlparse.urlsplit(track_zip_url)
611         self.failUnless(self.client.login(username=self.user.username, password=self.user_password))
612         response = self.client.get(path)
613         self.failUnless(response, "No response")
614         path = zip_file_id_url(track.zip_file)
615         redirect_response = self.client.get(path)
616         path = zip_file_url(track.zip_file)
617         redirect_response = self.client.get(path)
618         self.failUnless(redirect_response, "No redirect response")
619         self.assertZipFileStat(path, track, redirect_response)
620    
621     def assertZipFileStat(self, url, track, response):
622         (scheme, location, path, query, fragment) = urlparse.urlsplit(url)
623         zip_file_stat = ZipFileStat.objects.get(zip_file=track.zip_file)
624         self.assertEqual(zip_file_stat.request_stat.path, urlparse.urlunsplit(('', '', path, query, '')))
625         self.assertEqual(zip_file_stat.request_stat.http_host, location)
626         self.assertEqual(zip_file_stat.request_stat.status_code, response.status_code)
627    
628
629
630 class ArtistStatTestCase(TestCase):
631     def setUp(self):
632         self.user1_password = 'test'
633         self.user1 = User.objects.create_user('tester', 'test@gumption.com', password=self.user1_password)
634         self.user1.save()
635         self.client1 = Client()
636         #Change to the following post-0.96
637         self.client1.login(username=self.user1.username, password=self.user1_password)
638        
639         self.user2_password = 'test2'
640         self.user2 = User.objects.create_user('tester2', 'test2@gumption.com', password=self.user2_password)
641         self.user2.save()
642         self.client2 = Client()
643         #Change to the following post-0.96
644         self.client2.login(username=self.user2.username, password=self.user2_password)
645        
646         CatalogRoot.run_update_in_thread = False
647         self.root1 = CatalogRoot(name='catalog_root_1',
648                                  path=os.path.join(settings.FILE_ROOT, 'catalog_root_1'))
649         self.root1.save()
650         self.artist1 = Artist.objects.all()[0]
651         self.artist2 = Artist.objects.all()[1]
652    
653     def testZipStat(self):
654         catalog_stat_type = CatalogStatType.objects.get_for_name(CATALOG_STAT_TYPE_ZIP)
655         artist1_url = artist_zip_slug_url(self.artist1)
656         artist2_url = artist_zip_slug_url(self.artist2)
657         #This should create a stat
658         self.assertArtistStat(self.client1, artist1_url, self.artist1, self.user1, catalog_stat_type)
659         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
660         self.assertArtistStat(self.client1, artist1_url, self.artist1, self.user1, None)
661         #This should create a stat, since it's a different artist
662         self.assertArtistStat(self.client1, artist2_url, self.artist2, self.user1, catalog_stat_type)
663         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
664         self.assertArtistStat(self.client1, artist2_url, self.artist2, self.user1, None)
665         #This should create a stat, since it's a different user
666         self.assertArtistStat(self.client2, artist2_url, self.artist2, self.user2, catalog_stat_type)
667         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
668         self.assertArtistStat(self.client2, artist2_url, self.artist2, self.user2, None)
669    
670     def testM3UStat(self):
671         catalog_stat_type = CatalogStatType.objects.get_for_name(CATALOG_STAT_TYPE_M3U)
672         artist1_url = artist_m3u_slug_url(self.artist1)
673         artist2_url = artist_m3u_slug_url(self.artist2)
674         #This should create a stat
675         self.assertArtistStat(self.client1, artist1_url, self.artist1, self.user1, catalog_stat_type)
676         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
677         self.assertArtistStat(self.client1, artist1_url, self.artist1, self.user1, None)
678         #This should create a stat, since it's a different artist
679         self.assertArtistStat(self.client1, artist2_url, self.artist2, self.user1, catalog_stat_type)
680         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
681         self.assertArtistStat(self.client1, artist2_url, self.artist2, self.user1, None)
682         #This should create a stat, since it's a different user
683         self.assertArtistStat(self.client2, artist2_url, self.artist2, self.user2, catalog_stat_type)
684         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
685         self.assertArtistStat(self.client2, artist2_url, self.artist2, self.user2, None)
686    
687     def testXSPFStat(self):
688         catalog_stat_type = CatalogStatType.objects.get_for_name(CATALOG_STAT_TYPE_XSPF)
689         artist1_url = artist_xspf_slug_url(self.artist1)
690         artist2_url = artist_xspf_slug_url(self.artist2)
691         #This should create a stat
692         self.assertArtistStat(self.client1, artist1_url, self.artist1, self.user1, catalog_stat_type)
693         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
694         self.assertArtistStat(self.client1, artist1_url, self.artist1, self.user1, None)
695         #This should create a stat, since it's a different artist
696         self.assertArtistStat(self.client1, artist2_url, self.artist2, self.user1, catalog_stat_type)
697         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
698         self.assertArtistStat(self.client1, artist2_url, self.artist2, self.user1, None)
699         #This should create a stat, since it's a different user
700         self.assertArtistStat(self.client2, artist2_url, self.artist2, self.user2, catalog_stat_type)
701         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
702         self.assertArtistStat(self.client2, artist2_url, self.artist2, self.user2, None)
703    
704     def assertArtistStat(self, client, artist_url, artist, user, catalog_stat_type):
705         before_count = ArtistStat.objects.count()
706         (scheme, location, path, query, fragment) = urlparse.urlsplit(artist_url)
707         response = client.get(path)
708         self.failUnless(response, "NO RESPONSE: path=%s" % path)
709         self.assertEqual(response.status_code, 200)
710         if catalog_stat_type:
711             try:
712                 artist_stat = ArtistStat.objects.get(artist=artist, catalog_stat_type=catalog_stat_type, request_stat__user=user)
713             except ArtistStat.DoesNotExist:
714                 self.fail("NO STAT FOUND: path=%s  artist=%s  user=%s  catalog_stat_type=%s" % (path, artist, user, catalog_stat_type))
715             self.assertEqual(artist_stat.request_stat.path, urlparse.urlunsplit(('', '', path, query, '')))
716             self.assertEqual(artist_stat.request_stat.http_host, location)
717             self.assertEqual(artist_stat.request_stat.status_code, response.status_code)
718             self.assertEqual(ArtistStat.objects.count(), before_count+1)
719         else:
720             self.assertEqual(ArtistStat.objects.count(), before_count)
721
722
723 class AlbumStatTestCase(TestCase):
724     def setUp(self):
725         self.user1_password = 'test'
726         self.user1 = User.objects.create_user('tester', 'test@gumption.com', password=self.user1_password)
727         self.user1.save()
728         self.client1 = Client()
729         #Change to the following post-0.96
730         self.client1.login(username=self.user1.username, password=self.user1_password)
731        
732         self.user2_password = 'test2'
733         self.user2 = User.objects.create_user('tester2', 'test2@gumption.com', password=self.user2_password)
734         self.user2.save()
735         self.client2 = Client()
736         #Change to the following post-0.96
737         self.client2.login(username=self.user2.username, password=self.user2_password)
738        
739         CatalogRoot.run_update_in_thread = False
740         self.root1 = CatalogRoot(name='catalog_root_1',
741                                  path=os.path.join(settings.FILE_ROOT, 'catalog_root_1'))
742         self.root1.save()
743         self.album1 = Album.objects.all()[0]
744         self.album2 = Album.objects.all()[1]
745    
746     def testZipStat(self):
747         catalog_stat_type = CatalogStatType.objects.get_for_name(CATALOG_STAT_TYPE_ZIP)
748         album1_url = album_zip_slug_url(self.album1)
749         album2_url = album_zip_slug_url(self.album2)
750         #This should create a stat
751         self.assertAlbumStat(self.client1, album1_url, self.album1, self.user1, catalog_stat_type)
752         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
753         self.assertAlbumStat(self.client1, album1_url, self.album1, self.user1, None)
754         #This should create a stat, since it's a different album
755         self.assertAlbumStat(self.client1, album2_url, self.album2, self.user1, catalog_stat_type)
756         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
757         self.assertAlbumStat(self.client1, album2_url, self.album2, self.user1, None)
758         #This should create a stat, since it's a different user
759         self.assertAlbumStat(self.client2, album2_url, self.album2, self.user2, catalog_stat_type)
760         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
761         self.assertAlbumStat(self.client2, album2_url, self.album2, self.user2, None)
762        
763     def testM3UStat(self):
764         catalog_stat_type = CatalogStatType.objects.get_for_name(CATALOG_STAT_TYPE_M3U)
765         album1_url = album_m3u_slug_url(self.album1)
766         album2_url = album_m3u_slug_url(self.album2)
767         #This should create a stat
768         self.assertAlbumStat(self.client1, album1_url, self.album1, self.user1, catalog_stat_type)
769         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
770         self.assertAlbumStat(self.client1, album1_url, self.album1, self.user1, None)
771         #This should create a stat, since it's a different album
772         self.assertAlbumStat(self.client1, album2_url, self.album2, self.user1, catalog_stat_type)
773         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
774         self.assertAlbumStat(self.client1, album2_url, self.album2, self.user1, None)
775         #This should create a stat, since it's a different user
776         self.assertAlbumStat(self.client2, album2_url, self.album2, self.user2, catalog_stat_type)
777         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
778         self.assertAlbumStat(self.client2, album2_url, self.album2, self.user2, None)
779    
780     def testXSPFStat(self):
781         catalog_stat_type = CatalogStatType.objects.get_for_name(CATALOG_STAT_TYPE_XSPF)
782         album1_url = album_xspf_slug_url(self.album1)
783         album2_url = album_xspf_slug_url(self.album2)
784         #This should create a stat
785         self.assertAlbumStat(self.client1, album1_url, self.album1, self.user1, catalog_stat_type)
786         #This shouldn't create a stat, since we ignore multiple rapid requests for the same resource
787         self.assertAlbumStat(self.client1, album1_url, self.album1, self.user1, None)
788         #This should create a stat, since it's a different album
789         self.assertAlbumStat(self.client1, album2_url, self.album2, self.user1, catalog_stat_type)
790