Completed
Push — master ( 6a4ed1...7ae2ee )
by
unknown
44s
created

PartialUpdateTest   A

Complexity

Total Complexity 2

Size/Duplication

Total Lines 45
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 45
rs 10
c 1
b 0
f 0
wmc 2

2 Methods

Rating   Name   Duplication   Size   Complexity  
A test_update() 0 22 1
A test_create() 0 16 1
1
# coding: utf8
2
3
"""
4
This software is licensed under the Apache 2 license, quoted below.
5
6
Copyright 2014 Crystalnix Limited
7
8
Licensed under the Apache License, Version 2.0 (the "License"); you may not
9
use this file except in compliance with the License. You may obtain a copy of
10
the License at
11
12
    http://www.apache.org/licenses/LICENSE-2.0
13
14
Unless required by applicable law or agreed to in writing, software
15
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17
License for the specific language governing permissions and limitations under
18
the License.
19
"""
20
from __future__ import unicode_literals
21
from builtins import bytes, range
22
23
import base64
24
from datetime import datetime, timedelta, date
25
from uuid import UUID
26
27
from django.core.urlresolvers import reverse
28
from django.contrib.auth import get_user_model
29
from django.core.files.uploadedfile import SimpleUploadedFile
30
from django.conf import settings
31
32
from lxml.builder import E
33
from rest_framework import status
34
from rest_framework.test import APITestCase, APIClient
35
from bitmapist import mark_event
36
from freezegun import freeze_time
37
import pytz
38
import factory
39
40
from omaha_server.utils import is_private
41
from omaha.statistics import userid_counting, get_users_versions, get_channel_statistics
42
from omaha.utils import redis
43
from omaha.serializers import (
44
    AppSerializer,
45
    DataSerializer,
46
    PlatformSerializer,
47
    ChannelSerializer,
48
    VersionSerializer,
49
    ActionSerializer,
50
    StatisticsMonthsSerializer,
51
    ServerVersionSerializer,
52
    PartialUpdateSerializer,
53
)
54
from omaha.factories import ApplicationFactory, DataFactory, PlatformFactory, ChannelFactory, VersionFactory, ActionFactory, PartialUpdateFactory
55
from omaha.models import Application, Data, Channel, Platform, Version, Action, PartialUpdate
56
from omaha.tests import fixtures, OverloadTestStorageMixin
57
from omaha.tests.utils import temporary_media_root, create_app_xml
58
from sparkle.models import SparkleVersion
59
from sparkle.statistics import userid_counting as mac_userid_counting
60
User = get_user_model()
61
62
63
class BaseTest(object):
64
    url = None
65
    url_args = ()
66
    url_detail = None
67
    factory = None
68
    serializer = None
69
    maxDiff = None
70
    is_private = True
71
72
    def _is_private(self):
73
        if not self.is_private and not settings.IS_PRIVATE:
74
            return True
75
        elif self.is_private and settings.IS_PRIVATE:
76
            return True
77
        else:
78
            return False
79
80
    def setUp(self):
81
        self.objects = self.factory.create_batch(10)
82
        self.user = User.objects.create_user(username='test', password='secret', email='[email protected]')
83
        self.client.credentials(
84
            HTTP_AUTHORIZATION='Basic %s' % base64.b64encode(bytes('{}:{}'.format('test', 'secret'), 'utf8')).decode())
85
86
    def test_unauthorized(self):
87
        if not self._is_private():
88
            return
89
        client = APIClient()
90
        response = client.get(reverse(self.url, args=self.url_args), format='json')
91
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
92
93
    def test_list(self):
94
        if not self._is_private():
95
            return
96
        response = self.client.get(reverse(self.url, args=self.url_args), format='json')
97
        self.assertEqual(response.status_code, status.HTTP_200_OK)
98
        self.assertEqual(len(response.data), 10)
99
        self.assertEqual(self.serializer(self.objects, many=True).data, response.data[::-1])
100
101
    def test_detail(self):
102
        if not self._is_private():
103
            return
104
        obj = self.objects[0]
105
        url = reverse(self.url_detail, kwargs=dict(pk=obj.pk))
