Completed
Push — master ( 67eae9...f0f1ec )
by
unknown
01:23
created

test_get_users_statistics_weeks()   A

Complexity

Conditions 2

Size

Total Lines 13

Duplication

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