def test_insert_measures_out_of_range(self): session = self.db_master_session time = util.utcnow() - timedelta(days=1) measure = dict( id=0, created=encode_datetime(time), lat=PARIS_LAT, lon=PARIS_LON, time=encode_datetime(time), accuracy=0, altitude=0, altitude_accuracy=0, radio=RADIO_TYPE['gsm'], mcc=FRANCE_MCC, mnc=2, lac=3, cid=4) entries = [ {"asu": 8, "signal": -70, "ta": 32}, {"asu": -10, "signal": -300, "ta": -10}, {"asu": 256, "signal": 16, "ta": 128}, ] for e in entries: e.update(measure) result = insert_measures_cell.delay(entries) self.assertEqual(result.get(), 3) measures = session.query(CellMeasure).all() self.assertEqual(len(measures), 3) self.assertEqual(set([m.asu for m in measures]), set([-1, 8])) self.assertEqual(set([m.signal for m in measures]), set([0, -70])) self.assertEqual(set([m.ta for m in measures]), set([0, 32]))
def test_insert_measures_invalid_lac(self): session = self.db_master_session schema = ValidCellBaseSchema() time = util.utcnow() - timedelta(days=1) session.add( Cell(radio=RADIO_TYPE['gsm'], mcc=FRANCE_MCC, mnc=2, lac=3, cid=4, new_measures=2, total_measures=5)) session.add(Score(userid=1, key=SCORE_TYPE['new_cell'], value=7)) session.flush() measure = dict(created=encode_datetime(time), lat=PARIS_LAT, lon=PARIS_LON, time=encode_datetime(time), accuracy=0, altitude=0, altitude_accuracy=0, radio=RADIO_TYPE['gsm']) entries = [ { "mcc": FRANCE_MCC, "mnc": 2, "lac": constants.MAX_LAC_ALL + 1, "cid": constants.MAX_CID_ALL + 1, "psc": 5, "asu": 8 }, { "mcc": FRANCE_MCC, "mnc": 2, "lac": schema.fields['lac'].missing, "cid": schema.fields['cid'].missing, "psc": 5, "asu": 8 }, ] for e in entries: e.update(measure) result = insert_measures_cell.delay(entries, userid=1) self.assertEqual(result.get(), 2) measures = session.query(CellMeasure).all() self.assertEqual(len(measures), 2) self.assertEqual(set([m.lac for m in measures]), set([schema.fields['lac'].missing])) self.assertEqual(set([m.cid for m in measures]), set([schema.fields['cid'].missing])) # Nothing should change in the initially created Cell record cells = session.query(Cell).all() self.assertEqual(len(cells), 1) self.assertEqual(set([c.new_measures for c in cells]), set([2])) self.assertEqual(set([c.total_measures for c in cells]), set([5]))
def test_insert_measures(self): session = self.db_master_session time = util.utcnow() - timedelta(days=1) session.add(Wifi(key="ab1234567890")) session.add(Score(userid=1, key=SCORE_TYPE['new_wifi'], value=7)) session.flush() measure = dict( id=0, created=encode_datetime(time), lat=1.0, lon=2.0, time=encode_datetime(time), accuracy=0, altitude=0, altitude_accuracy=0, radio=-1, heading=52.9, speed=158.5, ) entries = [ {"key": "ab1234567890", "channel": 11, "signal": -80}, {"key": "ab1234567890", "channel": 3, "signal": -90}, {"key": "ab1234567890", "channel": 3, "signal": -80}, {"key": "cd3456789012", "channel": 3, "signal": -90}, ] for e in entries: e.update(measure) result = insert_measures_wifi.delay(entries, userid=1) self.assertEqual(result.get(), 4) measures = session.query(WifiMeasure).all() self.assertEqual(len(measures), 4) self.assertEqual(set([m.key for m in measures]), set(["ab1234567890", "cd3456789012"])) self.assertEqual(set([m.channel for m in measures]), set([3, 11])) self.assertEqual(set([m.signal for m in measures]), set([-80, -90])) self.assertEqual(set([m.heading or m in measures]), set([52.9])) self.assertEqual(set([m.speed or m in measures]), set([158.5])) wifis = session.query(Wifi).all() self.assertEqual(len(wifis), 2) self.assertEqual(set([w.key for w in wifis]), set(["ab1234567890", "cd3456789012"])) self.assertEqual(set([w.new_measures for w in wifis]), set([1, 3])) self.assertEqual(set([w.total_measures for w in wifis]), set([1, 3])) scores = session.query(Score).all() self.assertEqual(len(scores), 1) self.assertEqual(scores[0].key, SCORE_TYPE['new_wifi']) self.assertEqual(scores[0].value, 8) # test duplicate execution result = insert_measures_wifi.delay(entries, userid=1) self.assertEqual(result.get(), 4) # TODO this task isn't idempotent yet measures = session.query(WifiMeasure).all() self.assertEqual(len(measures), 8)
def test_normalize_time(self): now = util.utcnow() first_args = dict(day=1, hour=0, minute=0, second=0, microsecond=0, tzinfo=UTC) now_enc = now.replace(**first_args) two_weeks_ago = now - timedelta(14) short_format = now.date().isoformat() entries = [ ('', now_enc), (now, now_enc), (two_weeks_ago, two_weeks_ago.replace(**first_args)), (short_format, now_enc), ("2011-01-01T11:12:13.456Z", now_enc), ("2070-01-01T11:12:13.456Z", now_enc), ("10-10-10", now_enc), ("2011-10-13T.Z", now_enc), ] for entry in entries: in_, expected = entry if not isinstance(in_, str): in_ = encode_datetime(in_) self.assertEqual( decode_datetime(normalized_time(in_)), expected)
def test_time(self): app = self.app # test two weeks ago and "now" time = util.utcnow() - timedelta(14) tstr = encode_datetime(time) app.post_json( '/v1/submit', {"items": [ {"lat": 1.0, "lon": 2.0, "wifi": [{"key": "00aaaaaaaaaa"}], "time": tstr}, {"lat": 2.0, "lon": 3.0, "wifi": [{"key": "00bbbbbbbbbb"}]}, ]}, status=204) session = self.db_master_session result = session.query(WifiMeasure).all() self.assertEqual(len(result), 2) wifis = dict([(w.key, (w.created, w.time)) for w in result]) today = util.utcnow().date() month_rounded_tday = time.replace(day=1, hour=0, minute=0, second=0) month_rounded_tday = month_rounded_tday.replace(tzinfo=pytz.UTC) month_rounded_today = today.replace(day=1) self.assertEqual(wifis['00aaaaaaaaaa'][0].date(), today) self.assertEqual(wifis['00aaaaaaaaaa'][1], month_rounded_tday) self.assertEqual(wifis['00bbbbbbbbbb'][0].date(), today) self.assertEqual(wifis['00bbbbbbbbbb'][1].date(), month_rounded_today)
def test_normalize_time(self): now = util.utcnow() first_args = dict(day=1, hour=0, minute=0, second=0, microsecond=0, tzinfo=UTC) now_enc = now.replace(**first_args) two_weeks_ago = now - timedelta(14) short_format = now.date().isoformat() entries = [ ('', now_enc), (now, now_enc), (two_weeks_ago, two_weeks_ago.replace(**first_args)), (short_format, now_enc), ("2011-01-01T11:12:13.456Z", now_enc), ("2070-01-01T11:12:13.456Z", now_enc), ("10-10-10", now_enc), ("2011-10-13T.Z", now_enc), ] for entry in entries: in_, expected = entry if not isinstance(in_, str): in_ = encode_datetime(in_) self.assertEqual(decode_datetime(normalized_time(in_)), expected)
def normalized_time(time): """ Takes a string representation of a time value, validates and parses it and returns a JSON-friendly string representation of the normalized time. It rounds down a date to the first of the month. It takes any date greater than 60 days into the past or in the future and sets it to the current date. """ now = util.utcnow() if not time: time = None try: time = iso8601.parse_date(time) except (iso8601.ParseError, TypeError): time = now else: # don't accept future time values or # time values more than 60 days in the past min_time = now - timedelta(days=60) if time > now or time < min_time: time = now # cut down the time to a monthly resolution time = time.date().replace(day=1) return encode_datetime(time)
def test_insert_measures_out_of_range(self): session = self.db_master_session time = util.utcnow() - timedelta(days=1) measure = dict(created=encode_datetime(time), lat=PARIS_LAT, lon=PARIS_LON, time=encode_datetime(time), accuracy=0, altitude=0, altitude_accuracy=0, radio=RADIO_TYPE['gsm'], mcc=FRANCE_MCC, mnc=2, lac=3, cid=4) entries = [ { "asu": 8, "signal": -70, "ta": 32 }, { "asu": -10, "signal": -300, "ta": -10 }, { "asu": 256, "signal": 16, "ta": 128 }, ] for e in entries: e.update(measure) result = insert_measures_cell.delay(entries) self.assertEqual(result.get(), 3) measures = session.query(CellMeasure).all() self.assertEqual(len(measures), 3) self.assertEqual(set([m.asu for m in measures]), set([-1, 8])) self.assertEqual(set([m.signal for m in measures]), set([0, -70])) self.assertEqual(set([m.ta for m in measures]), set([0, 32]))
def test_insert_measures_invalid_lac(self): session = self.db_master_session time = util.utcnow() - timedelta(days=1) session.add(Cell(radio=RADIO_TYPE['gsm'], mcc=FRANCE_MCC, mnc=2, lac=3, cid=4, new_measures=2, total_measures=5)) session.add(Score(userid=1, key=SCORE_TYPE['new_cell'], value=7)) session.flush() measure = dict( id=0, created=encode_datetime(time), lat=PARIS_LAT, lon=PARIS_LON, time=encode_datetime(time), accuracy=0, altitude=0, altitude_accuracy=0, radio=RADIO_TYPE['gsm']) entries = [ {"mcc": FRANCE_MCC, "mnc": 2, "lac": 3147483647, "cid": 2147483647, "psc": 5, "asu": 8}, {"mcc": FRANCE_MCC, "mnc": 2, "lac": -1, "cid": -1, "psc": 5, "asu": 8}, ] for e in entries: e.update(measure) result = insert_measures_cell.delay(entries, userid=1) self.assertEqual(result.get(), 2) measures = session.query(CellMeasure).all() self.assertEqual(len(measures), 2) self.assertEqual(set([m.lac for m in measures]), set([-1])) self.assertEqual(set([m.cid for m in measures]), set([-1])) # Nothing should change in the initially created Cell record cells = session.query(Cell).all() self.assertEqual(len(cells), 1) self.assertEqual(set([c.new_measures for c in cells]), set([2])) self.assertEqual(set([c.total_measures for c in cells]), set([5]))
def normalized_time(time): """ Takes a string representation of a time value, validates and parses it and returns a JSON-friendly string representation of the normalized time. """ now = util.utcnow() if not time: time = None try: time = iso8601.parse_date(time) except (iso8601.ParseError, TypeError): time = now else: # don't accept future time values or # time values more than 60 days in the past min_time = now - timedelta(days=60) if time > now or time < min_time: time = now # cut down the time to a monthly resolution time = time.date().replace(day=1) return encode_datetime(time)
def test_blacklist_temporary_and_permanent(self): session = self.db_master_session # This test simulates a wifi that moves once a month, for 2 years. # The first 2 * PERMANENT_BLACKLIST_THRESHOLD (12) moves should be # temporary, forgotten after a week; after that it should be # permanently blacklisted. now = util.utcnow() # Station moves between these 4 points, all in the USA: points = [ # NYC (40.0, -74.0), # SF (37.0, -122.0), # Seattle (47.0, -122.0), # Miami (25.0, -80.0), ] N = 4 * PERMANENT_BLACKLIST_THRESHOLD for month in range(0, N): days_ago = (N - (month + 1)) * 30 time = now - timedelta(days=days_ago) time_enc = encode_datetime(time) measure = dict(id=month, key="ab1234567890", time=time_enc, lat=points[month % 4][0], lon=points[month % 4][1]) # insert_result is num-accepted-measures, override # utcnow to set creation date insert_result = insert_measures_wifi.delay( [measure], utcnow=time_enc) # update_result is (num-stations, num-moving-stations) update_result = location_update_wifi.delay(min_new=1) # Assuming PERMANENT_BLACKLIST_THRESHOLD == 6: # # 0th insert will create the station # 1st insert will create first blacklist entry, delete station # 2nd insert will recreate the station at new position # 3rd insert will update blacklist, re-delete station # 4th insert will recreate the station at new position # 5th insert will update blacklist, re-delete station # 6th insert will recreate the station at new position # ... # 11th insert will make blacklisting permanent, re-delete station # 12th insert will not recreate station # 13th insert will not recreate station # ... # 23rd insert will not recreate station bl = session.query(WifiBlacklist).all() if month == 0: self.assertEqual(len(bl), 0) else: self.assertEqual(len(bl), 1) # force the blacklist back in time to whenever the # measure was supposedly inserted. bl = bl[0] bl.time = time session.add(bl) session.commit() if month < N / 2: # We still haven't exceeded the threshold, so the # measurement was admitted. self.assertEqual(insert_result.get(), 1) self.assertEqual(session.query(WifiMeasure).count(), month + 1) if month % 2 == 0: # The station was (re)created. self.assertEqual(update_result.get(), (1, 0)) # One wifi record should exist. self.assertEqual(session.query(Wifi).count(), 1) else: # The station existed and was seen moving, # thereby activating the blacklist. self.assertEqual(update_result.get(), (1, 1)) self.assertEqual(bl.count, ((month + 1) / 2)) self.assertEqual(session.query(WifiBlacklist).count(), 1) self.assertEqual(session.query(Wifi).count(), 0) # Try adding one more measurement 1 day later # to be sure it is dropped by the now-active blacklist. next_day = encode_datetime(time + timedelta(days=1)) measure['time'] = next_day self.assertEqual( 0, insert_measures_wifi.delay([measure], utcnow=next_day).get()) else: # Blacklist has exceeded threshold, gone to "permanent" mode, # so no measures accepted, no stations seen. self.assertEqual(insert_result.get(), 0) self.assertEqual(update_result.get(), 0)
def test_insert_measures(self): session = self.db_master_session time = util.utcnow() - timedelta(days=1) mcc = FRANCE_MCC session.add(Cell(radio=RADIO_TYPE['gsm'], mcc=mcc, mnc=2, lac=3, cid=4, psc=5, new_measures=2, total_measures=5)) session.add(Score(userid=1, key=SCORE_TYPE['new_cell'], value=7)) session.flush() measure = dict( id=0, created=encode_datetime(time), lat=PARIS_LAT, lon=PARIS_LON, time=encode_datetime(time), accuracy=0, altitude=0, altitude_accuracy=0, radio=RADIO_TYPE['gsm'], ) entries = [ # Note that this first entry will be skipped as it does # not include (lac, cid) or (psc) {"mcc": mcc, "mnc": 2, "signal": -100}, {"mcc": mcc, "mnc": 2, "lac": 3, "cid": 4, "psc": 5, "asu": 8}, {"mcc": mcc, "mnc": 2, "lac": 3, "cid": 4, "psc": 5, "asu": 8}, {"mcc": mcc, "mnc": 2, "lac": 3, "cid": 4, "psc": 5, "asu": 15}, {"mcc": mcc, "mnc": 2, "lac": 3, "cid": 7, "psc": 5}, ] for e in entries: e.update(measure) result = insert_measures_cell.delay(entries, userid=1) self.assertEqual(result.get(), 4) measures = session.query(CellMeasure).all() self.assertEqual(len(measures), 4) self.assertEqual(set([m.mcc for m in measures]), set([mcc])) self.assertEqual(set([m.mnc for m in measures]), set([2])) self.assertEqual(set([m.asu for m in measures]), set([-1, 8, 15])) self.assertEqual(set([m.psc for m in measures]), set([5])) self.assertEqual(set([m.signal for m in measures]), set([0])) cells = session.query(Cell).all() self.assertEqual(len(cells), 2) self.assertEqual(set([c.mcc for c in cells]), set([mcc])) self.assertEqual(set([c.mnc for c in cells]), set([2])) self.assertEqual(set([c.lac for c in cells]), set([3])) self.assertEqual(set([c.cid for c in cells]), set([4, 7])) self.assertEqual(set([c.psc for c in cells]), set([5])) self.assertEqual(set([c.new_measures for c in cells]), set([1, 5])) self.assertEqual(set([c.total_measures for c in cells]), set([1, 8])) scores = session.query(Score).all() self.assertEqual(len(scores), 1) self.assertEqual(scores[0].key, SCORE_TYPE['new_cell']) self.assertEqual(scores[0].value, 8) # test duplicate execution result = insert_measures_cell.delay(entries, userid=1) self.assertEqual(result.get(), 4) # TODO this task isn't idempotent yet measures = session.query(CellMeasure).all() self.assertEqual(len(measures), 8)
def test_insert_measures(self): session = self.db_master_session time = util.utcnow() - timedelta(days=1) session.add(Wifi(key="ab1234567890")) session.add(Score(userid=1, key=SCORE_TYPE['new_wifi'], value=7)) session.flush() measure = dict( created=encode_datetime(time), lat=1.0, lon=2.0, time=encode_datetime(time), accuracy=0, altitude=0, altitude_accuracy=0, radio=-1, heading=52.9, speed=158.5, ) entries = [ { "key": "ab1234567890", "channel": 11, "signal": -80 }, { "key": "ab1234567890", "channel": 3, "signal": -90 }, { "key": "ab1234567890", "channel": 3, "signal": -80 }, { "key": "cd3456789012", "channel": 3, "signal": -90 }, ] for e in entries: e.update(measure) result = insert_measures_wifi.delay(entries, userid=1) self.assertEqual(result.get(), 4) measures = session.query(WifiMeasure).all() self.assertEqual(len(measures), 4) self.assertEqual(set([m.key for m in measures]), set(["ab1234567890", "cd3456789012"])) self.assertEqual(set([m.channel for m in measures]), set([3, 11])) self.assertEqual(set([m.signal for m in measures]), set([-80, -90])) self.assertEqual(set([m.heading or m in measures]), set([52.9])) self.assertEqual(set([m.speed or m in measures]), set([158.5])) wifis = session.query(Wifi).all() self.assertEqual(len(wifis), 2) self.assertEqual(set([w.key for w in wifis]), set(["ab1234567890", "cd3456789012"])) self.assertEqual(set([w.new_measures for w in wifis]), set([1, 3])) self.assertEqual(set([w.total_measures for w in wifis]), set([1, 3])) scores = session.query(Score).all() self.assertEqual(len(scores), 1) self.assertEqual(scores[0].key, SCORE_TYPE['new_wifi']) self.assertEqual(scores[0].value, 8) # test duplicate execution result = insert_measures_wifi.delay(entries, userid=1) self.assertEqual(result.get(), 4) # TODO this task isn't idempotent yet measures = session.query(WifiMeasure).all() self.assertEqual(len(measures), 8)
def test_blacklist_temporary_and_permanent(self): session = self.db_master_session # This test simulates a wifi that moves once a month, for 2 years. # The first 2 * PERMANENT_BLACKLIST_THRESHOLD (12) moves should be # temporary, forgotten after a week; after that it should be # permanently blacklisted. now = util.utcnow() # Station moves between these 4 points, all in the USA: points = [ # NYC (40.0, -74.0), # SF (37.0, -122.0), # Seattle (47.0, -122.0), # Miami (25.0, -80.0), ] N = 4 * PERMANENT_BLACKLIST_THRESHOLD for month in range(0, N): days_ago = (N - (month + 1)) * 30 time = now - timedelta(days=days_ago) time_enc = encode_datetime(time) measure = dict(key="ab1234567890", time=time_enc, lat=points[month % 4][0], lon=points[month % 4][1]) # insert_result is num-accepted-measures, override # utcnow to set creation date insert_result = insert_measures_wifi.delay([measure], utcnow=time_enc) # update_result is (num-stations, num-moving-stations) update_result = location_update_wifi.delay(min_new=1) # Assuming PERMANENT_BLACKLIST_THRESHOLD == 6: # # 0th insert will create the station # 1st insert will create first blacklist entry, delete station # 2nd insert will recreate the station at new position # 3rd insert will update blacklist, re-delete station # 4th insert will recreate the station at new position # 5th insert will update blacklist, re-delete station # 6th insert will recreate the station at new position # ... # 11th insert will make blacklisting permanent, re-delete station # 12th insert will not recreate station # 13th insert will not recreate station # ... # 23rd insert will not recreate station bl = session.query(WifiBlacklist).all() if month == 0: self.assertEqual(len(bl), 0) else: self.assertEqual(len(bl), 1) # force the blacklist back in time to whenever the # measure was supposedly inserted. bl = bl[0] bl.time = time session.add(bl) session.commit() if month < N / 2: # We still haven't exceeded the threshold, so the # measurement was admitted. self.assertEqual(insert_result.get(), 1) self.assertEqual(session.query(WifiMeasure).count(), month + 1) if month % 2 == 0: # The station was (re)created. self.assertEqual(update_result.get(), (1, 0)) # One wifi record should exist. self.assertEqual(session.query(Wifi).count(), 1) else: # The station existed and was seen moving, # thereby activating the blacklist. self.assertEqual(update_result.get(), (1, 1)) self.assertEqual(bl.count, ((month + 1) / 2)) self.assertEqual(session.query(WifiBlacklist).count(), 1) self.assertEqual(session.query(Wifi).count(), 0) # Try adding one more measurement 1 day later # to be sure it is dropped by the now-active blacklist. next_day = encode_datetime(time + timedelta(days=1)) measure['time'] = next_day self.assertEqual( 0, insert_measures_wifi.delay([measure], utcnow=next_day).get()) else: # Blacklist has exceeded threshold, gone to "permanent" mode, # so no measures accepted, no stations seen. self.assertEqual(insert_result.get(), 0) self.assertEqual(update_result.get(), 0)
def test_insert_measures(self): session = self.db_master_session time = util.utcnow() - timedelta(days=1) mcc = FRANCE_MCC session.add( Cell(radio=RADIO_TYPE['gsm'], mcc=mcc, mnc=2, lac=3, cid=4, psc=5, new_measures=2, total_measures=5)) session.add(Score(userid=1, key=SCORE_TYPE['new_cell'], value=7)) session.flush() measure = dict( created=encode_datetime(time), lat=PARIS_LAT, lon=PARIS_LON, time=encode_datetime(time), accuracy=0, altitude=0, altitude_accuracy=0, radio=RADIO_TYPE['gsm'], ) entries = [ # Note that this first entry will be skipped as it does # not include (lac, cid) or (psc) { "mcc": mcc, "mnc": 2, "signal": -100 }, { "mcc": mcc, "mnc": 2, "lac": 3, "cid": 4, "psc": 5, "asu": 8 }, { "mcc": mcc, "mnc": 2, "lac": 3, "cid": 4, "psc": 5, "asu": 8 }, { "mcc": mcc, "mnc": 2, "lac": 3, "cid": 4, "psc": 5, "asu": 15 }, { "mcc": mcc, "mnc": 2, "lac": 3, "cid": 7, "psc": 5 }, ] for e in entries: e.update(measure) result = insert_measures_cell.delay(entries, userid=1) self.assertEqual(result.get(), 4) measures = session.query(CellMeasure).all() self.assertEqual(len(measures), 4) self.assertEqual(set([m.mcc for m in measures]), set([mcc])) self.assertEqual(set([m.mnc for m in measures]), set([2])) self.assertEqual(set([m.asu for m in measures]), set([-1, 8, 15])) self.assertEqual(set([m.psc for m in measures]), set([5])) self.assertEqual(set([m.signal for m in measures]), set([0])) cells = session.query(Cell).all() self.assertEqual(len(cells), 2) self.assertEqual(set([c.mcc for c in cells]), set([mcc])) self.assertEqual(set([c.mnc for c in cells]), set([2])) self.assertEqual(set([c.lac for c in cells]), set([3])) self.assertEqual(set([c.cid for c in cells]), set([4, 7])) self.assertEqual(set([c.psc for c in cells]), set([5])) self.assertEqual(set([c.new_measures for c in cells]), set([1, 5])) self.assertEqual(set([c.total_measures for c in cells]), set([1, 8])) scores = session.query(Score).all() self.assertEqual(len(scores), 1) self.assertEqual(scores[0].key, SCORE_TYPE['new_cell']) self.assertEqual(scores[0].value, 8) # test duplicate execution result = insert_measures_cell.delay(entries, userid=1) self.assertEqual(result.get(), 4) # TODO this task isn't idempotent yet measures = session.query(CellMeasure).all() self.assertEqual(len(measures), 8)