106
107
        response = self.client.get(url, format='json')
108
        self.assertEqual(response.status_code, status.HTTP_200_OK)
109
        self.assertDictEqual(response.data, self.serializer(obj).data)
110
111
112
class AppTest(BaseTest, APITestCase):
113
    url = 'application-list'
114
    url_detail = 'application-detail'
115
    factory = ApplicationFactory
116
    serializer = AppSerializer
117
118
    @is_private()
119
    def test_create(self):
120
        data = dict(id='test_id', name='test_name', data_set=[])
121
        response = self.client.post(reverse(self.url
122
                                            ), data, format='json')
123
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
124
        obj = Application.objects.get(id=response.data['id'])
125
        self.assertEqual(response.data, self.serializer(obj).data)
126
127
    @is_private()
128
    def test_update(self):
129
        data = dict(id='test_id', name='test_name', data_set=[])
130
        response = self.client.post(reverse(self.url), data, format='json')
131
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
132
        obj_id = response.data['id']
133
        obj = Application.objects.get(id=obj_id)
134
        self.assertEqual(obj.name, 'test_name')
135
        url = reverse(self.url_detail, kwargs=dict(pk=obj_id))
136
        response = self.client.patch(url, dict(name='test_other_name'))
137
        self.assertEqual(response.status_code, status.HTTP_200_OK)
138
        obj = Application.objects.get(id=obj_id)
139
        self.assertEqual(obj.name, 'test_other_name')
140
141 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
142
class DataTest(BaseTest, APITestCase):
143
    url = 'data-list'
144
    url_detail = 'data-detail'
145
    factory = DataFactory
146
    serializer = DataSerializer
147
148
    @is_private()
149
    def test_create(self):
150
        app = ApplicationFactory.create()
151
        data = dict(name=0, app=app.pk)
152
        response = self.client.post(reverse(self.url), data, format='json')
153
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
154
        obj = Data.objects.get(id=response.data['id'])
155
        self.assertEqual(response.data, self.serializer(obj).data)
156
157
    @is_private()
158
    def test_update(self):
159
        app = ApplicationFactory.create()
160
        data = dict(name=0, app=app.pk)
161
        response = self.client.post(reverse(self.url), data, format='json')
162
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
163
        obj_id = response.data['id']
164
        obj = Data.objects.get(id=obj_id)
165
        self.assertEqual(obj.name, 0)
166
        url = reverse(self.url_detail, kwargs=dict(pk=obj_id))
167
        response = self.client.patch(url, dict(name=1))
168
        self.assertEqual(response.status_code, status.HTTP_200_OK)
169
        obj = Data.objects.get(id=obj_id)
170
        self.assertEqual(obj.name, 1)
171 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
172
173
class PlatformTest(BaseTest, APITestCase):
174
    url = 'platform-list'
175
    url_detail = 'platform-detail'
176
    factory = PlatformFactory
177
    serializer = PlatformSerializer
178
179
    @is_private()
180
    def test_list(self):
181
        super(PlatformTest, self).test_list()
182
183
    @is_private()
184
    def test_create(self):
185
        data = dict(name='test_name')
186
        response = self.client.post(reverse(self.url), data, format='json')
187
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
188
        obj = Platform.objects.get(id=response.data['id'])
189
        self.assertEqual(response.data, self.serializer(obj).data)
190
191
    @is_private()
192
    def test_create(self):
193
        data = dict(name='test_name')
194
        response = self.client.post(reverse(self.url), data, format='json')
195
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
196
        obj_id = response.data['id']
197
        obj = Platform.objects.get(id=obj_id)
198
        self.assertEqual(obj.name, 'test_name')
199
        url = reverse(self.url_detail, kwargs=dict(pk=obj_id))
200
        response = self.client.patch(url, dict(name='test_name2'))
201
        self.assertEqual(response.status_code, status.HTTP_200_OK)
202
        obj = Platform.objects.get(id=obj_id)
203
        self.assertEqual(obj.name, 'test_name2')
204 View Code Duplication
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
205
206
class ChannelTest(BaseTest, APITestCase):
207
    url = 'channel-list'
