def test_zone_list_get_with_sensor_filter(self, api_root): excluded_zone = Zone( name='Test Zone Excluded', notes='Zone notes.', key=uuid4() ) excluded_zone.save() excluded_sensor = Sensor( guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=excluded_zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) excluded_sensor.save() suffix = 'zones/?sensor_ids={}&format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_zone_json = [x for x in data if x['id'] == str(excluded_zone.id)] assert len(excluded_zone_json) == 0 excluded_sensor.delete() excluded_zone.delete() zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json)
def test_sensor_data_detail_post_guid(self, api_root): """ Test adding sensor data with only supplying a Sensor guid, sensor data value and a zone key. If the sensor doesn't exist, this will create it. """ zone = Zone(name='Test Zone', key=uuid4()) zone.save() guid = 'DEADBEEF00000012345TEST' value_first = 15.0 value_second = 25.0 num_sensors_before_add = Sensor.objects.all().count() data_dict = { 'guid': guid, 'value': value_first, 'key': str(zone.key), } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'data/', data=json.dumps(data_dict), headers=headers ) response_json_first = response.json() num_sensors_after_add = Sensor.objects.all().count() assert response.status_code == 201 assert num_sensors_before_add + 1 == num_sensors_after_add data = SensorData.objects.get(pk=response_json_first["id"]) data.delete() data_dict = { 'guid': guid, 'value': value_second, 'key': str(zone.key), } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'data/', data=json.dumps(data_dict), headers=headers ) response_json_second = response.json() num_sensors_after_second_request = Sensor.objects.all().count() # Ensure we didn't add another sensor assert response.status_code == 201 assert num_sensors_after_add == num_sensors_after_second_request assert response_json_first["sensor"] == response_json_second["sensor"] data = SensorData.objects.get(pk=response_json_second["id"]) sensor = Sensor.objects.get(pk=data.sensor.id) data.delete() sensor.delete()
def test_sensor_data_detail_post_guid(self, api_root): """ Test adding sensor data with only supplying a Sensor guid, sensor data value and a zone key. If the sensor doesn't exist, this will create it. """ zone = Zone(name='Test Zone', key=uuid4()) zone.save() guid = 'DEADBEEF00000012345TEST' value_first = 15.0 value_second = 25.0 num_sensors_before_add = Sensor.objects.all().count() data_dict = { 'guid': guid, 'value': value_first, 'key': str(zone.key), } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'data/', data=json.dumps(data_dict), headers=headers) response_json_first = response.json() num_sensors_after_add = Sensor.objects.all().count() assert response.status_code == 201 assert num_sensors_before_add + 1 == num_sensors_after_add data = SensorData.objects.get(pk=response_json_first["id"]) data.delete() data_dict = { 'guid': guid, 'value': value_second, 'key': str(zone.key), } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'data/', data=json.dumps(data_dict), headers=headers) response_json_second = response.json() num_sensors_after_second_request = Sensor.objects.all().count() # Ensure we didn't add another sensor assert response.status_code == 201 assert num_sensors_after_add == num_sensors_after_second_request assert response_json_first["sensor"] == response_json_second["sensor"] data = SensorData.objects.get(pk=response_json_second["id"]) sensor = Sensor.objects.get(pk=data.sensor.id) data.delete() sensor.delete()
def test_zone_list_get_with_zone_filter(self, api_root): excluded_zone = Zone( name='Test Zone Excluded', notes='Zone notes.', key=uuid4() ) excluded_zone.save() suffix = 'zones/?zone_ids={}&format=json'.format(self.zone.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_zone_json = [x for x in data if x['id'] == str(excluded_zone.id)] assert len(excluded_zone_json) == 0 excluded_zone.delete() zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json)
def create_data(self, request): def finalizer(): if self.data is not None: for data in self.data: data.delete() self.data = None if self.sensor is not None: self.sensor.delete() self.sensor = None if self.zone is not None: self.zone.delete() self.zone = None self.zone = Zone(name='Test Zone', notes='Zone notes.', key=uuid4()) self.zone.save() self.sensor = Sensor(guid=uuid4(), name='Test Sensor', notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) self.sensor.save() self.data = [] for i in range(3): datum = SensorData(sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + i, state=True, state_changed=False) datum.save() self.data.append(datum) request.addfinalizer(finalizer)
def test_zone_list_get_with_sensor_filter(self, api_root): excluded_zone = Zone(name='Test Zone Excluded', notes='Zone notes.', key=uuid4()) excluded_zone.save() excluded_sensor = Sensor(guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=excluded_zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) excluded_sensor.save() suffix = 'zones/?sensor_ids={}&format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_zone_json = [ x for x in data if x['id'] == str(excluded_zone.id) ] assert len(excluded_zone_json) == 0 excluded_sensor.delete() excluded_zone.delete() zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json)
def create_data(self, request): def finalizer(): if self.data is not None: for data in self.data: data.delete() self.data = None if self.sensor is not None: self.sensor.delete() self.sensor = None if self.zone is not None: self.zone.delete() self.zone = None self.zone = Zone( name='Test Zone', notes='Zone notes.', key=uuid4() ) self.zone.save() self.sensor = Sensor( guid=uuid4(), name='Test Sensor', notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) self.sensor.save() self.data = [] for i in range(3): datum = SensorData( sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + i, state=True, state_changed=False ) datum.save() self.data.append(datum) request.addfinalizer(finalizer)
def test_zone_list_get_with_zone_filter(self, api_root): excluded_zone = Zone(name='Test Zone Excluded', notes='Zone notes.', key=uuid4()) excluded_zone.save() suffix = 'zones/?zone_ids={}&format=json'.format(self.zone.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_zone_json = [ x for x in data if x['id'] == str(excluded_zone.id) ] assert len(excluded_zone_json) == 0 excluded_zone.delete() zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json)
def create_data(self, request): def finalizer(): if self.alerts is not None: for alert in self.alerts: alert.delete() self.alerts = None if self.data is not None: for data in self.data: data.delete() self.data = None if self.sensor is not None: self.sensor.delete() self.sensor = None if self.zone is not None: self.zone.delete() self.zone = None if self.alert_group is not None: self.alert_group.delete() self.alert_group = None if self.user is not None: self.user.delete() username = str(uuid4())[:30] self.user = User(username=username, email='{}@example.net'.format(username)) self.user.save() self.alert_group = SensorAlertGroup(name='Test Group') self.alert_group.save() self.alert_group.users.add(self.user) self.zone = Zone(name='Test Zone', notes='Zone notes.', key=uuid4()) self.zone.save() self.sensor = Sensor(guid=uuid4(), name='Test Sensor', notes='Sensor notes.', zone=self.zone, min_value=60, max_value=85, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) self.sensor.save() self.sensor.alert_groups.add(self.alert_group) self.data = [] # Inbox is empty assert 0 == len(mail.outbox) # Create in-range data point; no notification. datum = SensorData(sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + 1, state=True, state_changed=False) datum.save() self.data.append(datum) # Inbox still empty assert 0 == len(mail.outbox) # Create out-of-range notification; sends "alert." datum = SensorData(sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value - 1, state=True, state_changed=False) datum.save() self.data.append(datum) # Inbox received alert assert 1 == len(mail.outbox) # Create another in-range data point; sends "recovered." datum = SensorData(sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + 1, state=True, state_changed=False) datum.save() self.data.append(datum) # Inbox received recovery email assert 2 == len(mail.outbox) self.alerts = SensorAlert.objects.all().order_by('id') request.addfinalizer(finalizer)
class TestSensorsApi(object): user = None alert_group = None zone = None sensor = None data = None alerts = None @pytest.fixture(autouse=True) def api_root(self, request, live_server): api_root = '{}{}api/v1/'.format( live_server.url, '/' if not live_server.url.endswith('/') else '') return api_root @pytest.fixture(autouse=True) def create_data(self, request): def finalizer(): if self.alerts is not None: for alert in self.alerts: alert.delete() self.alerts = None if self.data is not None: for data in self.data: data.delete() self.data = None if self.sensor is not None: self.sensor.delete() self.sensor = None if self.zone is not None: self.zone.delete() self.zone = None if self.alert_group is not None: self.alert_group.delete() self.alert_group = None if self.user is not None: self.user.delete() username = str(uuid4())[:30] self.user = User(username=username, email='{}@example.net'.format(username)) self.user.save() self.alert_group = SensorAlertGroup(name='Test Group') self.alert_group.save() self.alert_group.users.add(self.user) self.zone = Zone(name='Test Zone', notes='Zone notes.', key=uuid4()) self.zone.save() self.sensor = Sensor(guid=uuid4(), name='Test Sensor', notes='Sensor notes.', zone=self.zone, min_value=60, max_value=85, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) self.sensor.save() self.sensor.alert_groups.add(self.alert_group) self.data = [] # Inbox is empty assert 0 == len(mail.outbox) # Create in-range data point; no notification. datum = SensorData(sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + 1, state=True, state_changed=False) datum.save() self.data.append(datum) # Inbox still empty assert 0 == len(mail.outbox) # Create out-of-range notification; sends "alert." datum = SensorData(sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value - 1, state=True, state_changed=False) datum.save() self.data.append(datum) # Inbox received alert assert 1 == len(mail.outbox) # Create another in-range data point; sends "recovered." datum = SensorData(sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + 1, state=True, state_changed=False) datum.save() self.data.append(datum) # Inbox received recovery email assert 2 == len(mail.outbox) self.alerts = SensorAlert.objects.all().order_by('id') request.addfinalizer(finalizer) def _compare_sensor_alert_json(self, alert, alert_json): assert alert.id == alert_json['id'] assert alert.alert_type == alert_json['alert_type'] assert alert.alert_class == alert_json['alert_class'] assert alert.recipients == alert_json['recipients'] assert alert.message == alert_json['message'] assert alert.date.strftime( '%Y-%m-%dT%H:%M:%S.%f') == alert_json['date'][:26] m = re.match(r'.*sensors/([0-9]+)/?', alert_json['sensor']) assert m is not None assert alert.sensor.id == int(m.group(1)) m = re.match(r'.*data/([0-9]+)/?', alert_json['data_point']) assert m is not None assert alert.data_point.id == int(m.group(1)) def test_alerts_list_no_filters(self, api_root): response = requests.get(api_root + 'alerts/?format=json') data = response.json() assert len(data) > 1 for alert in self.alerts: alert_json = [x for x in data if int(x['id']) == alert.id][0] self._compare_sensor_alert_json(alert, alert_json) def test_alerts_list_get_with_limit_and_offset(self, api_root): response = requests.get(api_root + 'alerts/?limit=10&offset=0&format=json') data = response.json() assert 'count' in data assert 'next' in data assert 'previous' in data assert 'results' in data def test_alerts_list_get_with_alert_filter(self, api_root): included_alert = self.alerts[0] excluded_alert = self.alerts[1] suffix = 'alerts/?alert_ids={}&format=json'.format(included_alert.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_alert_json = [ x for x in data if int(x['id']) == excluded_alert.id ] assert len(excluded_alert_json) == 0 included_alert_json = [ x for x in data if int(x['id']) == included_alert.id ][0] self._compare_sensor_alert_json(included_alert, included_alert_json) def test_alerts_list_get_with_zone_filters(self, api_root): alert = self.alerts[0] # Ensure this alert is *not* included if its zone isn't specified. suffix = 'alerts/?zone_ids={}&format=json'.format( alert.sensor.zone.id + 1) response = requests.get(api_root + suffix) data = response.json() alerts_json = [x for x in data if int(x['id']) == alert.id] assert len(alerts_json) == 0 # Ensure this alert *is* included if its zone is specified. suffix = 'alerts/?zone_ids={}&format=json'.format(alert.sensor.zone.id) response = requests.get(api_root + suffix) data = response.json() alert_json = [x for x in data if int(x['id']) == alert.id][0] self._compare_sensor_alert_json(alert, alert_json) def test_alerts_list_get_with_sensor_filters(self, api_root): alert = self.alerts[0] # Ensure this alert is *not* included if its zone isn't specified. suffix = 'alerts/?sensor_ids={}&format=json'.format(alert.sensor.id + 1) response = requests.get(api_root + suffix) data = response.json() alerts_json = [x for x in data if int(x['id']) == alert.id] assert len(alerts_json) == 0 # Ensure this alert *is* included if its zone is specified. suffix = 'alerts/?sensor_ids={}&format=json'.format(alert.sensor.id) response = requests.get(api_root + suffix) data = response.json() alert_json = [x for x in data if int(x['id']) == alert.id][0] self._compare_sensor_alert_json(alert, alert_json) def test_alerts_list_get_with_order_by(self, api_root): response = requests.get(api_root + 'alerts/?order_by=-id&format=json') data = response.json() assert len(data) > 1 assert int(data[0]['id']) == self.alerts[1].id assert int(data[1]['id']) == self.alerts[0].id def test_alerts_list_post(self, api_root): response = requests.post(api_root + 'alerts/?format=json') assert response.status_code == 405 def test_alerts_list_patch(self, api_root): response = requests.patch(api_root + 'alerts/?format=json') assert response.status_code == 405 def test_alerts_list_delete(self, api_root): response = requests.delete(api_root + 'alerts/?format=json') assert response.status_code == 405 def test_alerts_detail_get(self, api_root): alert = self.alerts[0] suffix = 'alerts/{}/?format=json'.format(alert.id) response = requests.get(api_root + suffix) data = response.json() self._compare_sensor_alert_json(alert, data) def test_alerts_detail_post(self, api_root): alert = self.alerts[0] suffix = 'alerts/{0}/?format=json'.format(alert.id) response = requests.post(api_root + suffix) assert response.status_code == 405 def test_alerts_detail_patch(self, api_root): alert = self.alerts[0] suffix = 'alerts/{0}/?format=json'.format(alert.id) response = requests.patch(api_root + suffix) assert response.status_code == 405 def test_alerts_detail_delete(self, api_root): alert = self.alerts[0] suffix = 'alerts/{0}/?format=json'.format(alert.id) response = requests.delete(api_root + suffix) assert response.status_code == 405
class TestSensorsApi(object): zone = None sensor = None data = None @pytest.fixture(autouse=True) def api_root(self, request, live_server): api_root = '{}{}api/v1/'.format( live_server.url, '/' if not live_server.url.endswith('/') else '') return api_root @pytest.fixture(autouse=True) def create_data(self, request): def finalizer(): if self.data is not None: for data in self.data: data.delete() self.data = None if self.sensor is not None: self.sensor.delete() self.sensor = None if self.zone is not None: self.zone.delete() self.zone = None self.zone = Zone(name='Test Zone', notes='Zone notes.', key=uuid4()) self.zone.save() self.sensor = Sensor(guid=uuid4(), name='Test Sensor', notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) self.sensor.save() self.data = [] for i in range(3): datum = SensorData(sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + i, state=True, state_changed=False) datum.save() self.data.append(datum) request.addfinalizer(finalizer) def _compare_zone_json(self, zone, zone_json): assert zone.id == zone_json['id'] assert zone.name == zone_json['name'] assert zone.notes == zone_json['notes'] def _compare_sensor_json(self, sensor, sensor_json): assert sensor.id == sensor_json['id'] assert str(sensor.guid) == sensor_json['guid'] assert sensor.name == sensor_json['name'] assert sensor.notes == sensor_json['notes'] assert sensor.latest_value == sensor_json['latest_value'] assert sensor.min_value == Decimal(sensor_json['min_value']) assert sensor.max_value == Decimal(sensor_json['max_value']) assert sensor.min_value_operator == sensor_json['min_value_operator'] assert sensor.max_value_operator == sensor_json['max_value_operator'] assert sensor.state == sensor_json['state'] assert sensor.state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%f') == \ sensor_json['state_last_change_date'][:26] m = re.match(r'.*zones/([0-9]+)/?', sensor_json['zone']) assert m is not None assert sensor.zone.id == int(m.group(1)) def _compare_sensor_data_json(self, sensor_data, sensor_data_json): assert sensor_data.datetime.strftime('%Y-%m-%dT%H:%M:%S.%f') == \ sensor_data_json['datetime'][:26] assert sensor_data.value == Decimal(sensor_data_json['value']) assert sensor_data.state == sensor_data_json['state'] assert sensor_data.state_changed == sensor_data_json['state_changed'] m = re.match(r'.*sensors/([0-9]+)/?', sensor_data_json['sensor']) assert m is not None assert sensor_data.sensor.id == int(m.group(1)) def test_api_root_get(self, api_root): response = requests.get(api_root) data = response.json() assert 'data' in data assert 'sensors' in data assert 'zones' in data def test_api_root_post(self, api_root): response = requests.post(api_root) assert response.status_code == 405 def test_api_root_put(self, api_root): response = requests.put(api_root) assert response.status_code == 405 def test_api_root_patch(self, api_root): response = requests.patch(api_root) assert response.status_code == 405 def test_api_root_delete(self, api_root): response = requests.delete(api_root) assert response.status_code == 405 def test_sensors_list_get_no_filters(self, api_root): response = requests.get(api_root + 'sensors/?format=json') data = response.json() assert len(data) > 0 sensor_json = [x for x in data if x['guid'] == str(self.sensor.guid)][0] self._compare_sensor_json(self.sensor, sensor_json) def test_sensors_list_get_with_limit_and_offset(self, api_root): response = requests.get(api_root + 'sensors/?limit=10&offset=0&format=json') data = response.json() assert 'count' in data assert 'next' in data assert 'previous' in data assert 'results' in data # It's more work than it's worth to check that we can find self.sensor # in this test--there's no telling how many pages would have to be # checked, and the json is already being checked elsewhere anyway. -ajm def test_sensors_list_get_with_sensor_filter(self, api_root): excluded_sensor = Sensor(guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) excluded_sensor.save() suffix = 'sensors/?sensor_ids={}&format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_sensor_json = [ x for x in data if x['guid'] == str(excluded_sensor.guid) ] assert len(excluded_sensor_json) == 0 excluded_sensor.delete() sensor_json = [x for x in data if x['guid'] == str(self.sensor.guid)][0] self._compare_sensor_json(self.sensor, sensor_json) def test_sensors_list_get_with_zone_filter(self, api_root): excluded_zone = Zone(name='Test Zone Excluded', notes='Zone notes.', key=uuid4()) excluded_zone.save() excluded_sensor = Sensor(guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=excluded_zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) excluded_sensor.save() suffix = 'sensors/?zone_ids={}&format=json'.format(self.sensor.zone.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_sensor_json = [ x for x in data if x['guid'] == str(excluded_sensor.guid) ] assert len(excluded_sensor_json) == 0 excluded_sensor.delete() excluded_zone.delete() sensor_json = [x for x in data if x['guid'] == str(self.sensor.guid)][0] self._compare_sensor_json(self.sensor, sensor_json) def test_sensors_list_get_with_order_by(self, api_root): second_sensor = Sensor( guid=uuid4(), name=self.sensor.name + '_', # Just something to make it sort lower notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) second_sensor.save() # Sort by name, ascending response = requests.get(api_root + 'sensors/?order_by=name&format=json') data = response.json() assert len(data) > 1 first_guid = str(self.sensor.guid) second_guid = str(second_sensor.guid) matches = [ x for x in data if (x['guid'] == first_guid or x['guid'] == second_guid) ] assert matches[0]['name'] == self.sensor.name assert matches[1]['name'] == second_sensor.name # Sort by name, descending response = requests.get(api_root + 'sensors/?order_by=-name&format=json') data = response.json() assert len(data) > 1 matches = [ x for x in data if (x['guid'] == first_guid or x['guid'] == second_guid) ] assert matches[0]['name'] == second_sensor.name assert matches[1]['name'] == self.sensor.name # Default sorting (id) response = requests.get(api_root + 'sensors/?format=json') data = response.json() assert len(data) > 1 matches = [ x for x in data if (x['guid'] == first_guid or x['guid'] == second_guid) ] assert matches[0]['name'] == self.sensor.name assert matches[1]['name'] == second_sensor.name def test_sensors_list_post(self, api_root): sensor_dict = { 'guid': str(uuid4()), 'name': 'POST Sensor', 'notes': 'POST notes.', 'min_value': 20, 'max_value': 25, 'min_value_operator': '>=', 'max_value_operator': '<=', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'sensors/', data=json.dumps(sensor_dict), headers=headers) data = response.json() assert 'id' in data id = int(data['id']) assert id > 0 sensor = Sensor.objects.get(id=id) self._compare_sensor_json(sensor, data) sensor.delete() def test_sensors_list_post_with_invalid_data(self, api_root): sensor_dict = { 'guid': None, 'name': None, 'notes': 'POST notes.', 'min_value': 20, 'max_value': 25, 'min_value_operator': '>=', 'max_value_operator': '<=', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'sensors/', data=json.dumps(sensor_dict), headers=headers) # Attempt to remove the object if it's erroneously created. try: data = response.json() if 'id' in data: Sensor.objects.get(id=int(data['id'])).delete() except: pass assert response.status_code == 400 def test_sensors_list_post_without_zone_key(self, api_root): sensor_dict = { 'guid': str(uuid4()), 'name': 'POST Sensor', 'notes': 'POST notes.', 'min_value': 20, 'max_value': 25, 'min_value_operator': '>=', 'max_value_operator': '<=' } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'sensors/', data=json.dumps(sensor_dict), headers=headers) # Attempt to remove the object if it's erroneously created. try: data = response.json() if 'id' in data: Sensor.objects.get(id=int(data['id'])).delete() except: pass assert response.status_code == 403 def test_sensors_list_put(self, api_root): response = requests.put(api_root + 'sensors/') assert response.status_code == 405 def test_sensors_list_patch(self, api_root): response = requests.patch(api_root + 'sensors/') assert response.status_code == 405 def test_sensors_list_delete(self, api_root): response = requests.delete(api_root + 'sensors/') assert response.status_code == 405 def test_sensors_detail_get(self, api_root): suffix = 'sensors/{}/?format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() self._compare_sensor_json(self.sensor, data) def test_sensors_detail_post(self, api_root): suffix = 'sensors/{}/?format=json'.format(self.sensor.id) response = requests.post(api_root + suffix) assert response.status_code == 405 def test_sensors_detail_put(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': str(uuid4()), 'name': 'PUT Sensor', 'notes': 'PUT notes.', 'zone': api_root + 'zones/{}/'.format(self.zone.id), 'min_value': 200, 'max_value': 250, 'min_value_operator': '<=', 'max_value_operator': '>=', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.put(api_root + suffix, data=json.dumps(sensor_dict), headers=headers) assert response.status_code == 200 data = response.json() assert data['guid'] == sensor_dict['guid'] assert data['name'] == sensor_dict['name'] assert data['notes'] == sensor_dict['notes'] assert data['zone'] == sensor_dict['zone'] assert Decimal(data['min_value']) == Decimal(sensor_dict['min_value']) assert Decimal(data['max_value']) == Decimal(sensor_dict['max_value']) assert data['min_value_operator'] == sensor_dict['min_value_operator'] assert data['max_value_operator'] == sensor_dict['max_value_operator'] def test_sensors_detail_put_without_zone_key(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': str(uuid4()), 'name': 'PUT Sensor', 'notes': 'PUT notes.', 'zone': api_root + 'zones/{}/'.format(self.zone.id), 'min_value': 200, 'max_value': 250, 'min_value_operator': '<=', 'max_value_operator': '>=' } headers = {'Content-type': 'application/json'} response = requests.put(api_root + suffix, data=json.dumps(sensor_dict), headers=headers) assert response.status_code == 403 def test_sensors_detail_put_with_invalid_data(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': None, 'name': None, 'notes': 'PUT notes.', 'zone': api_root + 'zones/{}/'.format(self.zone.id), 'min_value': 200, 'max_value': 250, 'min_value_operator': '<=', 'max_value_operator': '>=', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.put(api_root + suffix, data=json.dumps(sensor_dict), headers=headers) assert response.status_code == 400 def test_sensors_detail_patch(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': str(self.sensor.guid), 'name': 'PATCH Sensor', 'notes': 'PATCH notes.', 'min_value': self.sensor.min_value, 'max_value': self.sensor.max_value, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.patch(api_root + suffix, data=json.dumps(sensor_dict), headers=headers) print(response.text) assert response.status_code == 200 data = response.json() assert data['guid'] == sensor_dict['guid'] assert data['name'] == sensor_dict['name'] assert data['notes'] == sensor_dict['notes'] assert Decimal(data['min_value']) == Decimal(sensor_dict['min_value']) assert Decimal(data['max_value']) == Decimal(sensor_dict['max_value']) def test_sensors_detail_patch_without_zone_key(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': str(self.sensor.guid), 'name': 'PATCH Sensor', 'notes': 'PATCH notes.', 'min_value': self.sensor.min_value, 'max_value': self.sensor.max_value } headers = {'Content-type': 'application/json'} response = requests.patch(api_root + suffix, data=json.dumps(sensor_dict), headers=headers) assert response.status_code == 403 def test_sensors_detail_patch_with_invalid_data(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': None, 'name': None, 'notes': 'PATCH notes.', 'min_value': None, 'max_value': None, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.patch(api_root + suffix, data=json.dumps(sensor_dict), headers=headers) print(response.text) assert response.status_code == 400 def test_sensors_detail_delete(self, api_root): data = {'key': str(self.zone.key)} headers = {'Content-type': 'application/json'} suffix = 'sensors/{}/'.format(self.sensor.id) response = requests.delete(api_root + suffix, data=json.dumps(data), headers=headers) assert response.status_code == 204 def test_sensors_detail_delete_without_zone_key(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) response = requests.delete(api_root + suffix) assert response.status_code == 403 def test_sensor_data_list_get_no_filters(self, api_root): response = requests.get(api_root + 'data/?format=json') data = response.json() assert len(data) > 2 for i in range(3): data_json = [x for x in data if int(x['id']) == self.data[i].id][0] self._compare_sensor_data_json(self.data[i], data_json) def test_sensor_data_list_get_with_limit_and_offset(self, api_root): response = requests.get(api_root + 'data/?limit=10&offset=0&format=json') data = response.json() assert 'count' in data assert 'next' in data assert 'previous' in data assert 'results' in data def test_sensor_data_list_get_with_sensor_filter(self, api_root): excluded_sensor = Sensor(guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) excluded_sensor.save() excluded_data = SensorData(sensor=excluded_sensor, datetime=datetime.utcnow(), value=22, state=True, state_changed=False) excluded_data.save() suffix = 'data/?sensor_ids={}&format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_data_json = [ x for x in data if x['id'] == str(excluded_data.id) ] assert len(excluded_data_json) == 0 excluded_data.delete() excluded_sensor.delete() for i in range(3): data_json = [x for x in data if int(x['id']) == self.data[i].id][0] self._compare_sensor_data_json(self.data[i], data_json) def test_sensor_data_list_get_with_zone_filter(self, api_root): excluded_zone = Zone(name='Test Zone Excluded', notes='Zone notes.', key=uuid4()) excluded_zone.save() excluded_sensor = Sensor(guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=excluded_zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) excluded_sensor.save() excluded_data = SensorData(sensor=excluded_sensor, datetime=datetime.utcnow(), value=22, state=True, state_changed=False) excluded_data.save() suffix = 'data/?zone_ids={}&format=json'.format(self.zone.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_data_json = [ x for x in data if x['id'] == str(excluded_data.id) ] assert len(excluded_data_json) == 0 excluded_data.delete() excluded_sensor.delete() excluded_zone.delete() for i in range(3): data_json = [x for x in data if int(x['id']) == self.data[i].id][0] self._compare_sensor_data_json(self.data[i], data_json) def test_sensor_data_list_get_with_date_filters(self, api_root): suffix = 'data/?start_date={}&end_date={}&format=json'.format( self.data[0].datetime.strftime('%Y-%m-%dT%H:%M:%S.%fZ'), self.data[0].datetime.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_data_json = [ x for x in data if x['id'] == str(self.data[1].id) ] assert len(excluded_data_json) == 0 data_json = [x for x in data if int(x['id']) == self.data[0].id][0] self._compare_sensor_data_json(self.data[0], data_json) def test_sensor_data_list_get_with_value_filters(self, api_root): suffix = 'data/?min_value={}&max_value={}&format=json'.format( self.data[0].value, self.data[0].value) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_data_json = [ x for x in data if x['id'] == str(self.data[1].id) ] assert len(excluded_data_json) == 0 data_json = [x for x in data if int(x['id']) == self.data[0].id][0] self._compare_sensor_data_json(self.data[0], data_json) def test_sensor_data_list_get_csv(self, api_root): suffix = 'data/?zone_ids={}&format=csv'.format(self.zone.id) response = requests.get(api_root + suffix) reader = csv.reader(StringIO(response.text)) num_lines = 0 for line in reader: num_lines = num_lines + 1 # All lines should contain 4 fields # datetime,sensor_name,state,value assert len(line) == 4 # Should expect 3 lines of data and 1 header line == 4 assert num_lines == 4 def test_sensor_data_list_post(self, api_root): data_dict = { 'sensor': api_root + 'sensors/{}/'.format(self.sensor.id), 'datetime': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'value': 22.5, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'data/', data=json.dumps(data_dict), headers=headers) data = response.json() assert 'id' in data id = int(data['id']) assert id > 0 sensor_data = SensorData.objects.get(id=id) self._compare_sensor_data_json(sensor_data, data) sensor_data.delete() def test_sensor_data_list_post_without_zone_key(self, api_root): data_dict = { 'sensor': api_root + 'sensors/{}/'.format(self.sensor.id), 'datetime': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'value': 22.5 } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'data/', data=json.dumps(data_dict), headers=headers) assert response.status_code == 403 def test_sensor_data_list_post_in_range_maintains_state(self, api_root): prev_state_last_change_date = self.sensor.state_last_change_date data_dict = { 'sensor': api_root + 'sensors/{}/'.format(self.sensor.id), 'datetime': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'value': 22.5, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'data/', data=json.dumps(data_dict), headers=headers) data = response.json() assert 'id' in data id = int(data['id']) assert id > 0 sensor_data = SensorData.objects.get(id=id) self._compare_sensor_data_json(sensor_data, data) sensor = Sensor.objects.get(pk=self.sensor.id) assert sensor.state is True assert sensor.state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%fZ') == \ prev_state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%fZ') sensor_data.delete() def test_sensor_data_list_post_outside_range_updates_state(self, api_root): prev_state_last_change_date = self.sensor.state_last_change_date data_dict = { 'sensor': api_root + 'sensors/{}/'.format(self.sensor.id), 'datetime': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'value': self.sensor.max_value + 1, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'data/', data=json.dumps(data_dict), headers=headers) data = response.json() assert 'id' in data id = int(data['id']) assert id > 0 sensor_data = SensorData.objects.get(id=id) self._compare_sensor_data_json(sensor_data, data) sensor = Sensor.objects.get(pk=self.sensor.id) assert not sensor.state assert sensor.state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%fZ') != \ prev_state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%fZ') sensor_data.delete() def test_sensor_data_list_put(self, api_root): response = requests.put(api_root + 'data/') assert response.status_code == 405 def test_sensor_data_list_patch(self, api_root): response = requests.patch(api_root + 'data/') assert response.status_code == 405 def test_sensor_data_list_delete(self, api_root): response = requests.delete(api_root + 'data/') assert response.status_code == 405 def test_sensor_data_detail_get(self, api_root): suffix = 'data/{}/?format=json'.format(self.data[0].id) response = requests.get(api_root + suffix) data = response.json() self._compare_sensor_data_json(self.data[0], data) def test_sensor_data_detail_post(self, api_root): response = requests.post(api_root + 'data/{}/'.format(self.data[0].id)) assert response.status_code == 405 def test_sensor_data_detail_post_guid(self, api_root): """ Test adding sensor data with only supplying a Sensor guid, sensor data value and a zone key. If the sensor doesn't exist, this will create it. """ zone = Zone(name='Test Zone', key=uuid4()) zone.save() guid = 'DEADBEEF00000012345TEST' value_first = 15.0 value_second = 25.0 num_sensors_before_add = Sensor.objects.all().count() data_dict = { 'guid': guid, 'value': value_first, 'key': str(zone.key), } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'data/', data=json.dumps(data_dict), headers=headers) response_json_first = response.json() num_sensors_after_add = Sensor.objects.all().count() assert response.status_code == 201 assert num_sensors_before_add + 1 == num_sensors_after_add data = SensorData.objects.get(pk=response_json_first["id"]) data.delete() data_dict = { 'guid': guid, 'value': value_second, 'key': str(zone.key), } headers = {'Content-type': 'application/json'} response = requests.post(api_root + 'data/', data=json.dumps(data_dict), headers=headers) response_json_second = response.json() num_sensors_after_second_request = Sensor.objects.all().count() # Ensure we didn't add another sensor assert response.status_code == 201 assert num_sensors_after_add == num_sensors_after_second_request assert response_json_first["sensor"] == response_json_second["sensor"] data = SensorData.objects.get(pk=response_json_second["id"]) sensor = Sensor.objects.get(pk=data.sensor.id) data.delete() sensor.delete() def test_sensor_data_detail_put(self, api_root): response = requests.put(api_root + 'data/{}/'.format(self.data[0].id)) assert response.status_code == 405 def test_sensor_data_detail_patch(self, api_root): response = requests.patch(api_root + 'data/{}/'.format(self.data[0].id)) assert response.status_code == 405 def test_sensor_data_detail_delete(self, api_root): response = requests.delete(api_root + 'data/{}/'.format(self.data[0].id)) assert response.status_code == 405 def test_zone_list_get_no_filters(self, api_root): response = requests.get(api_root + 'zones/?format=json') data = response.json() assert len(data) > 0 zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json) def test_zone_list_get_with_limit_and_offset(self, api_root): response = requests.get(api_root + 'zones/?limit=10&offset=0&format=json') data = response.json() assert 'count' in data assert 'next' in data assert 'previous' in data assert 'results' in data def test_zone_list_get_with_sensor_filter(self, api_root): excluded_zone = Zone(name='Test Zone Excluded', notes='Zone notes.', key=uuid4()) excluded_zone.save() excluded_sensor = Sensor(guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=excluded_zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow()) excluded_sensor.save() suffix = 'zones/?sensor_ids={}&format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_zone_json = [ x for x in data if x['id'] == str(excluded_zone.id) ] assert len(excluded_zone_json) == 0 excluded_sensor.delete() excluded_zone.delete() zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json) def test_zone_list_get_with_zone_filter(self, api_root): excluded_zone = Zone(name='Test Zone Excluded', notes='Zone notes.', key=uuid4()) excluded_zone.save() suffix = 'zones/?zone_ids={}&format=json'.format(self.zone.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_zone_json = [ x for x in data if x['id'] == str(excluded_zone.id) ] assert len(excluded_zone_json) == 0 excluded_zone.delete() zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json) def test_zone_list_post(self, api_root): response = requests.put(api_root + 'zones/') assert response.status_code == 405 def test_zone_list_put(self, api_root): response = requests.put(api_root + 'zones/') assert response.status_code == 405 def test_zone_list_patch(self, api_root): response = requests.patch(api_root + 'zones/') assert response.status_code == 405 def test_zone_list_delete(self, api_root): response = requests.delete(api_root + 'zones/') assert response.status_code == 405 def test_zone_detail_get(self, api_root): response = requests.get(api_root + 'zones/{}/'.format(self.zone.id)) data = response.json() self._compare_zone_json(self.zone, data) def test_zone_detail_post(self, api_root): response = requests.post(api_root + 'zones/{}/'.format(self.zone.id)) assert response.status_code == 405 def test_zone_detail_put(self, api_root): zone_dict = { 'name': 'PUT Zone', 'notes': 'PUT notes.', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.put(api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers) assert response.status_code == 200 data = response.json() assert data['name'] == zone_dict['name'] assert data['notes'] == zone_dict['notes'] def test_zone_detail_put_without_zone_key(self, api_root): zone_dict = {'name': 'PUT Zone', 'notes': 'PUT notes.'} headers = {'Content-type': 'application/json'} response = requests.put(api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers) assert response.status_code == 403 def test_zone_detail_put_with_invalid_data(self, api_root): zone_dict = { 'name': None, 'notes': 'PUT notes.', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.put(api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers) assert response.status_code == 400 def test_zone_detail_patch(self, api_root): zone_dict = { 'name': 'PATCH Zone', 'notes': 'PATCH notes.', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.patch(api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers) assert response.status_code == 200 data = response.json() assert data['name'] == zone_dict['name'] assert data['notes'] == zone_dict['notes'] def test_zone_detail_patch_without_zone_key(self, api_root): zone_dict = {'name': 'PATCH Zone', 'notes': 'PATCH notes.'} headers = {'Content-type': 'application/json'} response = requests.patch(api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers) assert response.status_code == 403 def test_zone_detail_patch_with_invalid_data(self, api_root): zone_dict = { 'name': None, 'notes': 'PATCH notes.', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.patch(api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers) assert response.status_code == 400 def test_zone_detail_delete(self, api_root): response = requests.delete(api_root + 'zones/{}/'.format(self.zone.id)) assert response.status_code == 405
class TestSensorsApi(object): zone = None sensor = None data = None @pytest.fixture(autouse=True) def api_root(self, request, live_server): api_root = '{}{}api/v1/'.format( live_server.url, '/' if not live_server.url.endswith('/') else '') return api_root @pytest.fixture(autouse=True) def create_data(self, request): def finalizer(): if self.data is not None: for data in self.data: data.delete() self.data = None if self.sensor is not None: self.sensor.delete() self.sensor = None if self.zone is not None: self.zone.delete() self.zone = None self.zone = Zone( name='Test Zone', notes='Zone notes.', key=uuid4() ) self.zone.save() self.sensor = Sensor( guid=uuid4(), name='Test Sensor', notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) self.sensor.save() self.data = [] for i in range(3): datum = SensorData( sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + i, state=True, state_changed=False ) datum.save() self.data.append(datum) request.addfinalizer(finalizer) def _compare_zone_json(self, zone, zone_json): assert zone.id == zone_json['id'] assert zone.name == zone_json['name'] assert zone.notes == zone_json['notes'] def _compare_sensor_json(self, sensor, sensor_json): assert sensor.id == sensor_json['id'] assert str(sensor.guid) == sensor_json['guid'] assert sensor.name == sensor_json['name'] assert sensor.notes == sensor_json['notes'] assert sensor.latest_value == sensor_json['latest_value'] assert sensor.min_value == Decimal(sensor_json['min_value']) assert sensor.max_value == Decimal(sensor_json['max_value']) assert sensor.min_value_operator == sensor_json['min_value_operator'] assert sensor.max_value_operator == sensor_json['max_value_operator'] assert sensor.state == sensor_json['state'] assert sensor.state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%f') == \ sensor_json['state_last_change_date'][:26] m = re.match(r'.*zones/([0-9]+)/?', sensor_json['zone']) assert m is not None assert sensor.zone.id == int(m.group(1)) def _compare_sensor_data_json(self, sensor_data, sensor_data_json): assert sensor_data.datetime.strftime('%Y-%m-%dT%H:%M:%S.%f') == \ sensor_data_json['datetime'][:26] assert sensor_data.value == Decimal(sensor_data_json['value']) assert sensor_data.state == sensor_data_json['state'] assert sensor_data.state_changed == sensor_data_json['state_changed'] m = re.match(r'.*sensors/([0-9]+)/?', sensor_data_json['sensor']) assert m is not None assert sensor_data.sensor.id == int(m.group(1)) def test_api_root_get(self, api_root): response = requests.get(api_root) data = response.json() assert 'data' in data assert 'sensors' in data assert 'zones' in data def test_api_root_post(self, api_root): response = requests.post(api_root) assert response.status_code == 405 def test_api_root_put(self, api_root): response = requests.put(api_root) assert response.status_code == 405 def test_api_root_patch(self, api_root): response = requests.patch(api_root) assert response.status_code == 405 def test_api_root_delete(self, api_root): response = requests.delete(api_root) assert response.status_code == 405 def test_sensors_list_get_no_filters(self, api_root): response = requests.get(api_root + 'sensors/?format=json') data = response.json() assert len(data) > 0 sensor_json = [x for x in data if x['guid'] == str(self.sensor.guid)][0] self._compare_sensor_json(self.sensor, sensor_json) def test_sensors_list_get_with_limit_and_offset(self, api_root): response = requests.get(api_root + 'sensors/?limit=10&offset=0&format=json') data = response.json() assert 'count' in data assert 'next' in data assert 'previous' in data assert 'results' in data # It's more work than it's worth to check that we can find self.sensor # in this test--there's no telling how many pages would have to be # checked, and the json is already being checked elsewhere anyway. -ajm def test_sensors_list_get_with_sensor_filter(self, api_root): excluded_sensor = Sensor( guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) excluded_sensor.save() suffix = 'sensors/?sensor_ids={}&format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_sensor_json = [x for x in data if x['guid'] == str(excluded_sensor.guid)] assert len(excluded_sensor_json) == 0 excluded_sensor.delete() sensor_json = [x for x in data if x['guid'] == str(self.sensor.guid)][0] self._compare_sensor_json(self.sensor, sensor_json) def test_sensors_list_get_with_zone_filter(self, api_root): excluded_zone = Zone( name='Test Zone Excluded', notes='Zone notes.', key=uuid4() ) excluded_zone.save() excluded_sensor = Sensor( guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=excluded_zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) excluded_sensor.save() suffix = 'sensors/?zone_ids={}&format=json'.format(self.sensor.zone.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_sensor_json = [x for x in data if x['guid'] == str(excluded_sensor.guid)] assert len(excluded_sensor_json) == 0 excluded_sensor.delete() excluded_zone.delete() sensor_json = [x for x in data if x['guid'] == str(self.sensor.guid)][0] self._compare_sensor_json(self.sensor, sensor_json) def test_sensors_list_get_with_order_by(self, api_root): second_sensor = Sensor( guid=uuid4(), name=self.sensor.name + '_', # Just something to make it sort lower notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) second_sensor.save() # Sort by name, ascending response = requests.get(api_root + 'sensors/?order_by=name&format=json') data = response.json() assert len(data) > 1 first_guid = str(self.sensor.guid) second_guid = str(second_sensor.guid) matches = [x for x in data if ( x['guid'] == first_guid or x['guid'] == second_guid)] assert matches[0]['name'] == self.sensor.name assert matches[1]['name'] == second_sensor.name # Sort by name, descending response = requests.get(api_root + 'sensors/?order_by=-name&format=json') data = response.json() assert len(data) > 1 matches = [x for x in data if ( x['guid'] == first_guid or x['guid'] == second_guid)] assert matches[0]['name'] == second_sensor.name assert matches[1]['name'] == self.sensor.name # Default sorting (id) response = requests.get(api_root + 'sensors/?format=json') data = response.json() assert len(data) > 1 matches = [x for x in data if ( x['guid'] == first_guid or x['guid'] == second_guid)] assert matches[0]['name'] == self.sensor.name assert matches[1]['name'] == second_sensor.name def test_sensors_list_post(self, api_root): sensor_dict = { 'guid': str(uuid4()), 'name': 'POST Sensor', 'notes': 'POST notes.', 'min_value': 20, 'max_value': 25, 'min_value_operator': '>=', 'max_value_operator': '<=', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'sensors/', data=json.dumps(sensor_dict), headers=headers ) data = response.json() assert 'id' in data id = int(data['id']) assert id > 0 sensor = Sensor.objects.get(id=id) self._compare_sensor_json(sensor, data) sensor.delete() def test_sensors_list_post_with_invalid_data(self, api_root): sensor_dict = { 'guid': None, 'name': None, 'notes': 'POST notes.', 'min_value': 20, 'max_value': 25, 'min_value_operator': '>=', 'max_value_operator': '<=', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'sensors/', data=json.dumps(sensor_dict), headers=headers ) # Attempt to remove the object if it's erroneously created. try: data = response.json() if 'id' in data: Sensor.objects.get(id=int(data['id'])).delete() except: pass assert response.status_code == 400 def test_sensors_list_post_without_zone_key(self, api_root): sensor_dict = { 'guid': str(uuid4()), 'name': 'POST Sensor', 'notes': 'POST notes.', 'min_value': 20, 'max_value': 25, 'min_value_operator': '>=', 'max_value_operator': '<=' } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'sensors/', data=json.dumps(sensor_dict), headers=headers ) # Attempt to remove the object if it's erroneously created. try: data = response.json() if 'id' in data: Sensor.objects.get(id=int(data['id'])).delete() except: pass assert response.status_code == 403 def test_sensors_list_put(self, api_root): response = requests.put(api_root + 'sensors/') assert response.status_code == 405 def test_sensors_list_patch(self, api_root): response = requests.patch(api_root + 'sensors/') assert response.status_code == 405 def test_sensors_list_delete(self, api_root): response = requests.delete(api_root + 'sensors/') assert response.status_code == 405 def test_sensors_detail_get(self, api_root): suffix = 'sensors/{}/?format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() self._compare_sensor_json(self.sensor, data) def test_sensors_detail_post(self, api_root): suffix = 'sensors/{}/?format=json'.format(self.sensor.id) response = requests.post(api_root + suffix) assert response.status_code == 405 def test_sensors_detail_put(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': str(uuid4()), 'name': 'PUT Sensor', 'notes': 'PUT notes.', 'zone': api_root + 'zones/{}/'.format(self.zone.id), 'min_value': 200, 'max_value': 250, 'min_value_operator': '<=', 'max_value_operator': '>=', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.put( api_root + suffix, data=json.dumps(sensor_dict), headers=headers ) assert response.status_code == 200 data = response.json() assert data['guid'] == sensor_dict['guid'] assert data['name'] == sensor_dict['name'] assert data['notes'] == sensor_dict['notes'] assert data['zone'] == sensor_dict['zone'] assert Decimal(data['min_value']) == Decimal(sensor_dict['min_value']) assert Decimal(data['max_value']) == Decimal(sensor_dict['max_value']) assert data['min_value_operator'] == sensor_dict['min_value_operator'] assert data['max_value_operator'] == sensor_dict['max_value_operator'] def test_sensors_detail_put_without_zone_key(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': str(uuid4()), 'name': 'PUT Sensor', 'notes': 'PUT notes.', 'zone': api_root + 'zones/{}/'.format(self.zone.id), 'min_value': 200, 'max_value': 250, 'min_value_operator': '<=', 'max_value_operator': '>=' } headers = {'Content-type': 'application/json'} response = requests.put( api_root + suffix, data=json.dumps(sensor_dict), headers=headers ) assert response.status_code == 403 def test_sensors_detail_put_with_invalid_data(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': None, 'name': None, 'notes': 'PUT notes.', 'zone': api_root + 'zones/{}/'.format(self.zone.id), 'min_value': 200, 'max_value': 250, 'min_value_operator': '<=', 'max_value_operator': '>=', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.put( api_root + suffix, data=json.dumps(sensor_dict), headers=headers ) assert response.status_code == 400 def test_sensors_detail_patch(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': str(self.sensor.guid), 'name': 'PATCH Sensor', 'notes': 'PATCH notes.', 'min_value': self.sensor.min_value, 'max_value': self.sensor.max_value, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.patch( api_root + suffix, data=json.dumps(sensor_dict), headers=headers ) print(response.text) assert response.status_code == 200 data = response.json() assert data['guid'] == sensor_dict['guid'] assert data['name'] == sensor_dict['name'] assert data['notes'] == sensor_dict['notes'] assert Decimal(data['min_value']) == Decimal(sensor_dict['min_value']) assert Decimal(data['max_value']) == Decimal(sensor_dict['max_value']) def test_sensors_detail_patch_without_zone_key(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': str(self.sensor.guid), 'name': 'PATCH Sensor', 'notes': 'PATCH notes.', 'min_value': self.sensor.min_value, 'max_value': self.sensor.max_value } headers = {'Content-type': 'application/json'} response = requests.patch( api_root + suffix, data=json.dumps(sensor_dict), headers=headers ) assert response.status_code == 403 def test_sensors_detail_patch_with_invalid_data(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) sensor_dict = { 'guid': None, 'name': None, 'notes': 'PATCH notes.', 'min_value': None, 'max_value': None, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.patch( api_root + suffix, data=json.dumps(sensor_dict), headers=headers ) print(response.text) assert response.status_code == 400 def test_sensors_detail_delete(self, api_root): data = {'key': str(self.zone.key)} headers = {'Content-type': 'application/json'} suffix = 'sensors/{}/'.format(self.sensor.id) response = requests.delete( api_root + suffix, data=json.dumps(data), headers=headers ) assert response.status_code == 204 def test_sensors_detail_delete_without_zone_key(self, api_root): suffix = 'sensors/{}/'.format(self.sensor.id) response = requests.delete(api_root + suffix) assert response.status_code == 403 def test_sensor_data_list_get_no_filters(self, api_root): response = requests.get(api_root + 'data/?format=json') data = response.json() assert len(data) > 2 for i in range(3): data_json = [x for x in data if int(x['id']) == self.data[i].id][0] self._compare_sensor_data_json(self.data[i], data_json) def test_sensor_data_list_get_with_limit_and_offset(self, api_root): response = requests.get(api_root + 'data/?limit=10&offset=0&format=json') data = response.json() assert 'count' in data assert 'next' in data assert 'previous' in data assert 'results' in data def test_sensor_data_list_get_with_sensor_filter(self, api_root): excluded_sensor = Sensor( guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=self.zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) excluded_sensor.save() excluded_data = SensorData( sensor=excluded_sensor, datetime=datetime.utcnow(), value=22, state=True, state_changed=False ) excluded_data.save() suffix = 'data/?sensor_ids={}&format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_data_json = [x for x in data if x['id'] == str(excluded_data.id)] assert len(excluded_data_json) == 0 excluded_data.delete() excluded_sensor.delete() for i in range(3): data_json = [x for x in data if int(x['id']) == self.data[i].id][0] self._compare_sensor_data_json(self.data[i], data_json) def test_sensor_data_list_get_with_zone_filter(self, api_root): excluded_zone = Zone( name='Test Zone Excluded', notes='Zone notes.', key=uuid4() ) excluded_zone.save() excluded_sensor = Sensor( guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=excluded_zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) excluded_sensor.save() excluded_data = SensorData( sensor=excluded_sensor, datetime=datetime.utcnow(), value=22, state=True, state_changed=False ) excluded_data.save() suffix = 'data/?zone_ids={}&format=json'.format(self.zone.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_data_json = [x for x in data if x['id'] == str(excluded_data.id)] assert len(excluded_data_json) == 0 excluded_data.delete() excluded_sensor.delete() excluded_zone.delete() for i in range(3): data_json = [x for x in data if int(x['id']) == self.data[i].id][0] self._compare_sensor_data_json(self.data[i], data_json) def test_sensor_data_list_get_with_date_filters(self, api_root): suffix = 'data/?start_date={}&end_date={}&format=json'.format( self.data[0].datetime.strftime('%Y-%m-%dT%H:%M:%S.%fZ'), self.data[0].datetime.strftime('%Y-%m-%dT%H:%M:%S.%fZ')) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_data_json = [x for x in data if x['id'] == str(self.data[1].id)] assert len(excluded_data_json) == 0 data_json = [x for x in data if int(x['id']) == self.data[0].id][0] self._compare_sensor_data_json(self.data[0], data_json) def test_sensor_data_list_get_with_value_filters(self, api_root): suffix = 'data/?min_value={}&max_value={}&format=json'.format( self.data[0].value, self.data[0].value) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_data_json = [x for x in data if x['id'] == str(self.data[1].id)] assert len(excluded_data_json) == 0 data_json = [x for x in data if int(x['id']) == self.data[0].id][0] self._compare_sensor_data_json(self.data[0], data_json) def test_sensor_data_list_get_csv(self, api_root): suffix = 'data/?zone_ids={}&format=csv'.format( self.zone.id ) response = requests.get(api_root + suffix) reader = csv.reader(StringIO(response.text)) num_lines = 0 for line in reader: num_lines = num_lines + 1 # All lines should contain 4 fields # datetime,sensor_name,state,value assert len(line) == 4 # Should expect 3 lines of data and 1 header line == 4 assert num_lines == 4 def test_sensor_data_list_post(self, api_root): data_dict = { 'sensor': api_root + 'sensors/{}/'.format(self.sensor.id), 'datetime': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'value': 22.5, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'data/', data=json.dumps(data_dict), headers=headers ) data = response.json() assert 'id' in data id = int(data['id']) assert id > 0 sensor_data = SensorData.objects.get(id=id) self._compare_sensor_data_json(sensor_data, data) sensor_data.delete() def test_sensor_data_list_post_without_zone_key(self, api_root): data_dict = { 'sensor': api_root + 'sensors/{}/'.format(self.sensor.id), 'datetime': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'value': 22.5 } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'data/', data=json.dumps(data_dict), headers=headers ) assert response.status_code == 403 def test_sensor_data_list_post_in_range_maintains_state(self, api_root): prev_state_last_change_date = self.sensor.state_last_change_date data_dict = { 'sensor': api_root + 'sensors/{}/'.format(self.sensor.id), 'datetime': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'value': 22.5, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'data/', data=json.dumps(data_dict), headers=headers ) data = response.json() assert 'id' in data id = int(data['id']) assert id > 0 sensor_data = SensorData.objects.get(id=id) self._compare_sensor_data_json(sensor_data, data) sensor = Sensor.objects.get(pk=self.sensor.id) assert sensor.state is True assert sensor.state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%fZ') == \ prev_state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%fZ') sensor_data.delete() def test_sensor_data_list_post_outside_range_updates_state(self, api_root): prev_state_last_change_date = self.sensor.state_last_change_date data_dict = { 'sensor': api_root + 'sensors/{}/'.format(self.sensor.id), 'datetime': datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'value': self.sensor.max_value + 1, 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'data/', data=json.dumps(data_dict), headers=headers ) data = response.json() assert 'id' in data id = int(data['id']) assert id > 0 sensor_data = SensorData.objects.get(id=id) self._compare_sensor_data_json(sensor_data, data) sensor = Sensor.objects.get(pk=self.sensor.id) assert not sensor.state assert sensor.state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%fZ') != \ prev_state_last_change_date.strftime('%Y-%m-%dT%H:%M:%S.%fZ') sensor_data.delete() def test_sensor_data_list_put(self, api_root): response = requests.put(api_root + 'data/') assert response.status_code == 405 def test_sensor_data_list_patch(self, api_root): response = requests.patch(api_root + 'data/') assert response.status_code == 405 def test_sensor_data_list_delete(self, api_root): response = requests.delete(api_root + 'data/') assert response.status_code == 405 def test_sensor_data_detail_get(self, api_root): suffix = 'data/{}/?format=json'.format(self.data[0].id) response = requests.get(api_root + suffix) data = response.json() self._compare_sensor_data_json(self.data[0], data) def test_sensor_data_detail_post(self, api_root): response = requests.post(api_root + 'data/{}/'.format(self.data[0].id)) assert response.status_code == 405 def test_sensor_data_detail_post_guid(self, api_root): """ Test adding sensor data with only supplying a Sensor guid, sensor data value and a zone key. If the sensor doesn't exist, this will create it. """ zone = Zone(name='Test Zone', key=uuid4()) zone.save() guid = 'DEADBEEF00000012345TEST' value_first = 15.0 value_second = 25.0 num_sensors_before_add = Sensor.objects.all().count() data_dict = { 'guid': guid, 'value': value_first, 'key': str(zone.key), } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'data/', data=json.dumps(data_dict), headers=headers ) response_json_first = response.json() num_sensors_after_add = Sensor.objects.all().count() assert response.status_code == 201 assert num_sensors_before_add + 1 == num_sensors_after_add data = SensorData.objects.get(pk=response_json_first["id"]) data.delete() data_dict = { 'guid': guid, 'value': value_second, 'key': str(zone.key), } headers = {'Content-type': 'application/json'} response = requests.post( api_root + 'data/', data=json.dumps(data_dict), headers=headers ) response_json_second = response.json() num_sensors_after_second_request = Sensor.objects.all().count() # Ensure we didn't add another sensor assert response.status_code == 201 assert num_sensors_after_add == num_sensors_after_second_request assert response_json_first["sensor"] == response_json_second["sensor"] data = SensorData.objects.get(pk=response_json_second["id"]) sensor = Sensor.objects.get(pk=data.sensor.id) data.delete() sensor.delete() def test_sensor_data_detail_put(self, api_root): response = requests.put(api_root + 'data/{}/'.format(self.data[0].id)) assert response.status_code == 405 def test_sensor_data_detail_patch(self, api_root): response = requests.patch(api_root + 'data/{}/'.format(self.data[0].id)) assert response.status_code == 405 def test_sensor_data_detail_delete(self, api_root): response = requests.delete(api_root + 'data/{}/'.format(self.data[0].id)) assert response.status_code == 405 def test_zone_list_get_no_filters(self, api_root): response = requests.get(api_root + 'zones/?format=json') data = response.json() assert len(data) > 0 zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json) def test_zone_list_get_with_limit_and_offset(self, api_root): response = requests.get(api_root + 'zones/?limit=10&offset=0&format=json') data = response.json() assert 'count' in data assert 'next' in data assert 'previous' in data assert 'results' in data def test_zone_list_get_with_sensor_filter(self, api_root): excluded_zone = Zone( name='Test Zone Excluded', notes='Zone notes.', key=uuid4() ) excluded_zone.save() excluded_sensor = Sensor( guid=uuid4(), name='Test Sensor Excluded', notes='Sensor notes.', zone=excluded_zone, min_value=20, max_value=25, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) excluded_sensor.save() suffix = 'zones/?sensor_ids={}&format=json'.format(self.sensor.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_zone_json = [x for x in data if x['id'] == str(excluded_zone.id)] assert len(excluded_zone_json) == 0 excluded_sensor.delete() excluded_zone.delete() zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json) def test_zone_list_get_with_zone_filter(self, api_root): excluded_zone = Zone( name='Test Zone Excluded', notes='Zone notes.', key=uuid4() ) excluded_zone.save() suffix = 'zones/?zone_ids={}&format=json'.format(self.zone.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_zone_json = [x for x in data if x['id'] == str(excluded_zone.id)] assert len(excluded_zone_json) == 0 excluded_zone.delete() zone_json = [x for x in data if int(x['id']) == self.zone.id][0] self._compare_zone_json(self.zone, zone_json) def test_zone_list_post(self, api_root): response = requests.put(api_root + 'zones/') assert response.status_code == 405 def test_zone_list_put(self, api_root): response = requests.put(api_root + 'zones/') assert response.status_code == 405 def test_zone_list_patch(self, api_root): response = requests.patch(api_root + 'zones/') assert response.status_code == 405 def test_zone_list_delete(self, api_root): response = requests.delete(api_root + 'zones/') assert response.status_code == 405 def test_zone_detail_get(self, api_root): response = requests.get(api_root + 'zones/{}/'.format(self.zone.id)) data = response.json() self._compare_zone_json(self.zone, data) def test_zone_detail_post(self, api_root): response = requests.post(api_root + 'zones/{}/'.format(self.zone.id)) assert response.status_code == 405 def test_zone_detail_put(self, api_root): zone_dict = { 'name': 'PUT Zone', 'notes': 'PUT notes.', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.put( api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers ) assert response.status_code == 200 data = response.json() assert data['name'] == zone_dict['name'] assert data['notes'] == zone_dict['notes'] def test_zone_detail_put_without_zone_key(self, api_root): zone_dict = { 'name': 'PUT Zone', 'notes': 'PUT notes.' } headers = {'Content-type': 'application/json'} response = requests.put( api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers ) assert response.status_code == 403 def test_zone_detail_put_with_invalid_data(self, api_root): zone_dict = { 'name': None, 'notes': 'PUT notes.', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.put( api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers ) assert response.status_code == 400 def test_zone_detail_patch(self, api_root): zone_dict = { 'name': 'PATCH Zone', 'notes': 'PATCH notes.', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.patch( api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers ) assert response.status_code == 200 data = response.json() assert data['name'] == zone_dict['name'] assert data['notes'] == zone_dict['notes'] def test_zone_detail_patch_without_zone_key(self, api_root): zone_dict = { 'name': 'PATCH Zone', 'notes': 'PATCH notes.' } headers = {'Content-type': 'application/json'} response = requests.patch( api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers ) assert response.status_code == 403 def test_zone_detail_patch_with_invalid_data(self, api_root): zone_dict = { 'name': None, 'notes': 'PATCH notes.', 'key': str(self.zone.key) } headers = {'Content-type': 'application/json'} response = requests.patch( api_root + 'zones/{}/'.format(self.zone.id), data=json.dumps(zone_dict), headers=headers ) assert response.status_code == 400 def test_zone_detail_delete(self, api_root): response = requests.delete(api_root + 'zones/{}/'.format(self.zone.id)) assert response.status_code == 405
def create_data(self, request): def finalizer(): if self.alerts is not None: for alert in self.alerts: alert.delete() self.alerts = None if self.data is not None: for data in self.data: data.delete() self.data = None if self.sensor is not None: self.sensor.delete() self.sensor = None if self.zone is not None: self.zone.delete() self.zone = None if self.alert_group is not None: self.alert_group.delete() self.alert_group = None if self.user is not None: self.user.delete() username = str(uuid4())[:30] self.user = User( username=username, email='{}@example.net'.format(username) ) self.user.save() self.alert_group = SensorAlertGroup(name='Test Group') self.alert_group.save() self.alert_group.users.add(self.user) self.zone = Zone( name='Test Zone', notes='Zone notes.', key=uuid4() ) self.zone.save() self.sensor = Sensor( guid=uuid4(), name='Test Sensor', notes='Sensor notes.', zone=self.zone, min_value=60, max_value=85, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) self.sensor.save() self.sensor.alert_groups.add(self.alert_group) self.data = [] # Inbox is empty assert 0 == len(mail.outbox) # Create in-range data point; no notification. datum = SensorData( sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + 1, state=True, state_changed=False ) datum.save() self.data.append(datum) # Inbox still empty assert 0 == len(mail.outbox) # Create out-of-range notification; sends "alert." datum = SensorData( sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value - 1, state=True, state_changed=False ) datum.save() self.data.append(datum) # Inbox received alert assert 1 == len(mail.outbox) # Create another in-range data point; sends "recovered." datum = SensorData( sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + 1, state=True, state_changed=False ) datum.save() self.data.append(datum) # Inbox received recovery email assert 2 == len(mail.outbox) self.alerts = SensorAlert.objects.all().order_by('id') request.addfinalizer(finalizer)
class TestSensorsApi(object): user = None alert_group = None zone = None sensor = None data = None alerts = None @pytest.fixture(autouse=True) def api_root(self, request, live_server): api_root = '{}{}api/v1/'.format( live_server.url, '/' if not live_server.url.endswith('/') else '') return api_root @pytest.fixture(autouse=True) def create_data(self, request): def finalizer(): if self.alerts is not None: for alert in self.alerts: alert.delete() self.alerts = None if self.data is not None: for data in self.data: data.delete() self.data = None if self.sensor is not None: self.sensor.delete() self.sensor = None if self.zone is not None: self.zone.delete() self.zone = None if self.alert_group is not None: self.alert_group.delete() self.alert_group = None if self.user is not None: self.user.delete() username = str(uuid4())[:30] self.user = User( username=username, email='{}@example.net'.format(username) ) self.user.save() self.alert_group = SensorAlertGroup(name='Test Group') self.alert_group.save() self.alert_group.users.add(self.user) self.zone = Zone( name='Test Zone', notes='Zone notes.', key=uuid4() ) self.zone.save() self.sensor = Sensor( guid=uuid4(), name='Test Sensor', notes='Sensor notes.', zone=self.zone, min_value=60, max_value=85, min_value_operator='>=', max_value_operator='<=', state=True, state_last_change_date=datetime.utcnow() ) self.sensor.save() self.sensor.alert_groups.add(self.alert_group) self.data = [] # Inbox is empty assert 0 == len(mail.outbox) # Create in-range data point; no notification. datum = SensorData( sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + 1, state=True, state_changed=False ) datum.save() self.data.append(datum) # Inbox still empty assert 0 == len(mail.outbox) # Create out-of-range notification; sends "alert." datum = SensorData( sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value - 1, state=True, state_changed=False ) datum.save() self.data.append(datum) # Inbox received alert assert 1 == len(mail.outbox) # Create another in-range data point; sends "recovered." datum = SensorData( sensor=self.sensor, datetime=datetime.utcnow(), value=self.sensor.min_value + 1, state=True, state_changed=False ) datum.save() self.data.append(datum) # Inbox received recovery email assert 2 == len(mail.outbox) self.alerts = SensorAlert.objects.all().order_by('id') request.addfinalizer(finalizer) def _compare_sensor_alert_json(self, alert, alert_json): assert alert.id == alert_json['id'] assert alert.alert_type == alert_json['alert_type'] assert alert.alert_class == alert_json['alert_class'] assert alert.recipients == alert_json['recipients'] assert alert.message == alert_json['message'] assert alert.date.strftime('%Y-%m-%dT%H:%M:%S.%f') == alert_json['date'][:26] m = re.match(r'.*sensors/([0-9]+)/?', alert_json['sensor']) assert m is not None assert alert.sensor.id == int(m.group(1)) m = re.match(r'.*data/([0-9]+)/?', alert_json['data_point']) assert m is not None assert alert.data_point.id == int(m.group(1)) def test_alerts_list_no_filters(self, api_root): response = requests.get(api_root + 'alerts/?format=json') data = response.json() assert len(data) > 1 for alert in self.alerts: alert_json = [x for x in data if int(x['id']) == alert.id][0] self._compare_sensor_alert_json(alert, alert_json) def test_alerts_list_get_with_limit_and_offset(self, api_root): response = requests.get(api_root + 'alerts/?limit=10&offset=0&format=json') data = response.json() assert 'count' in data assert 'next' in data assert 'previous' in data assert 'results' in data def test_alerts_list_get_with_alert_filter(self, api_root): included_alert = self.alerts[0] excluded_alert = self.alerts[1] suffix = 'alerts/?alert_ids={}&format=json'.format(included_alert.id) response = requests.get(api_root + suffix) data = response.json() assert len(data) > 0 excluded_alert_json = [x for x in data if int(x['id']) == excluded_alert.id] assert len(excluded_alert_json) == 0 included_alert_json = [x for x in data if int(x['id']) == included_alert.id][0] self._compare_sensor_alert_json(included_alert, included_alert_json) def test_alerts_list_get_with_zone_filters(self, api_root): alert = self.alerts[0] # Ensure this alert is *not* included if its zone isn't specified. suffix = 'alerts/?zone_ids={}&format=json'.format(alert.sensor.zone.id + 1) response = requests.get(api_root + suffix) data = response.json() alerts_json = [x for x in data if int(x['id']) == alert.id] assert len(alerts_json) == 0 # Ensure this alert *is* included if its zone is specified. suffix = 'alerts/?zone_ids={}&format=json'.format(alert.sensor.zone.id) response = requests.get(api_root + suffix) data = response.json() alert_json = [x for x in data if int(x['id']) == alert.id][0] self._compare_sensor_alert_json(alert, alert_json) def test_alerts_list_get_with_sensor_filters(self, api_root): alert = self.alerts[0] # Ensure this alert is *not* included if its zone isn't specified. suffix = 'alerts/?sensor_ids={}&format=json'.format(alert.sensor.id + 1) response = requests.get(api_root + suffix) data = response.json() alerts_json = [x for x in data if int(x['id']) == alert.id] assert len(alerts_json) == 0 # Ensure this alert *is* included if its zone is specified. suffix = 'alerts/?sensor_ids={}&format=json'.format(alert.sensor.id) response = requests.get(api_root + suffix) data = response.json() alert_json = [x for x in data if int(x['id']) == alert.id][0] self._compare_sensor_alert_json(alert, alert_json) def test_alerts_list_get_with_order_by(self, api_root): response = requests.get(api_root + 'alerts/?order_by=-id&format=json') data = response.json() assert len(data) > 1 assert int(data[0]['id']) == self.alerts[1].id assert int(data[1]['id']) == self.alerts[0].id def test_alerts_list_post(self, api_root): response = requests.post(api_root + 'alerts/?format=json') assert response.status_code == 405 def test_alerts_list_patch(self, api_root): response = requests.patch(api_root + 'alerts/?format=json') assert response.status_code == 405 def test_alerts_list_delete(self, api_root): response = requests.delete(api_root + 'alerts/?format=json') assert response.status_code == 405 def test_alerts_detail_get(self, api_root): alert = self.alerts[0] suffix = 'alerts/{}/?format=json'.format(alert.id) response = requests.get(api_root + suffix) data = response.json() self._compare_sensor_alert_json(alert, data) def test_alerts_detail_post(self, api_root): alert = self.alerts[0] suffix = 'alerts/{0}/?format=json'.format(alert.id) response = requests.post(api_root + suffix) assert response.status_code == 405 def test_alerts_detail_patch(self, api_root): alert = self.alerts[0] suffix = 'alerts/{0}/?format=json'.format(alert.id) response = requests.patch(api_root + suffix) assert response.status_code == 405 def test_alerts_detail_delete(self, api_root): alert = self.alerts[0] suffix = 'alerts/{0}/?format=json'.format(alert.id) response = requests.delete(api_root + suffix) assert response.status_code == 405