Completed
Push — master ( 6c4ac7...836a98 )
by
unknown
01:30
created

StatisticsTest   A

Complexity

Total Complexity 32

Size/Duplication

Total Lines 380
Duplicated Lines 0 %

Importance

Changes 8
Bugs 0 Features 0
Metric Value
c 8
b 0
f 0
dl 0
loc 380
rs 9.6
wmc 32

14 Methods

Rating   Name   Duplication   Size   Complexity  
A tearDown() 0 2 1
A setUp() 0 2 1
B test_userid_counting() 0 40 4
F test_add_app_statistics() 0 90 11
A test_parse_apps() 0 17 2
A test_parse_request() 0 11 1
A test_parse_os() 0 8 1
A test_get_kwargs_for_model() 0 11 1
B test_live_statistics_updatecheck() 0 26 1
A test_is_user_active() 0 13 1
A test_collect_statistics() 0 65 2
B test_live_statistics_install() 0 47 4
A test_parse_hw() 0 12 1
A test_parse_events() 0 22 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
21
from builtins import range
22
23
from datetime import datetime
24
from uuid import UUID
25
26
from django.test import TestCase
27
from django.core.files.uploadedfile import SimpleUploadedFile
28
29
from mock import patch
30
from freezegun import freeze_time
31
from bitmapist import DayEvents, HourEvents, mark_event
32
33
from omaha.tests import fixtures
34
from omaha.parser import parse_request
35
from omaha.statistics import (
36
    userid_counting,
37
    add_app_statistics,
38
    is_user_active,
39
    get_kwargs_for_model,
40
    parse_os,
41
    parse_hw,
42
    parse_req,
43
    parse_apps,
44
    parse_events,
45
    collect_statistics,
46
    get_users_statistics_months,
47
    get_channel_statistics,
48
    get_users_versions,
49
)
50
51
from omaha.tests.utils import temporary_media_root, create_app_xml
52
from omaha.utils import redis, get_id
53
from omaha.settings import DEFAULT_CHANNEL
54
from omaha.models import (
55
    ACTIVE_USERS_DICT_CHOICES,
56
    Os,
57
    Hw,
58
    Request,
59
    AppRequest,
60
    Event,
61
    Application,
62
    Platform,
63
    Channel,
64
    Version,
65
)
66
from sparkle.models import SparkleVersion
67
from sparkle.statistics import userid_counting as mac_userid_counting
68
69
70
class StatisticsTest(TestCase):
71
    def setUp(self):
72
        redis.flushdb()
73
74
    def tearDown(self):
75
        redis.flushdb()
76
77
    @patch('omaha.statistics.add_app_statistics')
78
    def test_userid_counting(self, mock_add_app_statistics):
79
        now = datetime.utcnow()
80
81
        userid1 = '{F07B3878-CD6F-4B96-B52F-95C4D23077E0}'
82
        user1_id = get_id(userid1)
83
84
        userid2 = '{EC4C5647-F798-4BCA-83DA-926CD448A1D5}'
85
        user2_id = get_id(userid2)
86
87
        app_list = [dict(appid='{F97917B1-19AB-48C1-9802-CEF305B10804}'),
88
                    dict(appid='{555B8D18-076D-4576-9579-1FD7F0399EAE}')]
89
90
        request_events = DayEvents('request', now.year, now.month, now.day)
91
92
        self.assertFalse(user1_id in request_events)
93
        self.assertEqual(len(request_events), 0)
94
95
        userid_counting(userid1, app_list, 'win')
96
97
        for app in app_list:
98
            mock_add_app_statistics.assert_any_call(user1_id, 'win', app, now=None)
99
100
        self.assertEqual(len(request_events), 1)
101
        self.assertTrue(user1_id in request_events)
102
103
        userid_counting(userid1, app_list, 'win')
104
105
        for app in app_list:
106
            mock_add_app_statistics.assert_any_call(user1_id, 'win', app, now=None)