208
    url_detail = 'channel-detail'
209
    factory = ChannelFactory
210
    serializer = ChannelSerializer
211
212
    @is_private()
213
    def test_create(self):
214
        data = dict(name='test_name')
215
        response = self.client.post(reverse(self.url), data, format='json')
216
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
217
        obj = Channel.objects.get(id=response.data['id'])
218
        self.assertEqual(response.data, self.serializer(obj).data)
219
220
    @is_private()
221
    def test_update(self):
222
        data = dict(name='test_name')
223
        response = self.client.post(reverse(self.url), data, format='json')
224
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
225
        obj_id = response.data['id']
226
        obj = Channel.objects.get(id=obj_id)
227
        self.assertEqual(response.data, self.serializer(obj).data)
228
        url = reverse(self.url_detail, kwargs=dict(pk=obj_id))
229
        response = self.client.patch(url, dict(name='test_name2'))
230
        self.assertEqual(response.status_code, status.HTTP_200_OK)
231
        obj = Channel.objects.get(id=obj_id)
232
        self.assertEqual(obj.name, 'test_name2')
233
234
235
class VersionTest(OverloadTestStorageMixin, BaseTest, APITestCase):
236
    url = 'version-list'
237
    url_detail = 'version-detail'
238
    factory = VersionFactory
239
    serializer = VersionSerializer
240
    model = Version
241
242
    @temporary_media_root(MEDIA_URL='http://cache.pack.google.com/edgedl/chrome/install/782.112/')
243
    def setUp(self):
244
        super(VersionTest, self).setUp()
245
246
    @is_private()
247
    @temporary_media_root(MEDIA_URL='http://cache.pack.google.com/edgedl/chrome/install/782.112/')
248 View Code Duplication
    def test_detail(self):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
249
        super(VersionTest, self).test_detail()
250
251
    @is_private()
252
    @temporary_media_root(MEDIA_URL='http://cache.pack.google.com/edgedl/chrome/install/782.112/')
253
    def test_list(self):
254
        super(VersionTest, self).test_list()
255
256
    @is_private()
257
    @temporary_media_root(MEDIA_URL='http://cache.pack.google.com/edgedl/chrome/install/782.112/')
258
    def test_create(self):
259
        data = dict(
260
            app=ApplicationFactory.create().id,
261
            platform=PlatformFactory.create().id,
262
            channel=ChannelFactory.create().id,
263
            version='1.2.3.4',
264
            file=SimpleUploadedFile("chrome.exe", b'content'),
265
        )
266
        response = self.client.post(reverse(self.url), data)
267
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
268
        version = Version.objects.get(id=response.data['id'])
269
        self.assertEqual(response.data, self.serializer(version).data)
270
        self.assertEqual(version.file_size, len(b'content'))
271
        self.assertTrue(version.is_enabled)
272
273
    @is_private()
274
    @temporary_media_root(MEDIA_URL='http://cache.pack.google.com/edgedl/chrome/install/782.112/')
275
    def test_update(self):
276
        data = dict(
277
            app=ApplicationFactory.create().id,
278
            platform=PlatformFactory.create().id,
279
            channel=ChannelFactory.create().id,
280
            version='1.2.3.4',
281
            file=SimpleUploadedFile("chrome.exe", b'content'),
282
            is_enabled=False,
283
        )
284
        response = self.client.post(reverse(self.url), data)
285
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
286
        obj_id = response.data['id']
287
        version = Version.objects.get(id=obj_id)
288
        self.assertEqual(version.file_size, len(b'content'))
289
        self.assertFalse(version.is_enabled)
290
        url = reverse(self.url_detail, kwargs=dict(pk=obj_id))
291 View Code Duplication
        response = self.client.patch(url, dict(is_enabled=True))
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
292
        self.assertEqual(response.status_code, status.HTTP_200_OK)
293
        version = Version.objects.get(id=obj_id)
294
        self.assertEqual(version.file_size, len(b'content'))
295
        self.assertTrue(version.is_enabled)
