No more stats table -> functionality of TimescaleDB

Changed PK in tables device/receiver from id to name
Altered FK in table takeoff_landings/logbook from device_id to address
Updated Flarm release dates
pull/78/head
Konstantin Gründger 2020-05-15 19:01:17 +02:00
rodzic 695478654b
commit a18e6aeab3
17 zmienionych plików z 16 dodań i 525 usunięć

Wyświetl plik

@ -22,7 +22,6 @@ CELERYBEAT_SCHEDULE = {
"update-takeoff-and-landing": {"task": "update_takeoff_landings", "schedule": timedelta(hours=1), "kwargs": {"last_minutes": 90}},
"update-logbook": {"task": "update_logbook_entries", "schedule": timedelta(hours=2), "kwargs": {"day_offset": 0}},
"update-max-altitudes": {"task": "update_logbook_max_altitude", "schedule": timedelta(hours=1), "kwargs": {"day_offset": 0}},
"update-stats-daily": {"task": "update_stats", "schedule": crontab(hour=0, minute=5), "kwargs": {"day_offset": -1}},
"update-logbook-daily": {"task": "update_logbook_entries", "schedule": crontab(hour=1, minute=0), "kwargs": {"day_offset": -1}},
"purge_old_data": {"task": "purge_old_data", "schedule": timedelta(hours=1), "kwargs": {"max_hours": 48}},
}

Wyświetl plik

@ -4,7 +4,7 @@ from flask import request, render_template, send_file
from app import db
from app import cache
from app.model import Airport, Country, Device, Logbook, Receiver, ReceiverStats
from app.model import Airport, Country, Device, Logbook, Receiver
from app.main import bp
@ -184,14 +184,3 @@ def download_flight():
buffer.seek(0)
return send_file(buffer, as_attachment=True, attachment_filename="wtf.igc", mimetype="text/plain")
@bp.route("/statistics.html")
def statistics():
today = datetime.date.today()
today = datetime.date(2018, 7, 31)
receiverstats = db.session.query(ReceiverStats).filter(ReceiverStats.date == today)
return render_template("statistics.html", title="Receiver Statistics", receiverstats=receiverstats)

Wyświetl plik

@ -2,20 +2,14 @@
from .aircraft_type import AircraftType
from .beacon import Beacon
from .country import Country
from .country_stats import CountryStats
from .device import Device
from .device_info import DeviceInfo
from .device_info_origin import DeviceInfoOrigin
from .device_stats import DeviceStats
from .aircraft_beacon import AircraftBeacon
from .receiver_beacon import ReceiverBeacon
from .receiver import Receiver
from .receiver_stats import ReceiverStats
from .takeoff_landing import TakeoffLanding
from .airport import Airport
from .logbook import Logbook
from .receiver_coverage import ReceiverCoverage
from .relation_stats import RelationStats
from .flights2d import Flight2D
from .geo import Location

Wyświetl plik

@ -30,8 +30,8 @@ class AircraftBeacon(Beacon):
distance = db.Column(db.Float(precision=2))
radial = db.Column(db.SmallInteger)
quality = db.Column(db.Float(precision=2)) # signal quality normalized to 10km
location_mgrs = db.Column(db.String(15)) # full mgrs (15 chars)
location_mgrs_short = db.Column(db.String(9)) # reduced mgrs (9 chars), e.g. used for melissas range tool
location_mgrs = db.Column(db.String(15)) # full mgrs (15 chars)
location_mgrs_short = db.Column(db.String(9)) # reduced mgrs (9 chars), e.g. used for melissas range tool
agl = db.Column(db.Float(precision=2))
def __repr__(self):
@ -56,75 +56,5 @@ class AircraftBeacon(Beacon):
self.quality,
self.location_mgrs,
self.location_mgrs_short,
self.agl,
)
@classmethod
def get_columns(self):
return [
"location",
"altitude",
"name",
"dstcall",
"relay",
"receiver_name",
"timestamp",
"track",
"ground_speed",
# 'raw_message',
# 'reference_timestamp',
"address_type",
"aircraft_type",
"stealth",
"address",
"climb_rate",
"turn_rate",
"signal_quality",
"error_count",
"frequency_offset",
"gps_quality_horizontal",
"gps_quality_vertical",
"software_version",
"hardware_version",
"real_address",
"signal_power",
"distance",
"radial",
"quality",
"location_mgrs",
"location_mgrs_short",
]
def get_values(self):
return [
self.location_wkt,
int(self.altitude) if self.altitude else None,
self.name,
self.dstcall,
self.relay,
self.receiver_name,
self.timestamp,
self.track,
self.ground_speed,
# self.raw_message,
# self.reference_timestamp,
self.address_type,
self.aircraft_type,
self.stealth,
self.address,
self.climb_rate,
self.turn_rate,
self.signal_quality,
self.error_count,
self.frequency_offset,
self.gps_quality_horizontal,
self.gps_quality_vertical,
self.software_version,
self.hardware_version,
self.real_address,
self.signal_power,
self.distance,
self.radial,
self.quality,
self.location_mgrs,
self.location_mgrs_short,
]