107
108
        self.assertEqual(len(request_events), 1)
109
110
        self.assertFalse(user2_id in request_events)
111
        userid_counting(userid2, app_list[:1], 'win')
112
        self.assertTrue(user2_id in request_events)
113
        for app in app_list[:1]:
114
            mock_add_app_statistics.assert_any_call(user2_id, 'win', app, now=None)
115
116
        self.assertEqual(len(request_events), 2)
117
118
    @freeze_time('2016-1-1')
119
    def test_add_app_statistics(self):
120
        now = datetime.utcnow()
121
        next_month = now.replace(month=now.month + 1)
122
        userid = 1
123
        channel = DEFAULT_CHANNEL
124
        platform = 'win'
125
        app_kwargs = dict(appid='{2882CF9B-D9C2-4edb-9AAF-8ED5FCF366F7}', nextversion='0.0.0.1')
126
        success_app = create_app_xml(events=fixtures.event_install_success, **app_kwargs)
127
        error_app = create_app_xml(events=fixtures.event_install_error, **app_kwargs)
128
        appid = app_kwargs.get('appid')
129
        version = app_kwargs.get('nextversion')
130
131
        events_request_appid = lambda date=now: DayEvents.from_date('request:%s' % appid, date)
132
        events_new_appid = lambda date=now: DayEvents.from_date('new_install:%s' % appid, date)
133
        events_request_appid_version = lambda date=now: DayEvents.from_date('request:{}:{}'.format(appid, version), date)
134
        events_request_appid_platform = lambda date=now: DayEvents.from_date('request:{}:{}'.format(appid, platform), date)
135
        events_new_appid_platform = lambda date=now: DayEvents.from_date('new_install:{}:{}'.format(appid, platform), date)
136
        events_request_appid_channel = lambda date=now: DayEvents.from_date('request:{}:{}'.format(appid, channel), date)
137
        events_request_appid_platform_version = lambda date=now: DayEvents.from_date(
138
            'request:{}:{}:{}'.format(appid, platform, version), date)
139
        events_request_appid_platform_channel_version = lambda date=now: DayEvents.from_date(
140
            'request:{}:{}:{}:{}'.format(appid, platform, channel, version), date)
141
142
        self.assertEqual(len(events_new_appid()), 0)
143
        self.assertEqual(len(events_request_appid()), 0)
144
        self.assertEqual(len(events_request_appid_version()), 0)
145
        self.assertEqual(len(events_request_appid_platform()), 0)
146
        self.assertEqual(len(events_new_appid_platform()), 0)
147
        self.assertEqual(len(events_request_appid_channel()), 0)
148
        self.assertEqual(len(events_request_appid_platform_version()), 0)
149
        self.assertEqual(len(events_request_appid_platform_channel_version()), 0)
150
151
        add_app_statistics(userid, platform, error_app)
152
153
        self.assertEqual(len(events_new_appid()), 0)
154
        self.assertEqual(len(events_request_appid()), 0)
155
        self.assertEqual(len(events_request_appid_version()), 0)
156
        self.assertEqual(len(events_request_appid_platform()), 0)
157
        self.assertEqual(len(events_new_appid_platform()), 0)
158
        self.assertEqual(len(events_request_appid_channel()), 0)
159
        self.assertEqual(len(events_request_appid_platform_version()), 0)
160
        self.assertEqual(len(events_request_appid_platform_channel_version()), 0)
161
162
        add_app_statistics(userid, platform, success_app)
163
        self.assertEqual(len(events_new_appid()), 1)
164
        self.assertEqual(len(events_request_appid()), 0)
165
        self.assertEqual(len(events_request_appid_version()), 1)
166
        self.assertEqual(len(events_new_appid_platform()), 1)
167
        self.assertEqual(len(events_request_appid_platform()), 0)
168
        self.assertEqual(len(events_request_appid_channel()), 1)
