Merge branch 'radio-version' into 'master'
Extend the heartbeat and crashreport models with the radio version
See merge request !5
diff --git a/crashreport_stats/migrations/0002_version_and_versiondaily_with_defaults.py b/crashreport_stats/migrations/0002_version_and_versiondaily_with_defaults.py
new file mode 100644
index 0000000..0a58758
--- /dev/null
+++ b/crashreport_stats/migrations/0002_version_and_versiondaily_with_defaults.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+#
+# Set the default values for the Version and VersionDaily models.
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('crashreport_stats', '0001_initial'),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name='version',
+ name='first_seen_on',
+ field=models.DateField(auto_now_add=True),
+ ),
+ migrations.AlterField(
+ model_name='version',
+ name='heartbeats',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.AlterField(
+ model_name='version',
+ name='other',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.AlterField(
+ model_name='version',
+ name='prob_crashes',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.AlterField(
+ model_name='version',
+ name='released_on',
+ field=models.DateField(auto_now_add=True),
+ ),
+ migrations.AlterField(
+ model_name='version',
+ name='smpl',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.AlterField(
+ model_name='versiondaily',
+ name='date',
+ field=models.DateField(auto_now_add=True),
+ ),
+ migrations.AlterField(
+ model_name='versiondaily',
+ name='heartbeats',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.AlterField(
+ model_name='versiondaily',
+ name='other',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.AlterField(
+ model_name='versiondaily',
+ name='prob_crashes',
+ field=models.IntegerField(default=0),
+ ),
+ migrations.AlterField(
+ model_name='versiondaily',
+ name='smpl',
+ field=models.IntegerField(default=0),
+ ),
+ ]
diff --git a/crashreport_stats/migrations/0003_radioversion_radioversiondaily.py b/crashreport_stats/migrations/0003_radioversion_radioversiondaily.py
new file mode 100644
index 0000000..3ce431a
--- /dev/null
+++ b/crashreport_stats/migrations/0003_radioversion_radioversiondaily.py
@@ -0,0 +1,50 @@
+# -*- coding: utf-8 -*-
+#
+# Introducing the RadioVersion and RadioVersionDaily models
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+import django.db.models.deletion
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('crashreport_stats', '0002_version_and_versiondaily_with_defaults'),
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='RadioVersion',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('is_official_release', models.BooleanField(default=False)),
+ ('is_beta_release', models.BooleanField(default=False)),
+ ('first_seen_on', models.DateField(auto_now_add=True)),
+ ('released_on', models.DateField(auto_now_add=True)),
+ ('heartbeats', models.IntegerField(default=0)),
+ ('prob_crashes', models.IntegerField(default=0)),
+ ('smpl', models.IntegerField(default=0)),
+ ('other', models.IntegerField(default=0)),
+ ('radio_version', models.CharField(max_length=200, unique=True)),
+ ],
+ options={
+ 'abstract': False,
+ },
+ ),
+ migrations.CreateModel(
+ name='RadioVersionDaily',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('date', models.DateField(auto_now_add=True)),
+ ('heartbeats', models.IntegerField(default=0)),
+ ('prob_crashes', models.IntegerField(default=0)),
+ ('smpl', models.IntegerField(default=0)),
+ ('other', models.IntegerField(default=0)),
+ ('version', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='daily_stats', to='crashreport_stats.RadioVersion')),
+ ],
+ options={
+ 'abstract': False,
+ },
+ ),
+ ]
diff --git a/crashreport_stats/models.py b/crashreport_stats/models.py
index 04f38ab..f7fd05c 100644
--- a/crashreport_stats/models.py
+++ b/crashreport_stats/models.py
@@ -1,76 +1,96 @@
from django.db import models
from crashreports.models import *
+from django.db.models import F
from django.db.models.signals import post_save
from django.dispatch import receiver
import datetime
-def getVersion(build_fingerprint):
- v= None
- try:
- v = Version.objects.get(build_fingerprint=build_fingerprint)
- except Version.DoesNotExist:
- v =Version(build_fingerprint=build_fingerprint,
- first_seen_on=datetime.date.today(),
- released_on=datetime.date.today(),
- heartbeats=0, prob_crashes=0, smpl=0, other=0)
- v.save()
- return v
-
-def getVersionDaily(version,day):
- try:
- v = VersionDaily.objects.get(version=version, date=day)
- except VersionDaily.DoesNotExist:
- v =VersionDaily(version=version, date=day,
- heartbeats=0, prob_crashes=0, smpl=0, other=0)
- return v
-
@receiver(post_save, sender=Crashreport)
def on_crashreport_create(sender, **kwargs):
crashreport = kwargs.get('instance')
- v= getVersion(crashreport.build_fingerprint)
- vd = getVersionDaily(v, crashreport.date.date())
+ v, _ = Version.objects.get_or_create(build_fingerprint=crashreport.build_fingerprint)
+ vd, _ = VersionDaily.objects.get_or_create(version=v, date=crashreport.date)
+ stats = [v, vd]
+
+ if crashreport.radio_version:
+ rv, _ = RadioVersion.objects.get_or_create(radio_version=crashreport.radio_version)
+ rvd, _ = RadioVersionDaily.objects.get_or_create(version=rv, date=crashreport.date)
+ stats += [rv, rvd]
+
if crashreport.boot_reason == "RTC alarm":
- v.smpl = v.smpl + 1
- vd.smpl = vd.smpl + 1
+ for element in stats:
+ element.smpl = F('smpl') + 1
elif crashreport.boot_reason in ["UNKNOWN", "keyboard power on"]:
- v.prob_crashes = v.prob_crashes + 1
- vd.prob_crashes = vd.prob_crashes + 1
+ for element in stats:
+ element.prob_crashes = F('prob_crashes') + 1
else:
- v.other = v.other + 1
- vd.other = vd.other + 1
- v.save()
- vd.save()
+ for element in stats:
+ element.other = F('other') + 1
+
+ for element in stats:
+ element.save()
+
@receiver(post_save, sender=HeartBeat)
def on_heartbeat_create(sender, **kwargs):
hb = kwargs.get('instance')
- v = getVersion(hb.build_fingerprint)
- vd = getVersionDaily(v, hb.date)
- v.heartbeats = v.heartbeats + 1
- vd.heartbeats = vd.heartbeats + 1
- v.save()
- vd.save()
+
+ v, _ = Version.objects.get_or_create(build_fingerprint=hb.build_fingerprint)
+ vd, _ = VersionDaily.objects.get_or_create(version=v, date=hb.date)
+ stats = [v, vd]
+
+ if hb.radio_version:
+ rv, _ = RadioVersion.objects.get_or_create(radio_version=hb.radio_version)
+ rvd, _ = RadioVersionDaily.objects.get_or_create(version=rv, date=hb.date)
+ stats += [rv, rvd]
+
+ for element in stats:
+ element.heartbeats = F('heartbeats') + 1
+ element.save()
-class Version(models.Model):
- build_fingerprint = models.CharField(max_length=200, unique=True)
+class _VersionStats(models.Model):
is_official_release = models.BooleanField(default=False)
- is_beta_release = models.BooleanField(default=False)
- first_seen_on = models.DateField()
- released_on = models.DateField()
- heartbeats = models.IntegerField()
- prob_crashes = models.IntegerField()
- smpl = models.IntegerField()
- other = models.IntegerField()
+ is_beta_release = models.BooleanField(default=False)
+ first_seen_on = models.DateField(auto_now_add=True)
+ released_on = models.DateField(auto_now_add=True)
+ heartbeats = models.IntegerField(default=0)
+ prob_crashes = models.IntegerField(default=0)
+ smpl = models.IntegerField(default=0)
+ other = models.IntegerField(default=0)
+
+ class Meta:
+ abstract = True
+
+class _DailyVersionStats(models.Model):
+ date = models.DateField(auto_now_add=True)
+ heartbeats = models.IntegerField(default=0)
+ prob_crashes = models.IntegerField(default=0)
+ smpl = models.IntegerField(default=0)
+ other = models.IntegerField(default=0)
+
+ class Meta:
+ abstract = True
+
+
+class Version(_VersionStats):
+ build_fingerprint = models.CharField(max_length=200, unique=True)
+
def __str__(self):
return self.build_fingerprint
-
-
-class VersionDaily(models.Model):
- version = models.ForeignKey(Version, db_index=True, related_name='daily_stats', on_delete=models.CASCADE)
- date = models.DateField()
- heartbeats = models.IntegerField()
- prob_crashes = models.IntegerField()
- smpl = models.IntegerField()
- other = models.IntegerField()
+
+class VersionDaily(_DailyVersionStats):
+ version = models.ForeignKey(Version, db_index=True, related_name='daily_stats',
+ on_delete=models.CASCADE)
+
+
+class RadioVersion(_VersionStats):
+ radio_version = models.CharField(max_length=200, unique=True)
+
+ def __str__(self):
+ return self.radio_version
+
+class RadioVersionDaily(_DailyVersionStats):
+ version = models.ForeignKey(RadioVersion, db_index=True, related_name='daily_stats',
+ on_delete=models.CASCADE)
diff --git a/crashreports/migrations/0003_crashreport_and_heartbeat_with_radio_version.py b/crashreports/migrations/0003_crashreport_and_heartbeat_with_radio_version.py
new file mode 100644
index 0000000..564cc0e
--- /dev/null
+++ b/crashreports/migrations/0003_crashreport_and_heartbeat_with_radio_version.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+#
+# Extend the Crashreport and Heartbeat models to support the radio version.
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('crashreports', '0002_auto_20170502_1155'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='crashreport',
+ name='radio_version',
+ field=models.CharField(db_index=True, max_length=200, null=True),
+ ),
+ migrations.AddField(
+ model_name='heartbeat',
+ name='radio_version',
+ field=models.CharField(db_index=True, max_length=200, null=True),
+ ),
+ ]
diff --git a/crashreports/models.py b/crashreports/models.py
index b894522..56c4fb2 100644
--- a/crashreports/models.py
+++ b/crashreports/models.py
@@ -56,6 +56,7 @@
app_version = models.IntegerField()
uptime = models.CharField(max_length=200)
build_fingerprint = models.CharField(db_index=True, max_length=200)
+ radio_version = models.CharField(db_index=True, max_length=200, null=True)
boot_reason = models.CharField(db_index=True, max_length=200)
power_on_reason = models.CharField(db_index=True, max_length=200)
power_off_reason = models.CharField(db_index=True, max_length=200)
@@ -104,6 +105,7 @@
app_version = models.IntegerField()
uptime = models.CharField(max_length=200)
build_fingerprint = models.CharField( db_index=True, max_length=200)
+ radio_version = models.CharField(db_index=True, max_length=200, null=True)
date = models.DateTimeField(db_index=True)
device_local_id = models.PositiveIntegerField(blank=True)
created_at = models.DateTimeField(auto_now_add=True)
diff --git a/crashreports/rest_api_crashreports.py b/crashreports/rest_api_crashreports.py
index ecf5d74..b6555fd 100644
--- a/crashreports/rest_api_crashreports.py
+++ b/crashreports/rest_api_crashreports.py
@@ -12,7 +12,7 @@
paginate_by = 20
permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation, )
serializer_class = CrashReportSerializer
- filter_fields = ('device','build_fingerprint')
+ filter_fields = ('device', 'build_fingerprint', 'radio_version')
pass
diff --git a/crashreports/rest_api_heartbeats.py b/crashreports/rest_api_heartbeats.py
index 3db751f..841dec8 100644
--- a/crashreports/rest_api_heartbeats.py
+++ b/crashreports/rest_api_heartbeats.py
@@ -13,7 +13,7 @@
paginate_by = 20
permission_classes = (HasRightsOrIsDeviceOwnerDeviceCreation, )
serializer_class = HeartBeatSerializer
- filter_fields = ('device','build_fingerprint')
+ filter_fields = ('device', 'build_fingerprint', 'radio_version')
def get(self, *args, **kwargs):
diff --git a/crashreports/tests.py b/crashreports/tests.py
index 9f4465b..ea29d57 100644
--- a/crashreports/tests.py
+++ b/crashreports/tests.py
@@ -116,6 +116,7 @@
'app_version': 2,
'uptime': "2 Hours",
'build_fingerprint': "models.CharField(max_length=200)",
+ 'radio_version': 'XXXX.X-FP2-X-XX',
'date': str(datetime.datetime(year=2016, month=1, day=1))
}
@@ -214,6 +215,25 @@
request = self.user.get(self.url)
self.assertEqual(request.status_code, status.HTTP_403_FORBIDDEN)
+ def test_no_radio_version(self):
+ data = self.data.copy()
+ data.pop('radio_version')
+ self.post_multiple(self.user, data, 1)
+ url = self.url_by_uuid.format(self.uuid)
+ request = self.admin.get(url)
+ self.assertEqual(request.status_code, status.HTTP_200_OK)
+ self.assertEqual(len(request.data['results']), 1)
+ self.assertIsNone(request.data['results'][0]['radio_version'])
+
+ def test_radio_version_field(self):
+ self.post_multiple(self.user, self.data, 1)
+ url = self.url_by_uuid.format(self.uuid)
+ request = self.admin.get(url)
+ self.assertEqual(request.status_code, status.HTTP_200_OK)
+ self.assertEqual(len(request.data['results']), 1)
+ self.assertEqual(request.data['results'][0]['radio_version'],
+ self.data['radio_version'])
+
def create_crashreport(uuid="not set"):
return {
@@ -222,6 +242,7 @@
'app_version': 2,
'uptime': "2 Hours",
'build_fingerprint': "models.CharField(max_length=200)",
+ 'radio_version': 'XXXX.X-FP2-X-XX',
'boot_reason': "models.CharField(max_length=200)",
'power_on_reason': "models.CharField(max_length=200)",
'power_off_reason': "models.CharField(max_length=200)",