Wyświetl plik

@ -10,14 +10,14 @@ from app import db
class Beacon(AbstractConcreteBase, db.Model):
# APRS data
location_wkt = db.Column("location", Geometry("POINT", srid=4326))
location = db.Column("location", Geometry("POINT", srid=4326))
altitude = db.Column(db.Float(precision=2))
name = db.Column(db.String, primary_key=True, nullable=True)
name = db.Column(db.String, primary_key=True)
dstcall = db.Column(db.String)
relay = db.Column(db.String)
receiver_name = db.Column(db.String(9), primary_key=True, nullable=True)
timestamp = db.Column(db.DateTime, primary_key=True, nullable=True)
receiver_name = db.Column(db.String(9), primary_key=True)
timestamp = db.Column(db.DateTime, primary_key=True)
symboltable = None
symbolcode = None
track = db.Column(db.SmallInteger)
@ -31,15 +31,3 @@ class Beacon(AbstractConcreteBase, db.Model):
# Debug information
raw_message = None
reference_timestamp = None
@hybrid_property
def location(self):
if self.location_wkt is None:
return None
coords = to_shape(self.location_wkt)
return Location(lat=coords.y, lon=coords.x)
@location.expression
def location(cls):
return cls.location_wkt

Wyświetl plik

@ -1,17 +0,0 @@
from app import db
class CountryStats(db.Model):
__tablename__ = "country_stats"
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.Date)
# Static data
aircraft_beacon_count = db.Column(db.Integer)
device_count = db.Column(db.Integer)
# Relations
country_id = db.Column(db.Integer, db.ForeignKey("countries.gid", ondelete="SET NULL"), index=True)
country = db.relationship("Country", foreign_keys=[country_id], backref=db.backref("stats", order_by="CountryStats.date.asc()"))

Wyświetl plik

@ -10,9 +10,8 @@ from app.model.aircraft_type import AircraftType
class Device(db.Model):
__tablename__ = "devices"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String, primary_key=True)
name = db.Column(db.String, index=True)
# address = db.Column(db.String(6), index=True)
address = db.Column(db.String, index=True)
firstseen = db.Column(db.DateTime, index=True)
@ -38,6 +37,9 @@ class Device(db.Model):
return [info for info in query.all()]
EXPIRY_DATES = {
7.0: datetime.date(2021, 10, 31),
6.83: datetime.date(2021, 10, 31),
6.82: datetime.date(2021, 5, 31),
6.81: datetime.date(2021, 1, 31),
6.80: datetime.date(2021, 1, 31),
6.67: datetime.date(2020, 10, 31),

Wyświetl plik

@ -1,52 +0,0 @@
from app import db
from .aircraft_type import AircraftType
class DeviceStats(db.Model):
__tablename__ = "device_stats"
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.Date)
# Static data
name = db.Column(db.String)
firstseen = db.Column(db.DateTime)
lastseen = db.Column(db.DateTime)
aircraft_type = db.Column(db.Enum(AircraftType), nullable=False, default=AircraftType.UNKNOWN)
stealth = db.Column(db.Boolean)
software_version = db.Column(db.Float(precision=2))
hardware_version = db.Column(db.SmallInteger)
real_address = db.Column(db.String(6))
# Statistic data
max_altitude = db.Column(db.Float(precision=2))
receiver_count = db.Column(db.SmallInteger)
aircraft_beacon_count = db.Column(db.Integer)
jumps = db.Column(db.SmallInteger)
ambiguous = db.Column(db.Boolean)
quality = db.Column(db.Float(precision=2))
# Relation statistic data
quality_offset = db.Column(db.Float(precision=2))
# Ranking data
max_altitude_ranking_worldwide = db.Column(db.Integer)
max_altitude_ranking_country = db.Column(db.Integer)
receiver_count_ranking_worldwide = db.Column(db.Integer)
receiver_count_ranking_country = db.Column(db.Integer)
aircraft_beacon_count_ranking_worldwide = db.Column(db.Integer)
aircraft_beacon_count_ranking_country = db.Column(db.Integer)
quality_ranking_worldwide = db.Column(db.Integer)
quality_ranking_country = db.Column(db.Integer)
# Relations
device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="SET NULL"), index=True)
device = db.relationship("Device", foreign_keys=[device_id], backref=db.backref("stats", order_by="DeviceStats.date.asc()"))
def __repr__(self):
return "<DeviceStats: %s,%s,%s,%s>" % (self.date, self.receiver_count, self.aircraft_beacon_count, self.max_altitude)
db.Index("ix_device_stats_date_device_id", DeviceStats.date, DeviceStats.device_id)