296
297
298
class ActionTest(BaseTest, APITestCase):
299
    url = 'action-list'
300
    url_detail = 'action-detail'
301
    factory = ActionFactory
302
    serializer = ActionSerializer
303
304
    @is_private()
305
    def test_create(self):
306
        version = VersionFactory.create()
307
        data = dict(event=1, version=version.pk)
308
        response = self.client.post(reverse(self.url), data, format='json')
309
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
310
        obj = Action.objects.get(id=response.data['id'])
311
        self.assertEqual(response.data, self.serializer(obj).data)
312
313
    @is_private()
314
    def test_update(self):
315
        version = VersionFactory.create()
316
        data = dict(event=1, version=version.pk)
317
        response = self.client.post(reverse(self.url), data, format='json')
318
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
319
        obj_id = response.data['id']
320
        obj = Action.objects.get(id=obj_id)
321
        self.assertEqual(response.data, self.serializer(obj).data)
322
        url = reverse(self.url_detail, kwargs=dict(pk=obj_id))
323
        response = self.client.patch(url, dict(event=2))
324
        self.assertEqual(response.status_code, status.HTTP_200_OK)
325
        obj = Action.objects.get(id=obj_id)
326
        self.assertEqual(obj.event, 2)
327
328
329
class LiveStatistics(APITestCase):
330
    maxDiff = None
331
332
    def _generate_fake_statistics(self):
333
        date = datetime(2016, 2, 13, 0)
334
        for i in range(self.n_hours):
335
            for id in range(0, i):
336
                mark_event('request:app:win:2.0.0.0', id, now=date, track_hourly=True)
337
                mark_event('request:app:mac:4.0.0.1', id, now=date, track_hourly=True)
338
                mark_event('request:app:win:%s:2.0.0.0' % self.channel2.name,
339
                           id, now=date, track_hourly=True)
340
                mark_event('request:app:mac:%s:4.0.0.1' % self.channel2.name,
341
                           id, now=date, track_hourly=True)
342
            for id in range(i, self.n_hours):
343
                mark_event('request:app:win:1.0.0.0', id, now=date, track_hourly=True)
344
                mark_event('request:app:mac:3.0.0.0', id, now=date, track_hourly=True)
345
                mark_event('request:app:win:%s:1.0.0.0' % self.channel.name,
346
                           id, now=date, track_hourly=True)
347
                mark_event('request:app:mac:%s:3.0.0.0' % self.channel.name,
348
                           id, now=date, track_hourly=True)
349
            date += timedelta(hours=1)
350
351
    def setUp(self):
352
        self.user = User.objects.create_user(username='test', password='secret', email='[email protected]')
353
        self.client.credentials(
354
            HTTP_AUTHORIZATION='Basic %s' % base64.b64encode(bytes('{}:{}'.format('test', 'secret'), 'utf8')).decode())
355
356
        redis.flushdb()
357
        self.app = Application.objects.create(id='app', name='app')
358
        self.channel = Channel.objects.create(name='stable')
359
        self.channel2 = Channel.objects.create(name='alpha')
360
        self.platform = Platform.objects.create(name='win')
361
        Platform.objects.create(name='mac')
362
        self.version1 = Version.objects.create(
363
            app=self.app,
364
            platform=self.platform,
365
            channel=self.channel,
366
            version='1.0.0.0',
367
            file=SimpleUploadedFile('./chrome_installer.exe', False))
368
369
        self.version2 = Version.objects.create(
370
            app=self.app,
371
            platform=self.platform,
372
            channel=self.channel2,
373
            version='2.0.0.0',
374
            file=SimpleUploadedFile('./chrome_installer.exe', False))
375
376
        self.sparkle_version1 = SparkleVersion.objects.create(
377
            app=self.app,
378
            channel=self.channel,
379
            version='0.0',
380
            short_version='3.0.0.0',
381
            file=SimpleUploadedFile('./chrome_installer.dmg', False))
382
383
        self.sparkle_version2 = SparkleVersion.objects.create(
384
            app=self.app,
385
            channel=self.channel2,
386
            version='0.1',
387
            short_version='4.0.0.1',
388
            file=SimpleUploadedFile('./chrome_installer.dmg', False))