169
        self.assertEqual(len(events_request_appid_platform_version()), 1)
170
        self.assertEqual(len(events_request_appid_platform_channel_version()), 1)
171
172
        self.assertIn(userid, events_new_appid())
173
        self.assertIn(userid, events_request_appid_version())
174
        self.assertIn(userid, events_new_appid_platform())
175
        self.assertIn(userid, events_request_appid_channel())
176
        self.assertIn(userid, events_request_appid_platform_version())
177
        self.assertIn(userid, events_request_appid_platform_channel_version())
178
179
        add_app_statistics(userid, platform, success_app)
180
        self.assertEqual(len(events_new_appid()), 1)
181
        self.assertEqual(len(events_request_appid()), 0)
182
        self.assertEqual(len(events_request_appid_version()), 1)
183
        self.assertEqual(len(events_new_appid_platform()), 1)
184
        self.assertEqual(len(events_request_appid_platform()), 0)
185
        self.assertEqual(len(events_request_appid_channel()), 1)
186
        self.assertEqual(len(events_request_appid_platform_version()), 1)
187
188
        with freeze_time(next_month):
189
            add_app_statistics(userid, platform, error_app)
190
191
        self.assertEqual(len(events_request_appid(next_month)), 0)
192
        self.assertEqual(len(events_request_appid_platform(next_month)), 0)
193
194
        with freeze_time(next_month):
195
            add_app_statistics(userid, platform, success_app)
196
197
        self.assertEqual(len(events_request_appid(next_month)), 1)
198
        self.assertEqual(len(events_request_appid_platform(next_month)), 1)
199
        self.assertEqual(len(events_new_appid(next_month)), 0)
200
        self.assertEqual(len(events_request_appid_version(next_month)), 1)
201
        self.assertEqual(len(events_new_appid_platform(next_month)), 0)
202
        self.assertEqual(len(events_request_appid_channel(next_month)), 1)
203
        self.assertEqual(len(events_request_appid_platform_version(next_month)), 1)
204
        self.assertEqual(len(events_request_appid_platform_channel_version(next_month)), 1)
205
206
        self.assertIn(userid, events_request_appid(next_month))
207
        self.assertIn(userid, events_request_appid_platform(next_month))
208
209
    def test_is_user_active(self):
210
        userid = '{F07B3878-CD6F-4B96-B52F-95C4D23077E0}'
211
        id = get_id(userid)
212
213
        self.assertTrue(is_user_active(ACTIVE_USERS_DICT_CHOICES['all'], userid))
214
        self.assertFalse(is_user_active(ACTIVE_USERS_DICT_CHOICES['week'], userid))
215
        self.assertFalse(is_user_active(ACTIVE_USERS_DICT_CHOICES['month'], userid))
216
217
        mark_event('request', id)
218
219
        self.assertTrue(is_user_active(ACTIVE_USERS_DICT_CHOICES['all'], userid))
220
        self.assertTrue(is_user_active(ACTIVE_USERS_DICT_CHOICES['week'], userid))
221
        self.assertTrue(is_user_active(ACTIVE_USERS_DICT_CHOICES['month'], userid))
222
223
    def test_get_kwargs_for_model(self):
224
        os = dict(platform="win",
225
                  version="6.1",
226
                  sp="",
227
                  arch="x64")
228
        kwargs = get_kwargs_for_model(Os, os)
229
        self.assertDictEqual(kwargs, dict(platform="win",
230
                                          version="6.1",
231
                                          sp="",
232
                                          arch="x64",
233
                                          id=None))
234
235
    def test_parse_os(self):
236
        request = parse_request(fixtures.request_event)
237
        os = parse_os(request.os)
238
        self.assertIsInstance(os, Os)
239
        self.assertEqual(os.platform, 'win')
240
        self.assertEqual(os.version, '6.1')
241
        self.assertEqual(os.sp, '')