Wyświetl plik

@ -1,24 +0,0 @@
from geoalchemy2.types import Geometry
from app import db
class Flight2D(db.Model):
__tablename__ = "flights2d"
date = db.Column(db.Date, primary_key=True)
flight_type = db.Column(db.SmallInteger, primary_key=True)
path_wkt = db.Column("path", Geometry("MULTILINESTRING", srid=4326))
path_simple_wkt = db.Column("path_simple", Geometry("MULTILINESTRING", srid=4326)) # this is the path simplified with ST_Simplify(path, 0.0001)
# Relations
device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="SET NULL"), primary_key=True)
device = db.relationship("Device", foreign_keys=[device_id], backref="flights2d")
def __repr__(self):
return "<Flight %s: %s,%s>" % (self.date, self.path_wkt, self.path_simple_wkt)
db.Index("ix_flights2d_date_device_id", Flight2D.date, Flight2D.device_id)
# db.Index('ix_flights2d_date_path', Flight2D.date, Flight2D.path_wkt) --> CREATE INDEX ix_flights2d_date_path ON flights2d USING GIST("date", path)

Wyświetl plik

@ -9,6 +9,7 @@ class Logbook(db.Model):
id = db.Column(db.Integer, primary_key=True)
reftime = db.Column(db.DateTime, index=True)
address = db.Column(db.String, index=True)
takeoff_timestamp = db.Column(db.DateTime)
takeoff_track = db.Column(db.SmallInteger)
landing_timestamp = db.Column(db.DateTime)
@ -22,9 +23,6 @@ class Logbook(db.Model):
landing_airport_id = db.Column(db.Integer, db.ForeignKey("airports.id", ondelete="CASCADE"), index=True)
landing_airport = db.relationship("Airport", foreign_keys=[landing_airport_id])
device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="CASCADE"), index=True)
device = db.relationship("Device", foreign_keys=[device_id], backref=db.backref("logbook", order_by="Logbook.reftime"))
@hybrid_property
def duration(self):
return None if (self.landing_timestamp is None or self.takeoff_timestamp is None) else self.landing_timestamp - self.takeoff_timestamp

Wyświetl plik

@ -9,14 +9,13 @@ from app import db
class Receiver(db.Model):
__tablename__ = "receivers"
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(9), primary_key=True)
location_wkt = db.Column("location", Geometry("POINT", srid=4326))
altitude = db.Column(db.Float(precision=2))
name = db.Column(db.String(9), index=True)
firstseen = db.Column(db.DateTime, index=True)
lastseen = db.Column(db.DateTime, index=True)
timestamp = db.Column(db.DateTime, index=True)
version = db.Column(db.String)
platform = db.Column(db.String)

Wyświetl plik

@ -18,28 +18,3 @@ class ReceiverBeacon(Beacon):
self.receiver_name,
self.timestamp,
)
@classmethod
def get_columns(self):
return [
"location",
"altitude",
"name",
"dstcall",
"receiver_name",
"timestamp",
# 'raw_message',
# 'reference_timestamp',
]
def get_values(self):
return [
self.location_wkt,
int(self.altitude) if self.altitude else None,
self.name,
self.dstcall,
self.receiver_name,
self.timestamp,
# self.raw_message,
# self.reference_timestamp,
]