389
390
        self.n_hours = 36
391
        self._generate_fake_statistics()
392
393
        hours = [datetime(2016, 2, 13, 0, tzinfo=pytz.UTC) + timedelta(hours=hour)
394
                 for hour in range(self.n_hours)]
395
        self.win_statistics_ch1  = [('1.0.0.0', [[hour.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), self.n_hours - i]
396
                                            for (i, hour)in enumerate(hours)])]
397
        self.win_statistics_ch2 = [('2.0.0.0', [[hour.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), i]
398
                                                for (i, hour)in enumerate(hours)])]
399
        self.win_statistics = self.win_statistics_ch1 + self.win_statistics_ch2
400
401
        self.mac_statistics_ch1 = [('3.0.0.0', [[hour.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), self.n_hours - i]
402
                                            for (i, hour)in enumerate(hours)])]
403
        self.mac_statistics_ch2 = [('4.0.0.1', [[hour.strftime("%Y-%m-%dT%H:%M:%S.%fZ"), i]
404
                                                for (i, hour)in enumerate(hours)])]
405
        self.mac_statistics = self.mac_statistics_ch1 + self.mac_statistics_ch2
406
407
        self.win_daily_stat_ch1 = [('1.0.0.0', [['2016-02-13T00:00:00.000000Z', 36], ['2016-02-14T00:00:00.000000Z', 12]])]
408
        self.win_daily_stat_ch2 = [('2.0.0.0', [['2016-02-13T00:00:00.000000Z', 23], ['2016-02-14T00:00:00.000000Z', 35]])]
409
        self.win_daily_statistics = self.win_daily_stat_ch1 + self.win_daily_stat_ch2
410
411
        self.mac_daily_stat_ch1 = [('3.0.0.0', [['2016-02-13T00:00:00.000000Z', 36], ['2016-02-14T00:00:00.000000Z', 12]])]
412
        self.mac_daily_stat_ch2 = [('4.0.0.1', [['2016-02-13T00:00:00.000000Z', 23], ['2016-02-14T00:00:00.000000Z', 35]])]
413
        self.mac_daily_statistics = self.mac_daily_stat_ch1 + self.mac_daily_stat_ch2
414
415
        self.data = {'hourly': {}, 'daily':{}}
416
        self.data['hourly']['channel1'] = dict(data=dict(win=dict(self.win_statistics_ch1),
417
                                             mac=dict(self.mac_statistics_ch1)))
418
        self.data['hourly']['channel2'] = dict(data=dict(win=dict(self.win_statistics_ch2),
419
                                             mac=dict(self.mac_statistics_ch2)))
420
        self.data['hourly']['all'] = dict(data=dict(win=dict(self.win_statistics),
421
                                             mac=dict(self.mac_statistics)))
422
        self.data['hourly']['channel1'] = dict(data=dict(win=dict(self.win_statistics_ch1),
423
                                                         mac=dict(self.mac_statistics_ch1)))
424
        self.data['daily']['channel1'] = dict(data=dict(win=dict(self.win_daily_stat_ch1),
425
                                             mac=dict(self.mac_daily_stat_ch1)))
426
        self.data['daily']['channel2'] = dict(data=dict(win=dict(self.win_daily_stat_ch2),
427
                                             mac=dict(self.mac_daily_stat_ch2)))
428
        self.data['daily']['all'] = dict(data=dict(win=dict(self.win_daily_statistics),
429
                                                            mac=dict(self.mac_daily_statistics)))
430
431
    @is_private()
432
    def test_unauthorized(self):
433
        client = APIClient()
434
        response = client.get(reverse('api-statistics-live', args=('app',)), format='json')
435
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
436
437
    @freeze_time("2016-02-16")
438
    @is_private()
439
    def test_hourly_list(self):
440
        start = datetime(2016, 2, 13, 0)
441
        end = start + timedelta(hours=self.n_hours-1)
442
        response = self.client.get(reverse('api-statistics-live', args=('app',)),
443
                                   dict(start=start.isoformat(), end=end.isoformat()),
444
                                   format='json')