242
        self.assertEqual(os.arch, 'x64')
243
244
    def test_parse_hw(self):
245
        hw = dict(sse2="1")
246
        hw = parse_hw(hw)
247
        self.assertIsInstance(hw, Hw)
248
        self.assertEqual(hw.sse, None)
249
        self.assertEqual(hw.sse2, 1)
250
        self.assertEqual(hw.sse3, None)
251
        self.assertEqual(hw.ssse3, None)
252
        self.assertEqual(hw.sse41, None)
253
        self.assertEqual(hw.sse42, None)
254
        self.assertEqual(hw.avx, None)
255
        self.assertEqual(hw.physmemory, None)
256
257
    def test_parse_request(self):
258
        request = parse_request(fixtures.request_event)
259
        req = parse_req(request)
260
        self.assertIsInstance(req, Request)
261
        self.assertEqual(req.version, Request._meta.get_field_by_name('version')[0].to_python('1.3.23.0'))
262
        self.assertEqual(req.ismachine, 1)
263
        self.assertEqual(req.sessionid, '{2882CF9B-D9C2-4edb-9AAF-8ED5FCF366F7}')
264
        self.assertEqual(req.userid, '{D0BBD725-742D-44ae-8D46-0231E881D58E}')
265
        self.assertEqual(req.originurl, None)
266
        self.assertEqual(req.testsource, 'ossdev')
267
        self.assertEqual(req.updaterchannel, None)
268
269
    def test_parse_apps(self):
270
        request = parse_request(fixtures.request_event)
271
        req = parse_req(request)
272
        req.os = parse_os(request.os)
273
        req.hw = parse_hw(request.hw) if request.get('hw') else None
274
        req.save()
275
276
        apps = parse_apps(request.findall('app'), req)
277
        self.assertEqual(len(apps), 1)
278
        app = apps[0]
279
        self.assertIsInstance(app, AppRequest)
280
        self.assertEqual(app.version, None)
281
        self.assertEqual(app.nextversion, Request._meta.get_field_by_name('version')[0].to_python('13.0.782.112'))
282
        self.assertEqual(app.lang, 'en')
283
        self.assertEqual(app.tag, 'stable')
284
        self.assertEqual(app.installage, 6)
285
        self.assertEqual(app.appid, '{D0AB2EBC-931B-4013-9FEB-C9C4C2225C8C}')
286
287
    def test_parse_events(self):
288
        request = parse_request(fixtures.request_event)
289
        events = request.findall('app')[0].findall('event')
290
        events = parse_events(events)
291
        self.assertEqual(len(events), 3)
292
        event = events[0]
293
        self.assertIsInstance(event, Event)
294
        self.assertEqual(event.eventtype, 9)
295
        self.assertEqual(event.eventresult, 1)
296
        self.assertEqual(event.errorcode, 0)
297
        self.assertEqual(event.extracode1, 0)
298
        self.assertEqual(event.download_time_ms, None)
299
        self.assertEqual(event.downloaded, None)
300
        self.assertEqual(event.total, None)
301
        self.assertEqual(event.update_check_time_ms, None)
302
        self.assertEqual(event.install_time_ms, None)
303
        self.assertEqual(event.source_url_index, None)
304
        self.assertEqual(event.state_cancelled, None)
305
        self.assertEqual(event.time_since_update_available_ms, None)
306
        self.assertEqual(event.time_since_download_start_ms, None)
307
        self.assertEqual(event.nextversion, None)
308
        self.assertEqual(event.previousversion, None)
309
310
    def test_collect_statistics(self):
311
        request = parse_request(fixtures.request_event)
312
313
        self.assertEqual(Os.objects.all().count(), 0)
314
        self.assertEqual(Hw.objects.all().count(), 0)
315
        self.assertEqual(Request.objects.all().count(), 0)
316
        self.assertEqual(AppRequest.objects.all().count(), 0)