Wyświetl plik

@ -1,23 +0,0 @@
from app import db
class ReceiverCoverage(db.Model):
__tablename__ = "receiver_coverages"
location_mgrs_short = db.Column(db.String(9), primary_key=True)
date = db.Column(db.Date, primary_key=True)
max_signal_quality = db.Column(db.Float)
max_altitude = db.Column(db.Float(precision=2))
min_altitude = db.Column(db.Float(precision=2))
aircraft_beacon_count = db.Column(db.Integer)
device_count = db.Column(db.SmallInteger)
# Relations
receiver_id = db.Column(db.Integer, db.ForeignKey("receivers.id", ondelete="SET NULL"), primary_key=True)
receiver = db.relationship("Receiver", foreign_keys=[receiver_id], backref=db.backref("receiver_coverages", order_by="ReceiverCoverage.date.asc()"))
db.Index("ix_receiver_coverages_date_receiver_id", ReceiverCoverage.date, ReceiverCoverage.receiver_id)
db.Index("ix_receiver_coverages_receiver_id_date", ReceiverCoverage.receiver_id, ReceiverCoverage.date)

Wyświetl plik

@ -1,41 +0,0 @@
from geoalchemy2.types import Geometry
from app import db
class ReceiverStats(db.Model):
__tablename__ = "receiver_stats"
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.Date)
# Static data
firstseen = db.Column(db.DateTime, index=True)
lastseen = db.Column(db.DateTime, index=True)
location_wkt = db.Column("location", Geometry("POINT", srid=4326))
altitude = db.Column(db.Float(precision=2))
version = db.Column(db.String)
platform = db.Column(db.String)
# Statistic data
aircraft_beacon_count = db.Column(db.Integer)
aircraft_count = db.Column(db.SmallInteger)
max_distance = db.Column(db.Float)
quality = db.Column(db.Float(precision=2))
# Relation statistic data
quality_offset = db.Column(db.Float(precision=2))
# Ranking data
aircraft_beacon_count_ranking = db.Column(db.SmallInteger)
aircraft_count_ranking = db.Column(db.SmallInteger)
max_distance_ranking = db.Column(db.SmallInteger)
quality_ranking = db.Column(db.Integer)
# Relations
receiver_id = db.Column(db.Integer, db.ForeignKey("receivers.id", ondelete="SET NULL"), index=True)
receiver = db.relationship("Receiver", foreign_keys=[receiver_id], backref=db.backref("stats", order_by="ReceiverStats.date.asc()"))
db.Index("ix_receiver_stats_date_receiver_id", ReceiverStats.date, ReceiverStats.receiver_id)

Wyświetl plik

@ -1,26 +0,0 @@
from app import db
class RelationStats(db.Model):
__tablename__ = "relation_stats"
id = db.Column(db.Integer, primary_key=True)
date = db.Column(db.Date)
# Statistic data
quality = db.Column(db.Float(precision=2))
beacon_count = db.Column(db.Integer)
# Relations
device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="SET NULL"), index=True)
device = db.relationship("Device", foreign_keys=[device_id], backref="relation_stats")
receiver_id = db.Column(db.Integer, db.ForeignKey("receivers.id", ondelete="SET NULL"), index=True)
receiver = db.relationship("Receiver", foreign_keys=[receiver_id], backref="relation_stats")
def __repr__(self):
return "<RelationStats: %s,%s,%s>" % (self.date, self.quality, self.beacon_count)
db.Index("ix_relation_stats_date_device_id", RelationStats.date, RelationStats.device_id, RelationStats.receiver_id)
db.Index("ix_relation_stats_date_receiver_id", RelationStats.date, RelationStats.receiver_id, RelationStats.device_id)

Wyświetl plik