445
        self.assertEqual(response.status_code, status.HTTP_200_OK)
446
        self.assertDictEqual(StatisticsMonthsSerializer(self.data['hourly']['all']).data, response.data)
447
448
        response = self.client.get(reverse('api-statistics-live', args=('app',)),
449
                                   dict(start=start.isoformat(), end=end.isoformat(), channel=self.channel.name),
450
                                   format='json')
451
        self.assertEqual(response.status_code, status.HTTP_200_OK)
452
        self.assertDictEqual(StatisticsMonthsSerializer(self.data['hourly']['channel1']).data, response.data)
453
454
        response = self.client.get(reverse('api-statistics-live', args=('app',)),
455
                                   dict(start=start.isoformat(), end=end.isoformat(), channel=self.channel2.name),
456
                                   format='json')
457
        self.assertEqual(response.status_code, status.HTTP_200_OK)
458
        self.assertDictEqual(StatisticsMonthsSerializer(self.data['hourly']['channel2']).data, response.data)
459
460
    @freeze_time("2016-03-16")
461
    @is_private()
462
    def test_daily_list(self):
463
        start = datetime(2016, 2, 13, 0)
464
        end = start + timedelta(hours=self.n_hours-1)
465
        response = self.client.get(reverse('api-statistics-live', args=('app',)),
466
                                   dict(start=start.isoformat(), end=end.isoformat()),
467
                                   format='json')
468
        self.assertEqual(response.status_code, status.HTTP_200_OK)
469
        self.assertDictEqual(StatisticsMonthsSerializer(self.data['daily']['all']).data, response.data)
470
471
        response = self.client.get(reverse('api-statistics-live', args=('app',)),
472
                                   dict(start=start.isoformat(), end=end.isoformat(), channel=self.channel.name),
473
                                   format='json')
474
        self.assertEqual(response.status_code, status.HTTP_200_OK)
475
        self.assertDictEqual(StatisticsMonthsSerializer(self.data['daily']['channel1']).data, response.data)
476
477
        response = self.client.get(reverse('api-statistics-live', args=('app',)),
478
                                   dict(start=start.isoformat(), end=end.isoformat(), channel=self.channel2.name),
479
                                   format='json')
480
        self.assertEqual(response.status_code, status.HTTP_200_OK)
481
        self.assertDictEqual(StatisticsMonthsSerializer(self.data['daily']['channel2']).data, response.data)
482
483
class StatisticsMonthsMixin(object):
484
    url = None
485
    url_args = ()
486
    serializer = None
487
    url_get_params = None
488
489
    def _generate_fake_statistics(self):
490
        now = datetime.now()
491
        prev_year = now.year - 1
492
493
        for i in range(1, 13):
494
            date = datetime(year=prev_year, month=i, day=10)
495
            for id in range(1, i + 1):
496
                user_id = UUID(int=id)
497
                userid_counting(user_id, self.install_app_list, self.platform.name, now=date)
498
                user_id = UUID(int=1000 + id)
499
                mac_userid_counting(user_id, self.mac_app, 'mac', now=date)
500
            userid_counting(UUID(int=i), self.uninstall_app_list, self.platform.name, now=date)
501
502
        user_id = UUID(int=13)
503
        userid_counting(user_id, self.install_app_list, self.platform.name, now=datetime(year=now.year, month=1, day=1))
504
        userid_counting(user_id, self.uninstall_app_list, self.platform.name, now=datetime(year=now.year, month=1, day=1))
505
        user_id = UUID(int=1013)
506
        mac_userid_counting(user_id, self.mac_app, 'mac', now=datetime(year=now.year, month=1, day=1))
507
508
    @freeze_time("2016-01-27")
509
    @temporary_media_root()
510
    def setUp(self):
511
        self.user = User.objects.create_user(username='test', password='secret', email='[email protected]')
512
        self.client.credentials(
513
            HTTP_AUTHORIZATION='Basic %s' % base64.b64encode(bytes('{}:{}'.format('test', 'secret'), 'utf8')).decode())
514
515
        redis.flushdb()