317
        self.assertEqual(Event.objects.all().count(), 0)
318
319
        collect_statistics(request)
320
321
        self.assertEqual(Os.objects.all().count(), 1)
322
        self.assertEqual(Hw.objects.all().count(), 0)
323
        self.assertEqual(Request.objects.all().count(), 1)
324
        self.assertEqual(AppRequest.objects.all().count(), 1)
325
        self.assertEqual(Event.objects.all().count(), 3)
326
327
        os = Os.objects.get()
328
        req = Request.objects.get()
329
        app_req = AppRequest.objects.get()
330
        events = Event.objects.all()
331
332
        self.assertEqual(os.platform, 'win')
333
        self.assertEqual(os.version, '6.1')
334
        self.assertEqual(os.sp, '')
335
        self.assertEqual(os.arch, 'x64')
336
337
        self.assertEqual(req.version, Request._meta.get_field_by_name('version')[0].to_python('1.3.23.0'))
338
        self.assertEqual(req.ismachine, 1)
339
        self.assertEqual(req.sessionid, '{2882CF9B-D9C2-4edb-9AAF-8ED5FCF366F7}')
340
        self.assertEqual(req.userid, '{D0BBD725-742D-44ae-8D46-0231E881D58E}')
341
        self.assertEqual(req.originurl, None)
342
        self.assertEqual(req.testsource, 'ossdev')
343
        self.assertEqual(req.updaterchannel, None)
344
        self.assertEqual(req.os, os)
345
        self.assertEqual(req.hw, None)
346
347
        self.assertEqual(app_req.version, None)
348
        self.assertEqual(app_req.nextversion, Request._meta.get_field_by_name('version')[0].to_python('13.0.782.112'))
349
        self.assertEqual(app_req.lang, 'en')
350
        self.assertEqual(app_req.tag, 'stable')
351
        self.assertEqual(app_req.installage, 6)
352
        self.assertEqual(app_req.appid, '{D0AB2EBC-931B-4013-9FEB-C9C4C2225C8C}')
353
        self.assertEqual(app_req.request, req)
354
355
        event = events[0]
356
357
        self.assertEqual(event.eventtype, 9)
358
        self.assertEqual(event.eventresult, 1)
359
        self.assertEqual(event.errorcode, 0)
360
        self.assertEqual(event.extracode1, 0)
361
        self.assertEqual(event.download_time_ms, None)
362
        self.assertEqual(event.downloaded, None)
363
        self.assertEqual(event.total, None)
364
        self.assertEqual(event.update_check_time_ms, None)
365
        self.assertEqual(event.install_time_ms, None)
366
        self.assertEqual(event.source_url_index, None)
367
        self.assertEqual(event.state_cancelled, None)
368
        self.assertEqual(event.time_since_update_available_ms, None)
369
        self.assertEqual(event.time_since_download_start_ms, None)
370
        self.assertEqual(event.nextversion, None)
371
        self.assertEqual(event.previousversion, None)
372
373
        for e in events:
374
            self.assertIn(e, app_req.events.all())
375
376
    def test_live_statistics_install(self):
377
        request = parse_request(fixtures.request_event_install_success)
378
        apps = request.findall('app')
379
        app = apps[0]
380
        channel = DEFAULT_CHANNEL
381
        now = datetime.utcnow()
382
        userid = 1
383
        platform = 'win'
384
385
        appid = app.get('appid')
386
        version_1 = '0.0.0.1'
387
        version_2 = '0.0.0.2'
388
389
        events_appid_version = lambda version: HourEvents('request:{}:{}'.format(appid, version), now.year, now.month, now.day, now.hour)
390
        events_appid_platform_version = lambda version: HourEvents('request:{}:{}:{}'.format(appid, platform, version), now.year, now.month, now.day, now.hour)
391
        events_appid_platform_channel_version = lambda version: HourEvents(
392
            'request:{}:{}:{}:{}'.format(appid, platform, channel, version), now.year, now.month, now.day, now.hour)