@ -4,7 +4,7 @@ from app import db
class TakeoffLanding(db.Model):
__tablename__ = "takeoff_landings"
device_id = db.Column(db.Integer, db.ForeignKey("devices.id", ondelete="SET NULL"), primary_key=True)
address = db.Column(db.String, primary_key=True)
airport_id = db.Column(db.Integer, db.ForeignKey("airports.id", ondelete="SET NULL"), primary_key=True)
timestamp = db.Column(db.DateTime, primary_key=True)
@ -13,4 +13,3 @@ class TakeoffLanding(db.Model):
# Relations
airport = db.relationship("Airport", foreign_keys=[airport_id], backref="takeoff_landings")
device = db.relationship("Device", foreign_keys=[device_id], backref="takeoff_landings", order_by="TakeoffLanding.timestamp")

Wyświetl plik

@ -1,199 +0,0 @@
from datetime import datetime, date
import unittest
from tests.base import TestBaseDB, db
from app.model import AircraftBeacon, ReceiverBeacon, Receiver, Device, DeviceStats
from app.collect.stats import create_device_stats
class TestStats(TestBaseDB):
def setUp(self):
super().setUp()
# Prepare Beacons
self.ab01 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:01")
self.ab02 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:02")
self.ab03 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:03")
self.ab04 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:04")
self.ab05 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:05")
self.ab06 = AircraftBeacon(name="FLRDD4711", receiver_name="Koenigsdf", timestamp="2017-12-10 10:00:05")
self.rb01 = ReceiverBeacon(name="Koenigsdf", receiver_name="GLIDERN1", timestamp="2017-12-10 09:55:00", altitude=601)
self.rb02 = ReceiverBeacon(name="Koenigsdf", receiver_name="GLIDERN1", timestamp="2017-12-10 10:00:00", altitude=601)
self.rb03 = ReceiverBeacon(name="Koenigsdf", receiver_name="GLIDERN1", timestamp="2017-12-10 10:05:00", altitude=601)
self.r01 = Receiver(name="Koenigsdf")
self.r02 = Receiver(name="Bene")
self.d01 = Device(address="DD4711")
db.session.add(self.r01)
db.session.add(self.d01)
db.session.commit()
@unittest.skip('stats will replaced by timescaledb aggregates')
def test_create_device_stats(self):
# Compute 1st beacon
self.ab01.device = self.d01
self.ab01.receiver = self.r01
db.session.add(self.ab01)
db.session.commit()
today = date(2017, 12, 10)
create_device_stats(db.session, date=today)
devicestats = db.session.query(DeviceStats).all()
self.assertEqual(len(devicestats), 1)
self.assertEqual(devicestats[0].device, self.d01)
self.assertEqual(devicestats[0].max_altitude, None)
self.assertEqual(devicestats[0].receiver_count, 1)
self.assertEqual(devicestats[0].aircraft_beacon_count, 1)
self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date())
self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1))
self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 1))
self.assertEqual(devicestats[0].aircraft_type, None)
self.assertEqual(devicestats[0].stealth, None)
self.assertEqual(devicestats[0].software_version, None)
self.assertEqual(devicestats[0].hardware_version, None)
self.assertEqual(devicestats[0].real_address, None)
# Compute 2nd beacon: set altitude, aircraft_type and stealth
self.ab02.device = self.d01
self.ab02.receiver = self.r01
self.ab02.altitude = 200
self.ab02.aircraft_type = 3
self.ab02.stealth = False
db.session.add(self.ab02)
db.session.commit()
create_device_stats(db.session, date=today)
devicestats = db.session.query(DeviceStats).all()
self.assertEqual(len(devicestats), 1)
self.assertEqual(devicestats[0].device, self.d01)
self.assertEqual(devicestats[0].max_altitude, 200)
self.assertEqual(devicestats[0].receiver_count, 1)
self.assertEqual(devicestats[0].aircraft_beacon_count, 2)
self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date())
self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1))
self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 2))
self.assertEqual(devicestats[0].aircraft_type, 3)
self.assertEqual(devicestats[0].stealth, False)
self.assertEqual(devicestats[0].software_version, None)
self.assertEqual(devicestats[0].hardware_version, None)
self.assertEqual(devicestats[0].real_address, None)
# Compute 3rd beacon: changed software version, but with error_count > 0
self.ab03.device = self.d01
self.ab03.receiver = self.r01
self.ab03.error_count = 1
self.ab03.software_version = 6.01
db.session.add(self.ab03)
db.session.commit()
create_device_stats(db.session, date=today)
devicestats = db.session.query(DeviceStats).all()
self.assertEqual(len(devicestats), 1)
self.assertEqual(devicestats[0].device, self.d01)
self.assertEqual(devicestats[0].max_altitude, 200)
self.assertEqual(devicestats[0].receiver_count, 1)
self.assertEqual(devicestats[0].aircraft_beacon_count, 2)
self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date())
self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1))
self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 2))
self.assertEqual(devicestats[0].aircraft_type, 3)
self.assertEqual(devicestats[0].stealth, False)
self.assertEqual(devicestats[0].software_version, None)
self.assertEqual(devicestats[0].hardware_version, None)
self.assertEqual(devicestats[0].real_address, None)
# Compute 4. beacon: another receiver, greater altitude, software_version, hardware_version, real_address
self.ab04.device = self.d01
self.ab04.receiver = self.r02
self.ab04.altitude = 250
self.ab04.software_version = 6.01
self.ab04.hardware_version = 15
self.ab04.real_address = "DDALFA"
db.session.add(self.ab04)
db.session.commit()
create_device_stats(db.session, date=today)
devicestats = db.session.query(DeviceStats).all()
self.assertEqual(len(devicestats), 1)
self.assertEqual(devicestats[0].device, self.d01)
self.assertEqual(devicestats[0].max_altitude, 250)
self.assertEqual(devicestats[0].receiver_count, 2)
self.assertEqual(devicestats[0].aircraft_beacon_count, 3)
self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date())
self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1))
self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 4))
self.assertEqual(devicestats[0].aircraft_type, 3)
self.assertEqual(devicestats[0].stealth, False)
self.assertEqual(devicestats[0].software_version, 6.01)
self.assertEqual(devicestats[0].hardware_version, 15)
self.assertEqual(devicestats[0].real_address, "DDALFA")
# Compute 5. beacon: lower altitude, stealth
self.ab05.device = self.d01
self.ab05.receiver = self.r02
self.ab05.altitude = 100
self.ab05.stealth = True
db.session.add(self.ab05)
db.session.commit()
create_device_stats(db.session, date=today)
devicestats = db.session.query(DeviceStats).all()
self.assertEqual(len(devicestats), 1)
self.assertEqual(devicestats[0].device, self.d01)
self.assertEqual(devicestats[0].max_altitude, 250)
self.assertEqual(devicestats[0].receiver_count, 2)
self.assertEqual(devicestats[0].aircraft_beacon_count, 4)
self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date())
self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 10, 0, 1))
self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 5))
self.assertEqual(devicestats[0].aircraft_type, 3)
self.assertEqual(devicestats[0].stealth, True)
self.assertEqual(devicestats[0].software_version, 6.01)
self.assertEqual(devicestats[0].hardware_version, 15)
self.assertEqual(devicestats[0].real_address, "DDALFA")
# Compute 6. beacon: beacon from past, greater altitude, newer version
self.ab06.device = self.d01
self.ab06.receiver = self.r02
self.ab06.timestamp = datetime(2017, 12, 10, 9, 59, 50)
self.ab06.altitude = 300
self.ab06.software_version = 6.02
db.session.add(self.ab06)
db.session.commit()
create_device_stats(db.session, date=today)
devicestats = db.session.query(DeviceStats).all()
self.assertEqual(len(devicestats), 1)
self.assertEqual(devicestats[0].device, self.d01)
self.assertEqual(devicestats[0].max_altitude, 300)
self.assertEqual(devicestats[0].receiver_count, 2)
self.assertEqual(devicestats[0].aircraft_beacon_count, 5)
self.assertEqual(devicestats[0].date, datetime.strptime("2017-12-10", "%Y-%m-%d").date())
self.assertEqual(devicestats[0].firstseen, datetime(2017, 12, 10, 9, 59, 50))
self.assertEqual(devicestats[0].lastseen, datetime(2017, 12, 10, 10, 0, 5))
self.assertEqual(devicestats[0].aircraft_type, 3)
self.assertEqual(devicestats[0].stealth, True)
self.assertEqual(devicestats[0].software_version, 6.01)
self.assertEqual(devicestats[0].hardware_version, 15)
self.assertEqual(devicestats[0].real_address, "DDALFA")
if __name__ == "__main__":
unittest.main()