516
        self.app = Application.objects.create(id='app', name='app')
517
        self.channel = Channel.objects.create(name='stable')
518
        self.platform = Platform.objects.create(name='win')
519
        Platform.objects.create(name='mac')
520
        self.version1 = Version.objects.create(
521
            app=self.app,
522
            platform=self.platform,
523
            channel=self.channel,
524
            version='1.0.0.0',
525
            file=SimpleUploadedFile('./chrome_installer.exe', False))
526
        self.version2 = Version.objects.create(
527
            app=self.app,
528
            platform=self.platform,
529
            channel=self.channel,
530
            version='2.0.0.0',
531
            file=SimpleUploadedFile('./chrome_installer.exe', False))
532
        self.mac_version = SparkleVersion.objects.create(
533
            app=self.app,
534
            channel=self.channel,
535
            version='782.112',
536
            short_version='13.0.782.112',
537
            dsa_signature='MCwCFCdoW13VBGJWIfIklKxQVyetgxE7AhQTVuY9uQT0KOV1UEk21epBsGZMPg==',
538
            file=SimpleUploadedFile('./chrome.dmg', b'_' * 1024),
539
            file_size=1024)
540
        app_kwargs = dict(appid=self.app.id, version=str(self.version1.version))
541
        install_app = create_app_xml(events=[fixtures.event_install_success], **app_kwargs)
542
        uninstall_app = create_app_xml(events=[fixtures.event_uninstall_success], **app_kwargs)
543
        self.install_app_list = [install_app]
544
        self.uninstall_app_list = [uninstall_app]
545
        self.mac_app = dict(appid=self.app.id, version=str(self.mac_version.short_version))
546
547
        self._generate_fake_statistics()
548
        now = datetime.now()
549
        updates = [(datetime(now.year-1, x, 1).strftime("%Y-%m"), x - 1) for x in range(2, 13)]
550
        updates.append((datetime(now.year, 1, 1).strftime("%Y-%m"), 0))
551
        installs = [(datetime(now.year-1, x, 1).strftime("%Y-%m"), 1) for x in range(2, 13)]
552
        installs.append((datetime(now.year, 1, 1).strftime("%Y-%m"), 1))
553
        uninstalls = [(datetime(now.year-1, x, 1).strftime("%Y-%m"), 1) for x in range(2, 13)]
554
        uninstalls.append((datetime(now.year, 1, 1).strftime("%Y-%m"), 1))
555
556
        win_platform_statistics = dict(new=installs, updates=updates, uninstalls=uninstalls)
557
        mac_platform_statistics = dict(new=installs, updates=updates)
558
        self.users_statistics = dict(win=win_platform_statistics, mac=mac_platform_statistics)
559
        self.data = dict(data=dict(self.users_statistics))
560
561
    @is_private()
562
    def test_unauthorized(self):
563
        client = APIClient()
564
        response = client.get(reverse(self.url, args=self.url_args), format='json')
565
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
566
567
    @is_private()
568
    def test_list(self):
569
        response = self.client.get(reverse(self.url, args=self.url_args), self.url_get_params, format='json')
570
        self.assertEqual(response.status_code, status.HTTP_200_OK)
571
        self.assertEqual(self.serializer(self.data).data, response.data)
572
573
    @freeze_time("2016-01-27")
574
    @is_private()
575
    def test_default_list(self):
576
        data_detail = self.data.copy()
577
        response = self.client.get(reverse(self.url, args=self.url_args), format='json')
578
        self.assertEqual(response.status_code, status.HTTP_200_OK)
579
        self.assertEqual(self.serializer(data_detail).data, response.data)
580
581
582
class StatisticsMonthsDetailTest(StatisticsMonthsMixin, APITestCase):
583
    url = 'api-statistics-months-detail'
584
    url_args = ('app',)
585
    serializer = StatisticsMonthsSerializer
586
    url_get_params = dict(start='2015-2', end='2016-1')
587
588
    @is_private()
589
    def test_list(self):
590
        data_detail = self.data.copy()
591
        response = self.client.get(reverse(self.url, args=self.url_args), self.url_get_params, format='json')
