blob: 6ec7486a87bc46a41b8c3c0cb37a4875dd950739 [file] [log] [blame]
Mitja Nikolaus03e412b2018-09-18 17:50:15 +02001"""Utility functions shared by all crashreports tests."""
2
3from typing import Optional
4
5from django.contrib.auth.models import User
6from django.urls import reverse
7from rest_framework import status
8from rest_framework.test import APITestCase, APIClient
9
10from crashreports.models import Crashreport
11
12
13class InvalidCrashTypeError(BaseException):
14 """Invalid crash type encountered.
15
16 The valid crash type values (strings) are:
17 - 'crash';
18 - 'smpl';
19 - 'other'.
20
21 Args:
22 - crash_type: The invalid crash type.
23 """
24
25 def __init__(self, crash_type):
26 """Initialise the exception using the crash type to build a message.
27
28 Args:
29 crash_type: The invalid crash type.
30 """
31 super(InvalidCrashTypeError, self).__init__(
32 "{} is not a valid crash type".format(crash_type)
33 )
34
35
36class Dummy:
37 """Dummy values for devices, heartbeats and crashreports."""
38
39 DEFAULT_DUMMY_DEVICE_REGISTER_VALUES = {
40 "board_date": "2015-12-15T01:23:45Z",
41 "chipset": "Qualcomm MSM8974PRO-AA",
42 }
43
44 DEFAULT_DUMMY_HEARTBEAT_VALUES = {
45 "uuid": None,
46 "app_version": 10100,
47 "uptime": (
48 "up time: 16 days, 21:49:56, idle time: 5 days, 20:55:04, "
49 "sleep time: 10 days, 20:46:27"
50 ),
51 "build_fingerprint": (
52 "Fairphone/FP2/FP2:6.0.1/FP2-gms-18.03.1/FP2-gms-18.03.1:user/"
53 "release-keys"
54 ),
55 "radio_version": "4437.1-FP2-0-08",
56 "date": "2018-03-19T09:58:30.386Z",
57 }
58
59 DEFAULT_DUMMY_CRASHREPORTS_VALUES = DEFAULT_DUMMY_HEARTBEAT_VALUES.copy()
60 DEFAULT_DUMMY_CRASHREPORTS_VALUES.update(
61 {
62 "is_fake_report": 0,
63 "boot_reason": "why?",
64 "power_on_reason": "it was powered on",
65 "power_off_reason": "something happened and it went off",
66 }
67 )
68
69 CRASH_TYPE_TO_BOOT_REASON_MAP = {
70 "crash": Crashreport.BOOT_REASON_KEYBOARD_POWER_ON,
71 "smpl": Crashreport.BOOT_REASON_RTC_ALARM,
72 "other": "whatever",
73 }
74
75 @staticmethod
76 def _update_copy(original, update):
77 """Merge fields of update into a copy of original."""
78 data = original.copy()
79 data.update(update)
80 return data
81
82 @staticmethod
83 def device_register_data(**kwargs):
84 """Return the data required to register a device.
85
86 Use the values passed as keyword arguments or default to the ones
87 from `Dummy.DEFAULT_DUMMY_DEVICE_REGISTER_VALUES`.
88 """
89 return Dummy._update_copy(
90 Dummy.DEFAULT_DUMMY_DEVICE_REGISTER_VALUES, kwargs
91 )
92
93 @staticmethod
94 def heartbeat_data(**kwargs):
95 """Return the data required to create a heartbeat.
96
97 Use the values passed as keyword arguments or default to the ones
98 from `Dummy.DEFAULT_DUMMY_HEARTBEAT_VALUES`.
99 """
100 return Dummy._update_copy(Dummy.DEFAULT_DUMMY_HEARTBEAT_VALUES, kwargs)
101
102 @staticmethod
103 def crashreport_data(report_type: Optional[str] = None, **kwargs):
104 """Return the data required to create a crashreport.
105
106 Use the values passed as keyword arguments or default to the ones
107 from `Dummy.DEFAULT_DUMMY_CRASHREPORTS_VALUES`.
108
109 Args:
110 report_type: A valid value from
111 `Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP.keys()` that will
112 define the boot reason if not explicitly defined in the
113 keyword arguments already.
114 """
115 data = Dummy._update_copy(
116 Dummy.DEFAULT_DUMMY_CRASHREPORTS_VALUES, kwargs
117 )
118 if report_type and "boot_reason" not in kwargs:
119 if report_type not in Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP:
120 raise InvalidCrashTypeError(report_type)
121 data["boot_reason"] = Dummy.CRASH_TYPE_TO_BOOT_REASON_MAP.get(
122 report_type
123 )
124 return data
125
126
127class HiccupCrashreportsAPITestCase(APITestCase):
128 """Base class that offers a device registration method."""
129
130 REGISTER_DEVICE_URL = "api_v1_register_device"
131
132 def setUp(self):
133 """Create an admin user for accessing the API.
134
135 The APIClient that can be used to make authenticated requests to the
136 server is stored in self.admin.
137 """
138 admin_user = User.objects.create_superuser(
139 "somebody", "somebody@example.com", "thepassword"
140 )
141 self.admin = APIClient()
142 self.admin.force_authenticate(admin_user)
143
144 def _register_device(self, **kwargs):
145 """Register a new device.
146
147 Arguments:
148 **kwargs: The data to pass the dummy data creation
149 method `Dummy.device_register_data`.
150 Returns:
151 (UUID, APIClient, str): The uuid of the new device as well as an
152 authentication token and the associated user with credentials.
153
154 """
155 data = Dummy.device_register_data(**kwargs)
156 response = self.client.post(reverse(self.REGISTER_DEVICE_URL), data)
157 self.assertEqual(response.status_code, status.HTTP_200_OK)
158
159 uuid = response.data["uuid"]
160 token = response.data["token"]
161 user = APIClient()
162 user.credentials(HTTP_AUTHORIZATION="Token " + token)
163
164 return uuid, user, token