blob: 4502fbb8a6bd9e4bd5d75c79ae8083ae8cffd939 [file] [log] [blame]
"""Tests for the rest_endpoints module."""
import operator
from datetime import datetime, timedelta
import pytz
from django.test import override_settings
from django.urls import reverse
from django.utils.http import urlencode
from rest_framework import status
from crashreport_stats.models import RadioVersion
from crashreport_stats.tests.utils import Dummy, HiccupStatsAPITestCase
from crashreports.models import Crashreport, HeartBeat, LogFile
# pylint: disable=too-many-public-methods
class StatusTestCase(HiccupStatsAPITestCase):
"""Test the status endpoint."""
status_url = reverse("hiccup_stats_api_v1_status")
def _assert_status_response_is(
self, response, num_devices, num_crashreports, num_heartbeats
):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn("devices", response.data)
self.assertIn("crashreports", response.data)
self.assertIn("heartbeats", response.data)
self.assertEqual(response.data["devices"], num_devices)
self.assertEqual(response.data["crashreports"], num_crashreports)
self.assertEqual(response.data["heartbeats"], num_heartbeats)
def test_status_url_as_fp_staff(self):
"""Test that Fairphone staff users can access the status URL."""
self._assert_get_as_fp_staff_succeeds(self.status_url)
def test_status_url_as_device_owner(self):
"""Test that device owner users can not access the status URL."""
self._assert_get_as_device_owner_fails(self.status_url)
def test_status_url_no_auth(self):
"""Test that non-authenticated users can not access the status URL."""
self._assert_get_without_authentication_fails(self.status_url)
def test_get_status_empty_database(self):
"""Get the status when the database is empty."""
response = self.fp_staff_client.get(self.status_url)
# Assert that only the device that was created by the setUpTestData()
# method is found.
self._assert_status_response_is(response, 1, 0, 0)
def test_get_status(self):
"""Get the status after some reports have been created."""
# Create a device with a heartbeat and a crash report
device = Dummy.create_device(Dummy.create_user())
Dummy.create_report(HeartBeat, device)
Dummy.create_report(Crashreport, device)
# Create a second device without any reports
Dummy.create_device(Dummy.create_user(username=Dummy.USERNAMES[1]))
# Assert that the status includes the appropriate numbers (a third
# device was created by the setUpTestData() method)
response = self.fp_staff_client.get(self.status_url)
self._assert_status_response_is(
response, num_devices=3, num_crashreports=1, num_heartbeats=1
)
class _VersionTestCase(HiccupStatsAPITestCase):
"""Abstract class for version-related test cases to inherit from."""
@staticmethod
def _create_dummy_version(**kwargs):
return Dummy.create_version(**kwargs)
def _get_with_params(self, url, params):
return self.fp_staff_client.get("{}?{}".format(url, urlencode(params)))
def _assert_result_length_is(self, response, count):
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn("results", response.data)
self.assertIn("count", response.data)
self.assertEqual(response.data["count"], count)
self.assertEqual(len(response.data["results"]), count)
def _assert_filter_result_matches(
self, endpoint_url, unique_entry_name, filter_params, expected_result
):
# List entities with filter
response = self._get_with_params(endpoint_url, filter_params)
# Expect only the single matching result to be returned
self._assert_result_length_is(response, 1)
self.assertEqual(
response.data["results"][0][unique_entry_name],
getattr(expected_result, unique_entry_name),
)
class VersionTestCase(_VersionTestCase):
"""Test the Version and REST endpoint."""
# pylint: disable=too-many-ancestors
# The attribute name characterising the unicity of a stats entry (the
# named identifier)
unique_entry_name = "build_fingerprint"
# The collection of unique entries to post
unique_entries = Dummy.BUILD_FINGERPRINTS
# The URL to retrieve the stats entries from
endpoint_url = reverse("hiccup_stats_api_v1_versions")
def _create_version_entities(self):
versions = [
self._create_dummy_version(**{self.unique_entry_name: unique_entry})
for unique_entry in self.unique_entries
]
return versions
def test_endpoint_url_as_fp_staff(self):
"""Test that Fairphone staff users can access the endpoint URL."""
self._assert_get_as_fp_staff_succeeds(self.endpoint_url)
def test_endpoint_url_as_device_owner(self):
"""Test that device owner users can not access the endpoint URL."""
self._assert_get_as_device_owner_fails(self.endpoint_url)
def test_endpoint_url_no_auth(self):
"""Test that non-authenticated users can not access the endpoint URL."""
self._assert_get_without_authentication_fails(self.endpoint_url)
def test_list_versions_empty_database(self):
"""Test listing of versions on an empty database."""
response = self.fp_staff_client.get(self.endpoint_url)
self._assert_result_length_is(response, 0)
def test_list_versions(self):
"""Test listing versions."""
versions = self._create_version_entities()
response = self.fp_staff_client.get(self.endpoint_url)
self._assert_result_length_is(response, len(versions))
def test_filter_versions_by_unique_entry_name(self):
"""Test filtering versions by their unique entry name."""
versions = self._create_version_entities()
response = self.fp_staff_client.get(self.endpoint_url)
# Listing all entities should return the correct result length
self._assert_result_length_is(response, len(versions))
# List entities with filter
filter_params = {
self.unique_entry_name: getattr(versions[0], self.unique_entry_name)
}
self._assert_filter_result_matches(
self.endpoint_url,
self.unique_entry_name,
filter_params,
expected_result=versions[0],
)
def test_filter_versions_by_release_type(self):
"""Test filtering versions by release type."""
# Create versions for all combinations of release types
versions = []
i = 0
for is_official_release in True, False:
for is_beta_release in True, False:
versions.append(
self._create_dummy_version(
**{
"is_official_release": is_official_release,
"is_beta_release": is_beta_release,
self.unique_entry_name: self.unique_entries[i],
}
)
)
i += 1
# # Listing all entities should return the correct result length
response = self.fp_staff_client.get(self.endpoint_url)
self._assert_result_length_is(response, len(versions))
# List each of the entities with the matching filter params
for version in versions:
filter_params = {
"is_official_release": version.is_official_release,
"is_beta_release": version.is_beta_release,
}
self._assert_filter_result_matches(
self.endpoint_url,
self.unique_entry_name,
filter_params,
expected_result=version,
)
def test_filter_versions_by_first_seen_date(self):
"""Test filtering versions by first seen date."""
versions = self._create_version_entities()
# Set the first seen date of an entity
versions[0].first_seen_on = Dummy.DATES[2]
versions[0].save()
# Listing all entities should return the correct result length
response = self.fp_staff_client.get(self.endpoint_url)
self._assert_result_length_is(response, len(versions))
# Expect the single matching result to be returned
filter_params = {"first_seen_after": Dummy.DATES[2]}
self._assert_filter_result_matches(
self.endpoint_url,
self.unique_entry_name,
filter_params,
expected_result=versions[0],
)
# pylint: disable=too-many-ancestors
class RadioVersionTestCase(VersionTestCase):
"""Test the RadioVersion REST endpoint."""
unique_entry_name = "radio_version"
unique_entries = Dummy.RADIO_VERSIONS
endpoint_url = reverse("hiccup_stats_api_v1_radio_versions")
@staticmethod
def _create_dummy_version(**kwargs):
return Dummy.create_version(RadioVersion, **kwargs)
class VersionDailyTestCase(_VersionTestCase):
"""Test the VersionDaily REST endpoint."""
unique_entry_name = "build_fingerprint"
unique_entries = Dummy.BUILD_FINGERPRINTS
endpoint_url = reverse("hiccup_stats_api_v1_version_daily")
@staticmethod
def _create_dummy_daily_version(version, **kwargs):
return Dummy.create_daily_version(version, **kwargs)
def _create_version_entities(self):
versions = [
self._create_dummy_version(**{self.unique_entry_name: unique_entry})
for unique_entry in self.unique_entries
]
versions_daily = [
self._create_dummy_daily_version(version=version)
for version in versions
]
return versions_daily
def test_endpoint_url_as_fp_staff(self):
"""Test that Fairphone staff users can access the endpoint URL."""
self._assert_get_as_fp_staff_succeeds(self.endpoint_url)
def test_endpoint_url_as_device_owner(self):
"""Test that device owner users can not access the endpoint URL."""
self._assert_get_as_device_owner_fails(self.endpoint_url)
def test_endpoint_url_no_auth(self):
"""Test that non-authenticated users can not access the endpoint URL."""
self._assert_get_without_authentication_fails(self.endpoint_url)
def test_list_daily_versions_empty_database(self):
"""Test listing of daily versions on an empty database."""
response = self.fp_staff_client.get(self.endpoint_url)
self._assert_result_length_is(response, 0)
def test_list_daily_versions(self):
"""Test listing daily versions."""
versions_daily = self._create_version_entities()
response = self.fp_staff_client.get(self.endpoint_url)
self._assert_result_length_is(response, len(versions_daily))
def test_filter_daily_versions_by_version(self):
"""Test filtering versions by the version they relate to."""
# Create VersionDaily entities
versions = self._create_version_entities()
# Listing all entities should return the correct result length
response = self.fp_staff_client.get(self.endpoint_url)
self._assert_result_length_is(response, len(versions))
# List entities with filter
param_name = "version__" + self.unique_entry_name
filter_params = {
param_name: getattr(versions[0].version, self.unique_entry_name)
}
self._assert_filter_result_matches(
self.endpoint_url,
self.unique_entry_name,
filter_params,
expected_result=versions[0].version,
)
def test_filter_daily_versions_by_date(self):
"""Test filtering daily versions by date."""
# Create Version and VersionDaily entities
versions = self._create_version_entities()
# Update the date
versions[0].date = Dummy.DATES[2]
versions[0].save()
# Listing all entities should return the correct result length
response = self.fp_staff_client.get(self.endpoint_url)
self._assert_result_length_is(response, len(versions))
# Expect the single matching result to be returned
filter_params = {"date": versions[0].date}
self._assert_filter_result_matches(
self.endpoint_url,
self.unique_entry_name,
filter_params,
expected_result=versions[0].version,
)
class RadioVersionDailyTestCase(VersionDailyTestCase):
"""Test the RadioVersionDaily REST endpoint."""
unique_entry_name = "radio_version"
unique_entries = Dummy.RADIO_VERSIONS
endpoint_url = reverse("hiccup_stats_api_v1_radio_version_daily")
@staticmethod
def _create_dummy_version(**kwargs):
return Dummy.create_version(RadioVersion, **kwargs)
@staticmethod
def _create_dummy_daily_version(version, **kwargs):
return Dummy.create_daily_radio_version(version, **kwargs)
@override_settings(MEDIA_ROOT=Dummy.DEFAULT_LOG_FILE_DIRECTORY)
class DeviceStatsTestCase(HiccupStatsAPITestCase):
"""Test the single device stats REST endpoints."""
device_overview_url = "hiccup_stats_api_v1_device_overview"
device_report_history_url = "hiccup_stats_api_v1_device_report_history"
device_update_history_url = "hiccup_stats_api_v1_device_update_history"
device_logfile_download_url = "hiccup_stats_api_v1_logfile_download"
def _get_with_params(self, url, params):
url = reverse(url, kwargs=params)
return self.fp_staff_client.get(url)
def _assert_device_stats_response_is(
self,
response,
uuid,
board_date,
num_heartbeats,
num_crashreports,
num_smpls,
crashes_per_day,
smpl_per_day,
last_active,
):
# pylint: disable=too-many-arguments
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn("uuid", response.data)
self.assertIn("board_date", response.data)
self.assertIn("heartbeats", response.data)
self.assertIn("crashreports", response.data)
self.assertIn("smpls", response.data)
self.assertIn("crashes_per_day", response.data)
self.assertIn("smpl_per_day", response.data)
self.assertIn("last_active", response.data)
self.assertEqual(response.data["uuid"], uuid)
self.assertEqual(response.data["board_date"], board_date)
self.assertEqual(response.data["heartbeats"], num_heartbeats)
self.assertEqual(response.data["crashreports"], num_crashreports)
self.assertEqual(response.data["smpls"], num_smpls)
self.assertEqual(response.data["crashes_per_day"], crashes_per_day)
self.assertEqual(response.data["smpl_per_day"], smpl_per_day)
self.assertEqual(response.data["last_active"], last_active)
def test_device_overview_url_as_fp_staff(self):
"""Test that Fairphone staff users can access the URL."""
self._assert_get_as_fp_staff_succeeds(
reverse(
self.device_overview_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def test_device_overview_url_as_device_owner(self):
"""Test that device owner users can not access the URL."""
self._assert_get_as_device_owner_fails(
reverse(
self.device_overview_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def test_device_overview_url_no_auth(self):
"""Test that non-authenticated users can not access the URL."""
self._assert_get_without_authentication_fails(
reverse(
self.device_overview_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def test_device_report_history_url_as_fp_staff(self):
"""Test that FP staff can access device report history URL."""
self._assert_get_as_fp_staff_succeeds(
reverse(
self.device_report_history_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def test_device_report_history_url_as_device_owner(self):
"""Test that device owners can't access device report history URL."""
self._assert_get_as_device_owner_fails(
reverse(
self.device_report_history_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def test_device_report_history_url_no_auth(self):
"""Test that device report history is not accessible without auth."""
self._assert_get_without_authentication_fails(
reverse(
self.device_report_history_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def test_device_update_history_url_as_fp_staff(self):
"""Test that FP staff can access device update history URL."""
self._assert_get_as_fp_staff_succeeds(
reverse(
self.device_update_history_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def test_device_update_history_url_as_device_owner(self):
"""Test that device owners can't access device update history URL."""
self._assert_get_as_device_owner_fails(
reverse(
self.device_update_history_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def test_device_update_history_url_no_auth(self):
"""Test that device update history is not accessible without auth."""
self._assert_get_without_authentication_fails(
reverse(
self.device_update_history_url,
kwargs={"uuid": self.device_owner_device.uuid},
)
)
def tes_logfile_download_url_as_fp_staff(self):
"""Test that FP staff can access the logfile download URL."""
non_existent_logfile_id = 0
self.assertFalse(
LogFile.objects.filter(id=non_existent_logfile_id).exists()
)
self._assert_get_as_fp_staff_succeeds(
reverse(
self.device_logfile_download_url,
kwargs={"id_logfile": non_existent_logfile_id},
),
expected_status=status.HTTP_404_NOT_FOUND,
)
def test_logfile_download_url_as_device_owner(self):
"""Test that device owners can't access the logfile download URL."""
non_existent_logfile_id = 0
self.assertFalse(
LogFile.objects.filter(id=non_existent_logfile_id).exists()
)
self._assert_get_as_device_owner_fails(
reverse(
self.device_logfile_download_url,
kwargs={"id_logfile": non_existent_logfile_id},
)
)
def test_logfile_download_url_no_auth(self):
"""Test that the logfile download URL is not accessible without auth."""
non_existent_logfile_id = 0
self.assertFalse(
LogFile.objects.filter(id=non_existent_logfile_id).exists()
)
self._assert_get_without_authentication_fails(
reverse(
self.device_logfile_download_url,
kwargs={"id_logfile": non_existent_logfile_id},
)
)
def test_get_device_stats_no_reports(self):
"""Test getting device stats for a device without reports."""
# Create a device
device = Dummy.create_device(Dummy.create_user())
# Get the device statistics
response = self._get_with_params(
self.device_overview_url, {"uuid": device.uuid}
)
# Assert that the statistics match
self._assert_device_stats_response_is(
response=response,
uuid=str(device.uuid),
board_date=device.board_date,
num_heartbeats=0,
num_crashreports=0,
num_smpls=0,
crashes_per_day=0.0,
smpl_per_day=0.0,
last_active=device.board_date,
)
def test_get_device_stats_no_crash_reports(self):
"""Test getting device stats for a device without crashreports."""
# Create a device and a heartbeat
device = Dummy.create_device(Dummy.create_user())
heartbeat = Dummy.create_report(HeartBeat, device)
# Get the device statistics
response = self._get_with_params(
self.device_overview_url, {"uuid": device.uuid}
)
# Assert that the statistics match
self._assert_device_stats_response_is(
response=response,
uuid=str(device.uuid),
board_date=device.board_date,
num_heartbeats=1,
num_crashreports=0,
num_smpls=0,
crashes_per_day=0.0,
smpl_per_day=0.0,
last_active=heartbeat.date,
)
def test_get_device_stats_no_heartbeats(self):
"""Test getting device stats for a device without heartbeats."""
# Create a device and crashreport
device = Dummy.create_device(Dummy.create_user())
Dummy.create_report(Crashreport, device)
# Get the device statistics
response = self._get_with_params(
self.device_overview_url, {"uuid": device.uuid}
)
# Assert that the statistics match
self._assert_device_stats_response_is(
response=response,
uuid=str(device.uuid),
board_date=device.board_date,
num_heartbeats=0,
num_crashreports=1,
num_smpls=0,
crashes_per_day=0.0,
smpl_per_day=0.0,
last_active=device.board_date,
)
def test_get_device_stats(self):
"""Test getting device stats for a device."""
# Create a device with a heartbeat and one report of each type
device = Dummy.create_device(Dummy.create_user())
crashreport_date = Dummy.DEFAULT_CRASHREPORT_VALUES["date"]
heartbeat = Dummy.create_report(
HeartBeat, device, date=crashreport_date.date()
)
for boot_reason in (
Crashreport.SMPL_BOOT_REASONS
+ Crashreport.CRASH_BOOT_REASONS
+ ["other boot reason"]
):
Dummy.create_report(
Crashreport,
device,
boot_reason=boot_reason,
date=crashreport_date,
)
crashreport_date += timedelta(milliseconds=1)
# Get the device statistics
response = self._get_with_params(
self.device_overview_url, {"uuid": device.uuid}
)
# Assert that the statistics match
self._assert_device_stats_response_is(
response=response,
uuid=str(device.uuid),
board_date=device.board_date,
num_heartbeats=1,
num_crashreports=len(Crashreport.CRASH_BOOT_REASONS),
num_smpls=len(Crashreport.SMPL_BOOT_REASONS),
crashes_per_day=len(Crashreport.CRASH_BOOT_REASONS),
smpl_per_day=len(Crashreport.SMPL_BOOT_REASONS),
last_active=heartbeat.date,
)
def test_get_device_stats_multiple_days(self):
"""Test getting device stats for a device that sent more reports."""
# Create a device with some heartbeats and reports over time
device = Dummy.create_device(Dummy.create_user())
num_days = 100
for i in range(num_days):
report_date = datetime.now(tz=pytz.utc) + timedelta(days=i)
heartbeat = Dummy.create_report(
HeartBeat, device, date=report_date.date()
)
Dummy.create_report(Crashreport, device, date=report_date)
Dummy.create_report(
Crashreport,
device,
date=report_date + timedelta(minutes=1),
boot_reason=Crashreport.SMPL_BOOT_REASONS[0],
)
# Get the device statistics
response = self._get_with_params(
self.device_overview_url, {"uuid": device.uuid}
)
# Assert that the statistics match
self._assert_device_stats_response_is(
response=response,
uuid=str(device.uuid),
board_date=device.board_date,
num_heartbeats=num_days,
num_crashreports=num_days,
num_smpls=num_days,
crashes_per_day=1,
smpl_per_day=1,
last_active=heartbeat.date,
)
def test_get_device_stats_multiple_days_missing_heartbeat(self):
"""Test getting device stats for a device with missing heartbeat."""
# Create a device with some heartbeats and reports over time
device = Dummy.create_device(Dummy.create_user())
num_days = 100
skip_day = round(num_days / 2)
for i in range(num_days):
report_date = datetime.now(tz=pytz.utc) + timedelta(days=i)
# Skip creation of heartbeat at one day
if i != skip_day:
heartbeat = Dummy.create_report(
HeartBeat, device, date=report_date.date()
)
Dummy.create_report(Crashreport, device, date=report_date)
# Get the device statistics
response = self._get_with_params(
self.device_overview_url, {"uuid": device.uuid}
)
# Assert that the statistics match
self._assert_device_stats_response_is(
response=response,
uuid=str(device.uuid),
board_date=device.board_date,
num_heartbeats=num_days - 1,
num_crashreports=num_days,
num_smpls=0,
crashes_per_day=num_days / (num_days - 1),
smpl_per_day=0,
last_active=heartbeat.date,
)
def test_get_device_report_history_no_reports(self):
"""Test getting report history stats for a device without reports."""
# Create a device
device = Dummy.create_device(Dummy.create_user())
# Get the device report history statistics
response = self._get_with_params(
self.device_report_history_url, {"uuid": device.uuid}
)
# Assert that the report history is empty
self.assertEqual([], response.data)
def test_get_device_report_history(self):
"""Test getting report history stats for a device."""
# Create a device with a heartbeat and one report of each type
device = Dummy.create_device(Dummy.create_user())
crashreport_date = Dummy.DEFAULT_CRASHREPORT_VALUES["date"]
heartbeat = Dummy.create_report(
HeartBeat, device, date=crashreport_date.date()
)
for boot_reason in (
Crashreport.SMPL_BOOT_REASONS
+ Crashreport.CRASH_BOOT_REASONS
+ ["other boot reason"]
):
Dummy.create_report(
Crashreport,
device,
boot_reason=boot_reason,
date=crashreport_date,
)
crashreport_date += timedelta(milliseconds=1)
# Get the device report history statistics
response = self._get_with_params(
self.device_report_history_url, {"uuid": device.uuid}
)
# Assert that the statistics match
report_history = [
{
"date": heartbeat.date,
"heartbeats": 1,
"smpl": len(Crashreport.SMPL_BOOT_REASONS),
"prob_crashes": len(Crashreport.CRASH_BOOT_REASONS),
"other": 1,
}
]
self.assertEqual(report_history, response.data)
def test_get_device_report_history_multiple_days(self):
"""Test getting report history stats for a device for multiple days."""
device = Dummy.create_device(Dummy.create_user())
expected_report_history = []
# Create a device with a heartbeat and one report of each type for 10
# days
report_date = Dummy.DEFAULT_CRASHREPORT_VALUES["date"]
for _ in range(10):
report_date = report_date + timedelta(days=1)
Dummy.create_report(HeartBeat, device, date=report_date.date())
for i, boot_reason in enumerate(
Crashreport.SMPL_BOOT_REASONS
+ Crashreport.CRASH_BOOT_REASONS
+ ["other boot reason"]
):
Dummy.create_report(
Crashreport,
device,
boot_reason=boot_reason,
date=report_date + timedelta(milliseconds=i),
)
# Create the expected report history object
expected_report_history.append(
{
"date": report_date.date(),
"heartbeats": 1,
"smpl": len(Crashreport.SMPL_BOOT_REASONS),
"prob_crashes": len(Crashreport.CRASH_BOOT_REASONS),
"other": 1,
}
)
# Sort the expected values by date
expected_report_history.sort(key=operator.itemgetter("date"))
# Get the device report history statistics
response = self._get_with_params(
self.device_report_history_url, {"uuid": device.uuid}
)
# Assert that the statistics match
self.assertEqual(expected_report_history, response.data)
def test_get_device_update_history_no_reports(self):
"""Test getting update history stats for a device without reports."""
# Create a device
device = Dummy.create_device(Dummy.create_user())
# Get the device report history statistics
response = self._get_with_params(
self.device_update_history_url, {"uuid": device.uuid}
)
# Assert that the update history is empty
self.assertEqual([], response.data)
def test_get_device_update_history(self):
"""Test getting update history stats for a device."""
# Create a device with a heartbeat and one report of each type
device = Dummy.create_device(Dummy.create_user())
crashreport_date = Dummy.DEFAULT_CRASHREPORT_VALUES["date"]
heartbeat = Dummy.create_report(
HeartBeat, device, date=crashreport_date.date()
)
for boot_reason in (
Crashreport.SMPL_BOOT_REASONS
+ Crashreport.CRASH_BOOT_REASONS
+ ["other boot reason"]
):
params = {"boot_reason": boot_reason, "date": crashreport_date}
Dummy.create_report(Crashreport, device, **params)
crashreport_date += timedelta(milliseconds=1)
# Get the device update history statistics
response = self._get_with_params(
self.device_update_history_url, {"uuid": device.uuid}
)
# Assert that the statistics match
update_history = [
{
"build_fingerprint": heartbeat.build_fingerprint,
"heartbeats": 1,
"max": device.id,
"other": 1,
"prob_crashes": len(Crashreport.CRASH_BOOT_REASONS),
"smpl": len(Crashreport.SMPL_BOOT_REASONS),
"update_date": heartbeat.date,
}
]
self.assertEqual(update_history, response.data)
def test_get_device_update_history_multiple_updates(self):
"""Test getting update history stats with multiple updates."""
# Create a device with a heartbeats and crashreport for each build
# fingerprint in the dummy values
device = Dummy.create_device(Dummy.create_user())
expected_update_history = []
for i, build_fingerprint in enumerate(Dummy.BUILD_FINGERPRINTS):
report_date = datetime.now(tz=pytz.utc) + timedelta(days=i)
Dummy.create_report(
HeartBeat,
device,
date=report_date,
build_fingerprint=build_fingerprint,
)
Dummy.create_report(
Crashreport,
device,
date=report_date,
build_fingerprint=build_fingerprint,
)
# Create the expected update history object
expected_update_history.append(
{
"update_date": report_date.date(),
"build_fingerprint": build_fingerprint,
"max": device.id,
"prob_crashes": 1,
"smpl": 0,
"other": 0,
"heartbeats": 1,
}
)
# Sort the expected values by update date
expected_update_history.sort(key=operator.itemgetter("update_date"))
# Get the device update history statistics
response = self._get_with_params(
self.device_update_history_url, {"uuid": device.uuid}
)
# Assert that the statistics match
self.assertEqual(expected_update_history, response.data)
def test_download_non_existing_logfile(self):
"""Test download of a non existing log file."""
# Try to get a log file
response = self._get_with_params(
self.device_logfile_download_url, {"id_logfile": 0}
)
# Assert that the log file was not found
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
def test_download_logfile(self):
"""Test download of log files."""
# Create a device with a crash report along with log file
device = Dummy.create_device(Dummy.create_user())
crashreport = Dummy.create_report(Crashreport, device)
logfile = Dummy.create_log_file(crashreport)
# Get the log file
response = self._get_with_params(
self.device_logfile_download_url, {"id_logfile": logfile.id}
)
# Assert that the log file contents are in the response data
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertIn(Dummy.DEFAULT_LOG_FILE_NAME, response.data)
expected_logfile_content = Dummy.read_logfile_contents(
logfile.logfile.path, Dummy.DEFAULT_LOG_FILE_NAME
)
self.assertEqual(
response.data[Dummy.DEFAULT_LOG_FILE_NAME], expected_logfile_content
)