592
        self.assertEqual(response.status_code, status.HTTP_200_OK)
593
        self.assertEqual(self.serializer(data_detail).data, response.data)
594
595
596
class StatisticsVersionsTest(StatisticsMonthsMixin, APITestCase):
597
    url = 'api-statistics-versions'
598
    url_args = ('app',)
599
    serializer = StatisticsMonthsSerializer
600
    url_get_params = dict(date='2016-01')
601
602
    @freeze_time("2016-01-27")
603
    def setUp(self):
604
        super(StatisticsVersionsTest, self).setUp()
605
        data = get_users_versions(self.app.id)
606
        self.data = dict(data=dict(data))
607
608
609
class StatisticsChannelsTest(StatisticsMonthsMixin, APITestCase):
610
    url = 'api-statistics-channels'
611
    url_args = ('app',)
612
    serializer = StatisticsMonthsSerializer
613
    url_get_params = dict(date='2016-01')
614
615
    @freeze_time("2016-01-27")
616
    def setUp(self):
617
        super(StatisticsChannelsTest, self).setUp()
618
        data = get_channel_statistics(self.app.id)
619
        self.data = dict(data=dict(data))
620
621
    @is_private()
622
    def test_list(self):
623
        data_detail = self.data.copy()
624
        response = self.client.get(reverse(self.url, args=self.url_args), dict(date='2016-1'), format='json')
625
        self.assertEqual(response.status_code, status.HTTP_200_OK)
626
        self.assertEqual(self.serializer(data_detail).data, response.data)
627
628
629
class ServerVersionTest(APITestCase):
630
    url = 'api-version'
631
    serializer = ServerVersionSerializer
632
633
    def setUp(self):
634
        self.user = User.objects.create_user(username='test', password='secret', email='[email protected]')
635
        self.client.credentials(
636
            HTTP_AUTHORIZATION='Basic %s' % base64.b64encode(bytes('{}:{}'.format('test', 'secret'), 'utf8')).decode())
637
        self.data = dict(version=settings.APP_VERSION)
638
639
    @is_private()
640
    def test(self):
641
        response = self.client.get(reverse(self.url), format='json')
642
        self.assertEqual(response.status_code, status.HTTP_200_OK)
643
        self.assertEqual(self.serializer(self.data).data, response.data)
644
645
646
647
class PartialUpdateTest(BaseTest, APITestCase):
648
    url = 'partialupdate-list'
649
    url_detail = 'partialupdate-detail'
650
    factory = PartialUpdateFactory
651
    serializer = PartialUpdateSerializer
652
653
    @is_private()
654
    def test_create(self):
655
        version = VersionFactory.create()
656
        data = dict(
657
            is_enabled=True,
658
            exclude_new_users=True,
659
            version=version.pk,
660
            end_date=str(date.today()),
661
            percent=51.0,
662
            start_date=str(date.today()),
663
            active_users=1,
664
        )
665
        response = self.client.post(reverse(self.url), data, format='json')
666
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
667
        obj = PartialUpdate.objects.get(id=response.data['id'])
668
        self.assertEqual(response.data, self.serializer(obj).data)
669
670
    @is_private()
671
    def test_update(self):
672
        version = VersionFactory.create()
673
        data = dict(
674
            is_enabled=True,
675
            exclude_new_users=True,
676
            version=version.pk,
677
            end_date=str(date.today()),
678
            percent=51.0,
679
            start_date=str(date.today()),
680
            active_users=1,
681
        )
682
        response = self.client.post(reverse(self.url), data, format='json')
683
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
684
        obj_id = response.data['id']
685
        obj = PartialUpdate.objects.get(id=obj_id)
686
        self.assertEqual(response.data, self.serializer(obj).data)
687
        url = reverse(self.url_detail, kwargs=dict(pk=obj_id))
688
        response = self.client.patch(url, dict(event=2))
689
        self.assertEqual(response.status_code, status.HTTP_200_OK)
690
        obj = PartialUpdate.objects.get(id=obj_id)
691
        self.assertEqual(obj.percent, 51.0)
692