393
394
        self.assertEqual(len(events_appid_version(version_1)), 0)
395
        self.assertEqual(len(events_appid_platform_version(version_1)), 0)
396
        self.assertEqual(len(events_appid_platform_channel_version(version_1)), 0)
397
        userid_counting(userid, apps, platform)
398
399
        self.assertEqual(len(events_appid_version(version_1)), 1)
400
        self.assertEqual(len(events_appid_platform_version(version_1)), 1)
401
        self.assertEqual(len(events_appid_platform_channel_version(version_1)), 1)
402
403
        request = parse_request(fixtures.request_event_update_success)
404
        apps = request.findall('app')
405
406
        userid_counting(userid, apps, platform)
407
408
        self.assertEqual(len(events_appid_version(version_1)), 0)
409
        self.assertEqual(len(events_appid_platform_version(version_1)), 0)
410
        self.assertEqual(len(events_appid_platform_channel_version(version_1)), 0)
411
        self.assertEqual(len(events_appid_version(version_2)), 1)
412
        self.assertEqual(len(events_appid_platform_version(version_2)), 1)
413
        self.assertEqual(len(events_appid_platform_channel_version(version_2)), 1)
414
415
        request = parse_request(fixtures.request_event_uninstall_success)
416
        apps = request.findall('app')
417
418
        userid_counting(userid, apps, platform)
419
420
        self.assertEqual(len(events_appid_version(version_2)), 1)
421
        self.assertEqual(len(events_appid_platform_version(version_2)), 1)
422
        self.assertEqual(len(events_appid_platform_channel_version(version_2)), 1)
423
424
    def test_live_statistics_updatecheck(self):
425
        request = parse_request(fixtures.request_update_check)
426
        apps = request.findall('app')
427
        app = apps[0]
428
        channel = DEFAULT_CHANNEL
429
        now = datetime.utcnow()
430
        userid = 1
431
        platform = 'win'
432
433
        appid = app.get('appid')
434
        version = app.get('version')
435
436
        events_appid_version = HourEvents('request:{}:{}'.format(appid, version), now.year, now.month, now.day, now.hour)
437
        events_appid_platform_version = HourEvents('request:{}:{}:{}'.format(appid, platform, version), now.year, now.month, now.day, now.hour)
438
        events_appid_platform_channel_version = HourEvents(
439
            'request:{}:{}:{}:{}'.format(appid, platform, channel, version), now.year, now.month, now.day, now.hour)
440
441
        self.assertEqual(len(events_appid_version), 0)
442
        self.assertEqual(len(events_appid_platform_version), 0)
443
        self.assertEqual(len(events_appid_platform_channel_version), 0)
444
445
        userid_counting(userid, apps, platform)
446
447
        self.assertEqual(len(events_appid_version), 1)
448
        self.assertEqual(len(events_appid_platform_version), 1)
449
        self.assertEqual(len(events_appid_platform_channel_version), 1)
450
451
452
class GetStatisticsTest(TestCase):
453
    maxDiff = None
454
455
    def _generate_fake_statistics(self):
456
        now = datetime.now()
457
        year = now.year
458
        n_users = 12
459
460
        for i in range(1, n_users+1):
461
            date = datetime(year=year, month=i, day=10)
462
            for id in range(1, i + 1):
463
                user_id = UUID(int=id)
464
                userid_counting(user_id, self.install_app_list, self.platform.name, now=date)
465
                user_id = UUID(int=n_users + id)
466
                mac_userid_counting(user_id, self.mac_app, 'mac', now=date)
467
            userid_counting(UUID(int=i), self.uninstall_app_list, self.platform.name, now=date)
468
469
470
    @temporary_media_root()
471
    def setUp(self):
472
        redis.flushdb()
473
        self.app = Application.objects.create(id='app', name='app')
474
        self.channel = Channel.objects.create(name='stable')
475
        self.platform = Platform.objects.create(name='win')
476
        self.version1 = Version.objects.create(
477
            app=self.app,
478
            platform=self.platform,
479
            channel=self.channel,
480
            version='1.0.0.0',
481
            file=SimpleUploadedFile('./chrome_installer.exe', False))
482
        self.version2 = Version.objects.create(
483
            app=self.app,
484
            platform=self.platform,
485
            channel=self.channel,
486
            version='2.0.0.0',
487
            file=SimpleUploadedFile('./chrome_installer.exe', False))
488
        self.mac_version = SparkleVersion.objects.create(
489
            app=self.app,
490
            channel=self.channel,
491
            version='782.112',
492
            short_version='13.0.782.112',
493
            dsa_signature='MCwCFCdoW13VBGJWIfIklKxQVyetgxE7AhQTVuY9uQT0KOV1UEk21epBsGZMPg==',
494
            file=SimpleUploadedFile('./chrome.dmg', b'_' * 23963192),
495
            file_size=23963192)
496
497
        app_kwargs = dict(appid=self.app.id, version=str(self.version1.version))
498
        install_app = create_app_xml(events=[fixtures.event_install_success], **app_kwargs)
499
        uninstall_app = create_app_xml(events=[fixtures.event_uninstall_success], **app_kwargs)
500
        self.install_app_list = [install_app]
501
        self.uninstall_app_list = [uninstall_app]
502
        self.mac_app = dict(appid=self.app.id, version=str(self.mac_version.short_version))
503
504
        self._generate_fake_statistics()
505
        now = datetime.now()
506
        win_updates = [(datetime(now.year, x, 1).strftime("%Y-%m"), x - 1) for x in range(1, 13)]
507
        win_installs = [(datetime(now.year, x, 1).strftime("%Y-%m"), 1) for x in range(1, 13)]
508
        uninstalls = [(datetime(now.year, x, 1).strftime("%Y-%m"), 1) for x in range(1, 13)]
509
        mac_updates = [(datetime(now.year, x, 1).strftime("%Y-%m"), x - 1) for x in range(1, 13)]
510
        mac_installs = [(datetime(now.year, x, 1).strftime("%Y-%m"), 1) for x in range(1, 13)]
511
        total_installs = map(lambda x, y: (x[0], x[1] + y[1]), win_installs, mac_installs)
512
        total_updates = map(lambda x, y: (x[0], x[1] + y[1]), win_updates, mac_updates)
513
        self.users_statistics = dict(new=total_installs, updates=total_updates, uninstalls=uninstalls)
514
        self.win_users_statistics = dict(new=win_installs, updates=win_updates, uninstalls=uninstalls)
515
        self.mac_users_statistics = dict(new=mac_installs, updates=mac_updates)
516
517
518
    def tearDown(self):
519
        redis.flushdb()
520
521
    def test_get_users_statistics_months(self):
522
        self.assertDictEqual(get_users_statistics_months(app_id=self.app.id), self.users_statistics)
523
        self.assertDictEqual(get_users_statistics_months(app_id=self.app.id, platform='win'), self.win_users_statistics)
524
        self.assertDictEqual(get_users_statistics_months(app_id=self.app.id, platform='mac'), self.mac_users_statistics)
525
526
527
    def test_get_chanels_statistics(self):
528
        now = datetime.now()
529
        with freeze_time(datetime(year=now.year, month=now.month, day=10)):
530
            self.assertListEqual(get_channel_statistics(self.app.id), [('stable', now.month*2)])
531
532
    def test_get_users_versions(self):
533
        now = datetime.now()
534
        expected = dict(win={'1.0.0.0': now.month}, mac={'13.0.782.112': now.month})
535
        with freeze_time(datetime(year=now.year, month=now.month, day=10)):
536
            self.assertDictEqual(get_users_versions(self.app.id), expected)
537