Beispiel #1
0
    def test_geoip_match(self):
        app = self.app
        session = self.db_master_session
        cell = Cell()
        cell.lat = PARIS_LAT
        cell.lon = PARIS_LON
        cell.radio = 0
        cell.mcc = FRANCE_MCC
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        cell.total_measures = 1
        cell.new_measures = 0

        session.add(cell)
        session.commit()

        res = app.post_json('/v1/geosubmit?key=test',
                            {'items': [{"latitude": PARIS_LAT + 0.1,
                                        "longitude": PARIS_LON + 0.1,
                                        "accuracy": 12.4,
                                        "radioType": "gsm",
                                        "cellTowers": [{
                                            "cellId": 1234,
                                            "locationAreaCode": 2,
                                            "mobileCountryCode": FRANCE_MCC,
                                            "mobileNetworkCode": 1,
                                        }]},
                                       {"latitude": PARIS_LAT - 0.1,
                                        "longitude": PARIS_LON - 0.1,
                                        "accuracy": 22.4,
                                        "radioType": "gsm",
                                        "cellTowers": [{
                                            "cellId": 2234,
                                            "locationAreaCode": 22,
                                            "mobileCountryCode": FRANCE_MCC,
                                            "mobileNetworkCode": 2,
                                        }]}]},
                            extra_environ={'HTTP_X_FORWARDED_FOR': PARIS_IP},
                            status=200)

        # check that we get an empty response
        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {})

        # check that two new CellMeasure records are created
        self.assertEquals(2, session.query(CellMeasure).count())
        cm1 = session.query(CellMeasure).filter(
            CellMeasure.cid == 1234).count()
        cm2 = session.query(CellMeasure).filter(
            CellMeasure.cid == 2234).count()
        self.assertEquals(1, cm1)
        self.assertEquals(1, cm2)
Beispiel #2
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_slave_session
        cell = Cell()
        cell.lat = 123456781
        cell.lon = 234567892
        cell.radio = 0
        cell.mcc = 123
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        session.add(cell)
        session.commit()

        res = app.post_json(
            '/v1/geolocate?key=test', {
                "radioType": "gsm",
                "cellTowers": [
                    {"mobileCountryCode": 123, "mobileNetworkCode": 1,
                     "locationAreaCode": 2, "cellId": 1234},
                ]},
            status=200)
        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.body, '{"location": {"lat": 12.3456781, '
                                   '"lng": 23.4567892}, "accuracy": 35000.0}')
Beispiel #3
0
    def test_ok_cell(self):
        app = self.app
        session = self.get_session()
        cell = Cell()
        cell.lat = PARIS_LAT
        cell.lon = PARIS_LON
        cell.radio = RADIO_TYPE['gsm']
        cell.mcc = FRANCE_MCC
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        session.add(cell)
        session.commit()

        res = app.post_json(
            '%s?key=test' % self.url, {
                "radioType": "gsm",
                "cellTowers": [
                    {"mobileCountryCode": FRANCE_MCC,
                     "mobileNetworkCode": 1,
                     "locationAreaCode": 2,
                     "cellId": 1234},
                ]},
            status=200)

        self.check_stats(
            counter=[self.metric_url + '.200', self.metric + '.api_key.test']
        )

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {"location": {"lat": PARIS_LAT,
                                                 "lng": PARIS_LON},
                                    "accuracy": CELL_MIN_ACCURACY})
Beispiel #4
0
    def test_ok_cell_radio_in_celltowers(self):
        app = self.app
        session = self.db_slave_session
        cell = Cell()
        cell.lat = 123456781
        cell.lon = 234567892
        cell.radio = 0
        cell.mcc = 123
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        session.add(cell)
        session.commit()

        res = app.post_json(
            '/v1/geolocate?key=test', {
                "cellTowers": [
                    {"radio": "gsm",
                     "mobileCountryCode": 123,
                     "mobileNetworkCode": 1,
                     "locationAreaCode": 2,
                     "cellId": 1234},
                ]},
            status=200)

        self.check_expected_heka_messages(
            counter=['http.request', 'geolocate.api_key.test']
        )

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {"location": {"lat": 12.3456781,
                                                 "lng": 23.4567892},
                                    "accuracy": CELL_MIN_ACCURACY})
Beispiel #5
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_slave_session
        cell = Cell()
        cell.lat = 123456781
        cell.lon = 234567892
        cell.radio = 0
        cell.mcc = 123
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        session.add(cell)
        session.commit()

        res = app.post_json(
            '/v1/geolocate?key=test', {
                "radioType": "gsm",
                "cellTowers": [
                    {"mobileCountryCode": 123, "mobileNetworkCode": 1,
                     "locationAreaCode": 2, "cellId": 1234},
                ]},
            status=200)

        find_msg = self.find_heka_messages
        self.assertEquals(
            len(find_msg('counter', 'http.request')), 1)
        self.assertEqual(1, len(find_msg('counter', 'geolocate.api_key.test')))

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {"location": {"lat": 12.3456781,
                                                 "lng": 23.4567892},
                                    "accuracy": 35000.0})
Beispiel #6
0
 def test_ok_cell_radio_in_celltowers_dupes(self):
     # This test covered a bug related to FxOS calling the
     # geolocate API incorrectly.
     app = self.app
     session = self.get_session()
     cell = Cell()
     cell.lat = PARIS_LAT
     cell.lon = PARIS_LON
     cell.radio = 0
     cell.mcc = FRANCE_MCC
     cell.mnc = 1
     cell.lac = 2
     cell.cid = 1234
     session.add(cell)
     session.commit()
     res = app.post_json(
         '%s?key=test' % self.url, {
             "cellTowers": [
                 {"radio": "gsm",
                  "mobileCountryCode": FRANCE_MCC,
                  "mobileNetworkCode": 1,
                  "locationAreaCode": 2,
                  "cellId": 1234},
                 {"radio": "gsm",
                  "mobileCountryCode": FRANCE_MCC,
                  "mobileNetworkCode": 1,
                  "locationAreaCode": 2,
                  "cellId": 1234},
             ]},
         status=200)
     self.assertEqual(res.content_type, 'application/json')
     self.assertEqual(res.json, {"location": {"lat": PARIS_LAT,
                                              "lng": PARIS_LON},
                                 "accuracy": CELL_MIN_ACCURACY})
Beispiel #7
0
    def test_removal_updates_lac(self):
        session = self.session
        keys = dict(radio=Radio.cdma, mcc=1, mnc=1, lac=1)

        # setup: build LAC as above
        self.add_line_of_cells_and_scan_lac()

        # confirm we got one
        lac = session.query(CellArea).filter(CellArea.lac == 1).first()

        self.assertEqual(lac.lat, 4.5)
        self.assertEqual(lac.lon, 4.5)
        self.assertEqual(lac.range, 723001)

        # Remove cells one by one checking that the LAC
        # changes shape along the way.
        steps = [
            ((5.0, 5.0), 644242),
            ((5.5, 5.5), 565475),
            ((6.0, 6.0), 486721),
            ((6.5, 6.5), 408000),
            ((7.0, 7.0), 329334),
            ((7.5, 7.5), 250743),
            ((8.0, 8.0), 172249),
            ((8.5, 8.5), 93871),
            ((9.0, 9.0), 15630),
        ]
        for i in range(9):
            session.expire(lac)
            k = Cell.to_hashkey(cid=i, **keys)
            result = remove_cell.delay([k])
            self.assertEqual(1, result.get())
            result = scan_areas.delay()
            self.assertEqual(1, result.get())
            lac = session.query(CellArea).filter(CellArea.lac == 1).first()

            self.assertEqual(lac.lat, steps[i][0][0])
            self.assertEqual(lac.lon, steps[i][0][1])
            self.assertEqual(lac.range, steps[i][1])

        # Remove final cell, check LAC is gone
        k = Cell.to_hashkey(cid=9, **keys)
        result = remove_cell.delay([k])
        self.assertEqual(1, result.get())
        result = scan_areas.delay()
        self.assertEqual(1, result.get())
        lac = session.query(CellArea).filter(CellArea.lac == 1).first()
        self.assertEqual(lac, None)
Beispiel #8
0
    def test_local_export(self):
        session = self.db_master_session
        cell_fixture_fields = ('radio', 'cid', 'lat', 'lon', 'mnc', 'mcc',
                               'lac')
        cell_key = {'radio': RADIO_TYPE['gsm'], 'mcc': 1, 'mnc': 2, 'lac': 4}
        cells = set()

        for cid in range(190, 200):
            cell = dict(cid=cid, lat=1.0, lon=2.0, **cell_key)
            session.add(Cell(**cell))

            cell['radio'] = 'GSM'
            cell_strings = [(field, str(value))
                            for (field, value) in cell.items()]
            cell_tuple = tuple(sorted(cell_strings))
            cells.add(cell_tuple)

        # add one incomplete / unprocessed cell
        session.add(Cell(cid=210, lat=None, lon=None, **cell_key))
        session.commit()

        with selfdestruct_tempdir() as temp_dir:
            path = os.path.join(temp_dir, 'export.csv.gz')
            cond = Cell.__table__.c.lat.isnot(None)
            write_stations_to_csv(session, Cell.__table__, CELL_COLUMNS, cond,
                                  path, make_cell_export_dict, CELL_FIELDS)

            with GzipFile(path, 'rb') as gzip_file:
                reader = csv.DictReader(gzip_file, CELL_FIELDS)

                header = reader.next()
                self.assertTrue('area' in header.values())
                self.assertEqual(header, CELL_HEADER_DICT)

                exported_cells = set()
                for exported_cell in reader:
                    exported_cell_filtered = [
                        (field, value)
                        for (field, value) in exported_cell.items()
                        if field in cell_fixture_fields
                    ]
                    exported_cell = tuple(sorted(exported_cell_filtered))
                    exported_cells.add(exported_cell)

                self.assertEqual(cells, exported_cells)
Beispiel #9
0
    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(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]))
Beispiel #10
0
def remove_cell(self, cell_keys):
    cells_removed = 0
    redis_client = self.app.redis_client
    with self.db_session() as session:
        changed_lacs = set()

        for k in cell_keys:
            key = Cell.to_hashkey(k)
            query = session.query(Cell).filter(*Cell.joinkey(key))
            cells_removed += query.delete()
            changed_lacs.add(CellArea.to_hashkey(key))

        if changed_lacs:
            session.on_post_commit(enqueue_lacs, redis_client, changed_lacs,
                                   UPDATE_KEY['cell_lac'])

        session.commit()
    return cells_removed
Beispiel #11
0
    def test_cell_location_update(self):
        from ichnaea.tasks import cell_location_update
        now = datetime.utcnow()
        before = now - timedelta(days=1)
        session = self.db_master_session
        k1 = dict(radio=1, mcc=1, mnc=2, lac=3, cid=4)
        k2 = dict(radio=1, mcc=1, mnc=2, lac=6, cid=8)
        k3 = dict(radio=1, mcc=1, mnc=2, lac=-1, cid=-1)
        data = [
            Cell(new_measures=3, total_measures=5, **k1),
            CellMeasure(lat=10000000, lon=10000000, **k1),
            CellMeasure(lat=10020000, lon=10030000, **k1),
            CellMeasure(lat=10040000, lon=10060000, **k1),
            # The lac, cid are invalid and should be skipped
            CellMeasure(lat=15000000, lon=15000000, **k3),
            CellMeasure(lat=15020000, lon=15030000, **k3),
            Cell(lat=20000000,
                 lon=20000000,
                 new_measures=2,
                 total_measures=4,
                 **k2),
            # the lat/lon is bogus and mismatches the line above on purpose
            # to make sure old measures are skipped
            CellMeasure(lat=-10000000, lon=-10000000, created=before, **k2),
            CellMeasure(lat=-10000000, lon=-10000000, created=before, **k2),
            CellMeasure(lat=20020000, lon=20040000, **k2),
            CellMeasure(lat=20020000, lon=20040000, **k2),
        ]
        session.add_all(data)
        session.commit()

        result = cell_location_update.delay(min_new=1)
        self.assertEqual(result.get(), (2, 0))

        cells = session.query(Cell).filter(Cell.cid != CELLID_LAC).all()
        self.assertEqual(len(cells), 2)
        self.assertEqual([c.new_measures for c in cells], [0, 0])
        for cell in cells:
            if cell.cid == 4:
                self.assertEqual(cell.lat, 10020000)
                self.assertEqual(cell.lon, 10030000)
            elif cell.cid == 8:
                self.assertEqual(cell.lat, 20010000)
                self.assertEqual(cell.lon, 20020000)
Beispiel #12
0
    def test_location_update_cell(self):
        now = util.utcnow()
        before = now - timedelta(days=1)
        session = self.db_master_session
        k1 = dict(radio=1, mcc=1, mnc=2, lac=3, cid=4)
        k2 = dict(radio=1, mcc=1, mnc=2, lac=6, cid=8)
        k3 = dict(radio=1, mcc=1, mnc=2, lac=-1, cid=-1)
        data = [
            Cell(new_measures=3, total_measures=5, **k1),
            CellMeasure(lat=1.0, lon=1.0, **k1),
            CellMeasure(lat=1.002, lon=1.003, **k1),
            CellMeasure(lat=1.004, lon=1.006, **k1),
            # The lac, cid are invalid and should be skipped
            CellMeasure(lat=1.5, lon=1.5, **k3),
            CellMeasure(lat=1.502, lon=1.503, **k3),
            Cell(lat=2.0, lon=2.0, new_measures=2, total_measures=4, **k2),
            # the lat/lon is bogus and mismatches the line above on purpose
            # to make sure old measures are skipped
            CellMeasure(lat=-1.0, lon=-1.0, created=before, **k2),
            CellMeasure(lat=-1.0, lon=-1.0, created=before, **k2),
            CellMeasure(lat=2.002, lon=2.004, **k2),
            CellMeasure(lat=2.002, lon=2.004, **k2),
        ]
        session.add_all(data)
        session.commit()

        result = location_update_cell.delay(min_new=1)
        self.assertEqual(result.get(), (2, 0))
        self.check_stats(
            total=2,
            timer=['task.data.location_update_cell'],
            gauge=['task.data.location_update_cell.new_measures_1_100'],
        )

        cells = session.query(Cell).filter(Cell.cid != CELLID_LAC).all()
        self.assertEqual(len(cells), 2)
        self.assertEqual([c.new_measures for c in cells], [0, 0])
        for cell in cells:
            if cell.cid == 4:
                self.assertEqual(cell.lat, 1.002)
                self.assertEqual(cell.lon, 1.003)
            elif cell.cid == 8:
                self.assertEqual(cell.lat, 2.001)
                self.assertEqual(cell.lon, 2.002)
Beispiel #13
0
    def test_inconsistent_cell_radio_in_towers(self):
        app = self.app
        session = self.db_slave_session
        cells = [
            Cell(lat=PARIS_LAT,
                 lon=PARIS_LON,
                 radio=RADIO_TYPE['gsm'],
                 mcc=FRANCE_MCC, mnc=1, lac=2, cid=3,
                 range=10000),
            Cell(lat=PARIS_LAT + 0.002,
                 lon=PARIS_LON + 0.004,
                 radio=RADIO_TYPE['umts'],
                 mcc=FRANCE_MCC, mnc=2, lac=3, cid=4,
                 range=2000),
        ]
        session.add_all(cells)
        session.commit()

        res = app.post_json(
            '%s?key=test' % self.url, {
                "radioType": "cdma",
                "cellTowers": [
                    {"radio": "gsm",
                     "mobileCountryCode": FRANCE_MCC,
                     "mobileNetworkCode": 1,
                     "locationAreaCode": 2,
                     "cellId": 3},
                    {"radio": "wcdma",
                     "mobileCountryCode": FRANCE_MCC,
                     "mobileNetworkCode": 2,
                     "locationAreaCode": 3,
                     "cellId": 4},
                ]},
            status=200)

        self.check_stats(
            counter=[self.metric_url + '.200', self.metric + '.api_key.test']
        )

        self.assertEqual(res.content_type, 'application/json')
        location = res.json['location']
        self.assertAlmostEquals(location['lat'], PARIS_LAT + 0.002)
        self.assertAlmostEquals(location['lng'], PARIS_LON + 0.004)
        self.assertEqual(res.json['accuracy'], CELL_MIN_ACCURACY)
Beispiel #14
0
    def test_cell_multiple_lac_hit(self):
        session = self.db_slave_session
        lat = PARIS_LAT
        lon = PARIS_LON
        gsm = RADIO_TYPE['gsm']

        key = dict(mcc=FRANCE_MCC, mnc=2, lac=3)
        key2 = dict(mcc=FRANCE_MCC, mnc=2, lac=4)

        expected_lac = CellArea(
            lat=lat + 0.2, lon=lon + 0.2, radio=gsm,
            range=20000, **key)

        data = [
            Cell(lat=lat + 0.02, lon=lon + 0.02, radio=gsm,
                 cid=4, range=2000, **key2),
            Cell(lat=lat + 0.04, lon=lon + 0.04, radio=gsm,
                 cid=5, range=3000, **key2),
            Cell(lat=lat + 0.2, lon=lon + 0.4, radio=gsm,
                 cid=5, range=1000, **key),
            CellArea(lat=lat, lon=lon, radio=gsm,
                     range=30000, **key2),
            expected_lac,
        ]
        session.add_all(data)
        session.flush()

        # We have two lacs, both with two cells, but only know about
        # one cell in one of them and two in the other.
        # The lac with two known cells wins and we use both their
        # positions to calculate the final result.
        result = self._make_query(data={
            "cell": [
                dict(radio="gsm", cid=4, **key),
                dict(radio="gsm", cid=9, **key),
                dict(radio="gsm", cid=4, **key2),
                dict(radio="gsm", cid=5, **key2),
            ]
        })
        self.assertEqual(result,
                         {'lat': expected_lac.lat,
                          'lon': expected_lac.lon,
                          'accuracy': expected_lac.range})
Beispiel #15
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_slave_session
        key = dict(mcc=FRANCE_MCC, mnc=2, lac=3)
        lat = PARIS_LAT
        lon = PARIS_LON
        data = [
            Cell(lat=lat, lon=lon, range=1000, radio=2, cid=4, **key),
            Cell(lat=lat + 0.002,
                 lon=lon + 0.004,
                 range=1000,
                 radio=2,
                 cid=5,
                 **key),
        ]
        session.add_all(data)
        session.commit()

        res = app.post_json('/v1/search?key=test', {
            "radio":
            "gsm",
            "cell": [
                dict(radio="umts", cid=4, **key),
                dict(radio="umts", cid=5, **key),
            ]
        },
                            status=200)

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(
            res.json, {
                "status": "ok",
                "lat": PARIS_LAT + 0.001,
                "lon": PARIS_LON + 0.002,
                "accuracy": CELL_MIN_ACCURACY
            })

        self.check_stats(
            timer=[('request.v1.search', 1)],
            counter=[('search.api_key.test', 1), ('search.cell_hit', 1),
                     ('request.v1.search.200', 1),
                     ('search.api_log.test.cell_hit', 1)],
        )
Beispiel #16
0
    def test_unique_cell_histogram(self):
        session = self.db_master_session
        today = util.utcnow().date()
        one_day = (today - timedelta(1))
        two_days = (today - timedelta(2))
        long_ago = (today - timedelta(3))
        cells = [
            Cell(created=long_ago, radio=0, mcc=1, mnc=2, lac=3, cid=4),
            Cell(created=two_days, radio=2, mcc=1, mnc=2, lac=3, cid=4),
            Cell(created=two_days, radio=2, mcc=1, mnc=2, lac=3, cid=5),
            Cell(created=one_day, radio=0, mcc=2, mnc=2, lac=3, cid=5),
            Cell(created=today, radio=0, mcc=1, mnc=3, lac=3, cid=4),
        ]
        session.add_all(cells)
        session.commit()

        result = unique_cell_histogram.delay(ago=3)
        self.assertEqual(result.get(), 1)

        stats = session.query(Stat).order_by(Stat.time).all()
        self.assertEqual(len(stats), 1)
        self.assertEqual(stats[0].key, STAT_TYPE['unique_cell'])
        self.assertEqual(stats[0].time, long_ago)
        self.assertEqual(stats[0].value, 1)

        # fill up newer dates
        unique_cell_histogram.delay(ago=2).get()
        unique_cell_histogram.delay(ago=1).get()
        unique_cell_histogram.delay(ago=0).get()

        # test duplicate execution
        unique_cell_histogram.delay(ago=1).get()

        stats = session.query(Stat).order_by(Stat.time).all()
        self.assertEqual(len(stats), 4)
        self.assertEqual(stats[0].time, long_ago)
        self.assertEqual(stats[0].value, 1)
        self.assertEqual(stats[1].time, two_days)
        self.assertEqual(stats[1].value, 3)
        self.assertEqual(stats[2].time, one_day)
        self.assertEqual(stats[2].value, 4)
        self.assertEqual(stats[3].time, today)
        self.assertEqual(stats[3].value, 5)
Beispiel #17
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_master_session
        cell = Cell()
        cell.lat = PARIS_LAT + 0.1
        cell.lon = PARIS_LON + 0.1
        cell.radio = 0
        cell.mcc = FRANCE_MCC
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        cell.total_measures = 1
        cell.new_measures = 0

        session.add(cell)
        session.commit()

        res = app.post_json('/v1/geosubmit?key=test', {
                            "latitude": PARIS_LAT,
                            "longitude": PARIS_LON,
                            "accuracy": 12.4,
                            "radioType": "gsm",
                            "cellTowers": [{
                                "cellId": 1234,
                                "locationAreaCode": 2,
                                "mobileCountryCode": FRANCE_MCC,
                                "mobileNetworkCode": 1,
                            }]},
                            status=200)

        # check that we get back a location
        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {"location": {"lat": PARIS_LAT,
                                                 "lng": PARIS_LON},
                                    "accuracy": 12.4})

        cell = session.query(Cell).first()
        self.assertEqual(2, cell.total_measures)
        self.assertEqual(1, cell.new_measures)

        # check that one new CellMeasure record is created
        self.assertEquals(1, session.query(CellMeasure).count())
Beispiel #18
0
    def test_lac_miss(self):
        session = self.db_slave_session
        key = dict(mcc=FRANCE_MCC, mnc=2, lac=3)
        lat = PARIS_LAT
        lon = PARIS_LON
        gsm = RADIO_TYPE['gsm']
        data = [
            Cell(lat=lat, lon=lon, radio=gsm, cid=4, **key),
            Cell(lat=lat + 0.002, lon=lon + 0.004, radio=gsm, cid=5, **key),
            Cell(lat=1.006, lon=1.006, radio=gsm, cid=6, **key),
            CellArea(lat=1.0026666, lon=1.0033333, radio=gsm,
                     range=50000, **key),
        ]
        session.add_all(data)
        session.flush()

        result = self._make_query(
            data={"cell": [dict(radio="gsm", mcc=FRANCE_MCC,
                                mnc=2, lac=4, cid=5)]})
        self.assertTrue(result is None)
Beispiel #19
0
    def test_cell_multiple_lac_hit(self):
        session = self.db_slave_session
        lat = PARIS_LAT
        lon = PARIS_LON
        gsm = RADIO_TYPE['gsm']

        key = dict(mcc=FRANCE_MCC, mnc=2, lac=3)
        key2 = dict(mcc=FRANCE_MCC, mnc=2, lac=4)

        data = [
            Cell(lat=lat + 0.2, lon=lon + 0.2, radio=gsm,
                 cid=CELLID_LAC, range=20000, **key),
            Cell(lat=lat + 0.2, lon=lon + 0.4, radio=gsm,
                 cid=5, range=1000, **key),
            Cell(lat=lat, lon=lon, radio=gsm,
                 cid=CELLID_LAC, range=30000, **key2),
            Cell(lat=lat + 0.02, lon=lon + 0.02, radio=gsm,
                 cid=4, range=2000, **key2),
            Cell(lat=lat + 0.04, lon=lon + 0.04, radio=gsm,
                 cid=5, range=3000, **key2),
        ]
        session.add_all(data)
        session.flush()

        # We have two lacs, both with two cells, but only know about
        # one cell in one of them and two in the other.
        # The lac with two known cells wins and we use both their
        # positions to calculate the final result.
        result = locate.search_all_sources(
            session, 'm',
            {"cell": [
                dict(radio="gsm", cid=4, **key),
                dict(radio="gsm", cid=9, **key),
                dict(radio="gsm", cid=4, **key2),
                dict(radio="gsm", cid=5, **key2),
            ]})

        self.assertEqual(result,
                         {'lat': PARIS_LAT + 0.03,
                          'lon': PARIS_LON + 0.03,
                          'accuracy': CELL_MIN_ACCURACY})
Beispiel #20
0
    def test_scan_areas_race_with_location_update(self):
        session = self.session

        # First batch of cell observations for CID 1
        keys = dict(radio=Radio.cdma, mcc=1, mnc=1, lac=1, cid=1)
        cell = Cell(new_measures=4, total_measures=1, **keys)
        observations = [
            CellObservation(lat=1.0, lon=1.0, **keys),
            CellObservation(lat=1.0, lon=1.0, **keys),
            CellObservation(lat=1.0, lon=1.0, **keys),
            CellObservation(lat=1.0, lon=1.0, **keys),
        ]
        session.add(cell)
        session.add_all(observations)
        session.commit()

        # Periodic location_update_cell runs and updates CID 1
        # to have a location, inserts LAC 1 with new_measures=1
        # which will be picked up by the next scan_lac.
        result = location_update_cell.delay(min_new=1)
        self.assertEqual(result.get(), (1, 0))

        # Second batch of cell observations for CID 2
        keys['cid'] = 2
        cell = Cell(new_measures=4, total_measures=1, **keys)
        observations = [
            CellObservation(lat=1.0, lon=1.0, **keys),
            CellObservation(lat=1.0, lon=1.0, **keys),
            CellObservation(lat=1.0, lon=1.0, **keys),
            CellObservation(lat=1.0, lon=1.0, **keys),
        ]
        session.add(cell)
        session.add_all(observations)
        session.commit()

        # Periodic LAC scan runs, picking up LAC 1; this could
        # accidentally pick up CID 2, but it should not since it
        # has not had its location updated yet. If there's no
        # exception here, CID 2 is properly ignored.
        scan_areas.delay()
Beispiel #21
0
    def test_cell_ignore_invalid_lac_cid(self):
        schema = ValidCellKeySchema()
        session = self.db_slave_session
        lat = PARIS_LAT
        lon = PARIS_LON
        gsm = RADIO_TYPE['gsm']
        lte = RADIO_TYPE['lte']

        key = dict(mcc=FRANCE_MCC, mnc=2, lac=3)
        ignored_key = dict(
            mcc=FRANCE_MCC, mnc=2,
            lac=schema.fields['lac'].missing,
            cid=schema.fields['cid'].missing)

        data = [
            Cell(lat=lat, lon=lon, range=1000,
                 radio=gsm, cid=4, **key),
            Cell(lat=lat + 0.002, lon=lon + 0.004, range=1000,
                 radio=gsm, cid=5, **key),
            Cell(lat=lat, lon=lon, range=1000,
                 radio=gsm, **ignored_key),
            Cell(lat=lat + 0.002, lon=lon + 0.004, range=1000,
                 radio=lte, **ignored_key),
        ]
        session.add_all(data)
        session.flush()

        result = self._make_query(data={
            "cell": [
                dict(radio="gsm", cid=4, **key),
                dict(radio="gsm", cid=5, **key),

                dict(radio="gsm", cid=5, mcc=FRANCE_MCC, mnc=2, lac=-1),
                dict(radio="gsm", cid=-1, mcc=FRANCE_MCC, mnc=2, lac=3),
            ]
        })
        self.assertEqual(result,
                         {'lat': PARIS_LAT + 0.001,
                          'lon': PARIS_LON + 0.002,
                          'accuracy': CELL_MIN_ACCURACY})
Beispiel #22
0
    def test_cell_disagrees_with_lac(self):
        # This test checks that when a cell is at a lat/lon that
        # is not in the LAC associated with it, we drop back
        # to the LAC. This likely represents some kind of internal
        # database consistency error, but it might also just be a
        # new cell that hasn't been integrated yet or something.

        session = self.db_slave_session
        key = dict(mcc=BRAZIL_MCC, mnc=VIVO_MNC, lac=12345)
        data = [
            Cell(lat=PORTO_ALEGRE_LAT,
                 lon=PORTO_ALEGRE_LON,
                 radio=RADIO_TYPE['gsm'], cid=6789, **key),
            Cell(lat=SAO_PAULO_LAT,
                 lon=SAO_PAULO_LON,
                 radio=RADIO_TYPE['gsm'], cid=CELLID_LAC, **key),
        ]
        session.add_all(data)
        session.flush()

        result = locate.search_all_sources(
            session, 'm',
            {"cell": [dict(radio="gsm", cid=6789, **key)]},
        )

        self.assertEqual(result,
                         {'lat': SAO_PAULO_LAT,
                          'lon': SAO_PAULO_LON,
                          'accuracy': LAC_MIN_ACCURACY})

        self.check_stats(
            counter=[
                ('m.anomaly.cell_cell_lac_mismatch', 1),
                ('m.country_from_mcc', 1),
                ('m.cell_lac_found', 1),
                ('m.cell_found', 1),
                ('m.cell_lac_hit', 1),
            ]
        )
Beispiel #23
0
    def test_lac_miss(self):
        app = self.app
        session = self.db_slave_session
        key = dict(mcc=1, mnc=2, lac=3)
        data = [
            Cell(lat=10000000, lon=10000000, radio=2, cid=4, **key),
            Cell(lat=10020000, lon=10040000, radio=2, cid=5, **key),
            Cell(lat=10060000, lon=10060000, radio=2, cid=6, **key),
            Cell(lat=10026666, lon=10033333, radio=2, cid=CELLID_LAC,
                 range=50000, **key),
        ]
        session.add_all(data)
        session.commit()

        res = app.post_json(
            '/v1/search?key=test',
            {"radio": "gsm", "cell": [
                dict(radio="umts", mcc=1, mnc=2, lac=4, cid=5),
            ]},
            status=200)
        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {"status": "not_found"})
Beispiel #24
0
    def test_cell_multiple_lac_lower_range_wins(self):
        session = self.db_slave_session
        lat = PARIS_LAT
        lon = PARIS_LON
        gsm = RADIO_TYPE['gsm']

        key = dict(mcc=FRANCE_MCC, mnc=2, lac=3)
        key2 = dict(mcc=FRANCE_MCC, mnc=2, lac=4)

        expected_lac = CellArea(
            lat=lat + 0.2, lon=lon + 0.2, radio=gsm,
            range=10000, **key)

        data = [
            Cell(lat=lat + 0.02, lon=lon + 0.02, radio=gsm,
                 cid=4, range=2000, **key2),
            Cell(lat=lat + 0.2, lon=lon + 0.4, radio=gsm,
                 cid=4, range=4000, **key),
            CellArea(lat=lat, lon=lon, radio=gsm,
                     range=20000, **key2),
            expected_lac,
        ]

        session.add_all(data)
        session.flush()

        # We have two lacs with each one known cell.
        # The lac with the smallest cell wins.
        result = self._make_query(data={
            "cell": [
                dict(radio="gsm", cid=4, **key),
                dict(radio="gsm", cid=4, **key2),
            ]
        })
        self.assertEqual(result,
                         {'lat': expected_lac.lat,
                          'lon': expected_lac.lon,
                          'accuracy': LAC_MIN_ACCURACY})
Beispiel #25
0
    def test_scan_lacs_remove(self):
        session = self.db_master_session
        redis_client = self.redis_client

        # create an orphaned lac entry
        key = dict(radio=1, mcc=1, mnc=1, lac=1, cid=CELLID_LAC)
        session.add(Cell(**key))
        session.flush()
        enqueue_lacs(session, redis_client, [CellKey(**key)])

        # after scanning the orphaned record gets removed
        self.assertEqual(scan_lacs.delay().get(), 1)
        lacs = session.query(Cell).filter(Cell.cid == CELLID_LAC).all()
        self.assertEqual(lacs, [])
Beispiel #26
0
    def __call__(self, cell_keys):
        cells_removed = 0
        changed_areas = set()
        area_queue = self.task.app.data_queues['update_cellarea']

        for key in cell_keys:
            query = Cell.querykey(self.session, key)
            cells_removed += query.delete()
            changed_areas.add(CellArea.to_hashkey(key))

        if changed_areas:
            area_queue.enqueue(changed_areas, pipe=self.pipe)

        return cells_removed
Beispiel #27
0
    def test_daily_export(self):
        session = self.db_master_session
        gsm = RADIO_TYPE['gsm']
        k = dict(radio=gsm, mcc=1, mnc=2, lac=4, lat=1.0, lon=2.0)
        for i in range(190, 200):
            session.add(Cell(cid=i, **k))
        session.commit()

        with mock_s3() as mock_key:
            export_modified_cells(bucket="localhost.bucket", hourly=False)
            pat = r"MLS-full-cell-export-\d+-\d+-\d+T000000\.csv\.gz"
            self.assertRegexpMatches(mock_key.key, pat)
            method = mock_key.set_contents_from_filename
            self.assertRegexpMatches(method.call_args[0][0], pat)
Beispiel #28
0
    def remove(self, cell_keys):
        cells_removed = 0
        changed_areas = set()

        for key in cell_keys:
            query = Cell.querykey(self.session, key)
            cells_removed += query.delete()
            changed_areas.add(CellArea.to_hashkey(key))

        if changed_areas:
            self.session.on_post_commit(enqueue_areas, self.redis_client,
                                        changed_areas, UPDATE_KEY['cell_lac'])

        return cells_removed
Beispiel #29
0
    def test_cell_multiple_radio_lac_hit_with_min_lac_accuracy(self):
        session = self.db_slave_session
        lat = PARIS_LAT
        lon = PARIS_LON
        gsm = RADIO_TYPE['gsm']
        lte = RADIO_TYPE['lte']

        key = dict(mcc=FRANCE_MCC, mnc=3, lac=4)
        key2 = dict(mcc=FRANCE_MCC, mnc=2, lac=3)

        expected_lac = CellArea(
            lat=lat + 0.2, lon=lon + 0.2, radio=gsm,
            range=3000, **key)

        data = [
            Cell(lat=lat + 0.01, lon=lon + 0.02, radio=lte,
                 cid=4, range=2000, **key2),
            Cell(lat=lat + 0.2, lon=lon + 0.4, radio=gsm,
                 cid=5, range=500, **key),
            CellArea(lat=lat, lon=lon, radio=lte,
                     range=10000, **key2),
            expected_lac,
        ]
        session.add_all(data)
        session.flush()

        # GSM lac-only hit (cid 9 instead of 5) and a LTE cell hit
        result = self._make_query(data={
            "cell": [
                dict(radio="gsm", cid=9, **key),
                dict(radio="lte", cid=4, **key2),
            ]
        })
        self.assertEqual(result,
                         {'lat': expected_lac.lat,
                          'lon': expected_lac.lon,
                          'accuracy': LAC_MIN_ACCURACY})
Beispiel #30
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_slave_session
        cell = Cell()
        cell.lat = PARIS_LAT
        cell.lon = PARIS_LON
        cell.radio = RADIO_TYPE['gsm']
        cell.mcc = FRANCE_MCC
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        cell.range = 1000
        session.add(cell)
        session.commit()

        res = app.post_json(
            '%s?key=test' % self.url, {
                "radioType": "gsm",
                "cellTowers": [
                    {"mobileCountryCode": FRANCE_MCC,
                     "mobileNetworkCode": 1,
                     "locationAreaCode": 2,
                     "cellId": 1234},
                ]},
            status=200)

        self.check_stats(
            counter=[self.metric_url + '.200',
                     self.metric + '.api_key.test',
                     self.metric + '.api_log.test.cell_hit']
        )

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {"location": {"lat": PARIS_LAT,
                                                 "lng": PARIS_LON},
                                    "accuracy": CELL_MIN_ACCURACY})
Beispiel #31
0
    def test_ok_cell_radio_in_celltowers(self):
        # This test covers a bug related to FxOS calling the
        # geolocate API incorrectly.
        app = self.app
        session = self.db_slave_session
        cell = Cell()
        cell.lat = PARIS_LAT
        cell.lon = PARIS_LON
        cell.radio = 0
        cell.mcc = FRANCE_MCC
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        cell.range = 1000
        session.add(cell)
        session.commit()

        res = app.post_json(
            '%s?key=test' % self.url, {
                "cellTowers": [
                    {"radio": "gsm",
                     "mobileCountryCode": FRANCE_MCC,
                     "mobileNetworkCode": 1,
                     "locationAreaCode": 2,
                     "cellId": 1234},
                ]},
            status=200)

        self.check_stats(
            counter=[self.metric_url + '.200', self.metric + '.api_key.test']
        )

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {"location": {"lat": PARIS_LAT,
                                                 "lng": PARIS_LON},
                                    "accuracy": CELL_MIN_ACCURACY})
Beispiel #32
0
    def test_cell_agrees_with_lac(self):
        # This test checks that when a cell is at a lat/lon that
        # is inside its enclosing LAC, we accept it and tighten
        # our accuracy accordingly.

        session = self.db_slave_session
        key = dict(mcc=BRAZIL_MCC, mnc=VIVO_MNC, lac=12345)
        data = [
            Cell(lat=SAO_PAULO_LAT + 0.002,
                 lon=SAO_PAULO_LON + 0.002,
                 radio=RADIO_TYPE['gsm'], cid=6789, **key),
            Cell(lat=SAO_PAULO_LAT,
                 lon=SAO_PAULO_LON,
                 radio=RADIO_TYPE['gsm'], cid=CELLID_LAC, **key),
        ]
        session.add_all(data)
        session.flush()

        result = locate.search_all_sources(
            session, 'm',
            {"cell": [dict(radio="gsm", cid=6789, **key)]},
        )

        self.assertEqual(result,
                         {'lat': SAO_PAULO_LAT + 0.002,
                          'lon': SAO_PAULO_LON + 0.002,
                          'accuracy': CELL_MIN_ACCURACY})

        self.check_stats(
            counter=[
                ('m.country_from_mcc', 1),
                ('m.cell_lac_found', 1),
                ('m.cell_found', 1),
                ('m.cell_hit', 1),
            ]
        )
Beispiel #33
0
    def test_inconsistent_cell_radio_in_towers(self):
        app = self.app
        session = self.db_slave_session
        cell = Cell()
        cell.lat = 123456781
        cell.lon = 234567892
        cell.radio = 0
        cell.mcc = 123
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        session.add(cell)
        session.commit()

        res = app.post_json(
            '/v1/geolocate?key=test', {
                "cellTowers": [
                    {"radio": "gsm",
                     "mobileCountryCode": 123,
                     "mobileNetworkCode": 1,
                     "locationAreaCode": 2,
                     "cellId": 1234},
                    {"radio": "cdma",
                     "mobileCountryCode": 123,
                     "mobileNetworkCode": 1,
                     "locationAreaCode": 2,
                     "cellId": 1234},
                ]},
            status=400)

        self.check_expected_heka_messages(
            counter=['http.request', 'geolocate.api_key.test']
        )

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(
            res.json, {"error": {
                "errors": [{
                    "domain": "global",
                    "reason": "parseError",
                    "message": "Parse Error",
                }],
                "code": 400,
                "message": "Parse Error"
            }}
        )
Beispiel #34
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_slave_session
        key = dict(mcc=1, mnc=2, lac=3)
        data = [
            Cell(lat=10000000, lon=10000000, radio=2, cid=4, **key),
            Cell(lat=10020000, lon=10040000, radio=2, cid=5, **key),
        ]
        session.add_all(data)
        session.commit()

        res = app.post_json('/v1/search', {
            "radio":
            "gsm",
            "cell": [
                dict(radio="umts", cid=4, **key),
                dict(radio="umts", cid=5, **key),
            ]
        },
                            status=200)
        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(
            res.body, '{"status": "ok", "lat": 1.0010000, '
            '"lon": 1.0020000, "accuracy": 35000}')
Beispiel #35
0
    def test_cell_hit_ignores_lac(self):
        session = self.db_slave_session
        lat = PARIS_LAT
        lon = PARIS_LON
        key = dict(mcc=FRANCE_MCC, mnc=2, lac=3)
        data = [
            Cell(lat=lat, lon=lon, radio=2, cid=4, **key),
            Cell(lat=lat + 0.002, lon=lon + 0.004, radio=2, cid=5, **key),
            Cell(lat=lat + 0.006, lon=lon + 0.006, radio=2, cid=6, **key),
            Cell(lat=lat + 0.0026666,
                 lon=lon + 0.0033333, radio=2, cid=CELLID_LAC,
                 range=50000, **key),
        ]
        session.add_all(data)
        session.flush()

        result = locate.search_all_sources(
            session, 'm',
            {"cell": [dict(radio="umts", cid=5, **key)]})

        self.assertEqual(result,
                         {'lat': PARIS_LAT + 0.002,
                          'lon': PARIS_LON + 0.004,
                          'accuracy': CELL_MIN_ACCURACY})
Beispiel #36
0
    def test_geoip_mcc_mismatch(self):
        session = self.db_slave_session
        gsm = RADIO_TYPE['gsm']
        key = {'mcc': USA_MCC, 'mnc': 1, 'lac': 1, 'cid': 1}
        key2 = {'mcc': USA_MCC, 'mnc': 1, 'lac': 1, 'cid': CELLID_LAC}
        session.add(Cell(radio=gsm, lat=FREMONT_LAT, lon=FREMONT_LON, **key))
        session.add(Cell(radio=gsm, lat=FREMONT_LAT, lon=FREMONT_LON, **key2))
        session.flush()

        result = locate.search_all_sources(
            session, 'm',
            {'cell': [dict(radio='gsm', **key)]},
            client_addr=GB_IP, geoip_db=self.geoip_db)

        self.assertEqual(result,
                         {'lat': FREMONT_LAT,
                          'lon': FREMONT_LON,
                          'accuracy': CELL_MIN_ACCURACY})

        self.check_stats(
            counter=[
                'm.anomaly.geoip_mcc_mismatch',
            ],
        )
Beispiel #37
0
    def test_wifi_not_found_cell_fallback(self):
        app = self.app
        session = self.db_slave_session
        key = dict(mcc=1, mnc=2, lac=3)
        data = [
            Wifi(key="abcd", lat=30000000, lon=30000000),
            Cell(lat=10000000, lon=10000000, radio=2, cid=4, **key),
            Cell(lat=10020000, lon=10040000, radio=2, cid=5, **key),
        ]
        session.add_all(data)
        session.commit()

        res = app.post_json('/v1/search?key=test', {
            "radio":
            "gsm",
            "cell": [
                dict(radio="umts", cid=4, **key),
                dict(radio="umts", cid=5, **key),
            ],
            "wifi": [
                {
                    "key": "abcd"
                },
                {
                    "key": "cdef"
                },
            ]
        },
                            status=200)
        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {
            "status": "ok",
            "lat": 1.0010000,
            "lon": 1.0020000,
            "accuracy": 35000
        })
Beispiel #38
0
    def remove(self, cell_keys):
        cells_removed = 0
        changed_areas = set()

        for key in cell_keys:
            query = Cell.querykey(self.session, key)
            cells_removed += query.delete()
            changed_areas.add(CellArea.to_hashkey(key))

        if changed_areas:
            redis_key = self.task.app.data_queues['cell_area_update']
            self.session.on_post_commit(enqueue_areas, self.redis_client,
                                        changed_areas, redis_key)

        return cells_removed
Beispiel #39
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_slave_session
        key = dict(mcc=1, mnc=2, lac=3)
        data = [
            Cell(lat=10000000, lon=10000000, radio=2, cid=4, **key),
            Cell(lat=10020000, lon=10040000, radio=2, cid=5, **key),
        ]
        session.add_all(data)
        session.commit()

        res = app.post_json('/v1/search?key=test', {
            "radio":
            "gsm",
            "cell": [
                dict(radio="umts", cid=4, **key),
                dict(radio="umts", cid=5, **key),
            ]
        },
                            status=200)

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.json, {
            "status": "ok",
            "lat": 1.0010000,
            "lon": 1.0020000,
            "accuracy": 35000
        })

        self.check_expected_heka_messages(total=4,
                                          timer=[('http.request', {
                                              'url_path': '/v1/search'
                                          })],
                                          counter=[('search.api_key', 1),
                                                   ('search.cell_hit', 1),
                                                   ('http.request', 1)])
Beispiel #40
0
    def process_reports(self, reports, userid=None):
        malformed_reports = 0
        positions = set()
        observations = {'cell': [], 'wifi': []}
        obs_count = {
            'cell': {'upload': 0, 'drop': 0},
            'wifi': {'upload': 0, 'drop': 0},
        }
        new_station_count = {'cell': 0, 'wifi': 0}

        for report in reports:
            cell, wifi, malformed_obs = self.process_report(report)
            if cell:
                observations['cell'].extend(cell)
                obs_count['cell']['upload'] += len(cell)
            if wifi:
                observations['wifi'].extend(wifi)
                obs_count['wifi']['upload'] += len(wifi)
            if (cell or wifi):
                positions.add((report['lat'], report['lon']))
            else:
                malformed_reports += 1
            for name in ('cell', 'wifi'):
                obs_count[name]['drop'] += malformed_obs[name]

        # group by unique station key
        for name in ('cell', 'wifi'):
            station_keys = set()
            for obs in observations[name]:
                if name == 'cell':
                    station_keys.add(Cell.to_hashkey(obs))
                elif name == 'wifi':
                    station_keys.add(obs.mac)
            # determine scores for stations
            new_station_count[name] += self.new_stations(name, station_keys)

        for name, queue in (('cell', self.cell_queue),
                            ('wifi', self.wifi_queue)):
            if observations[name]:
                queue.enqueue(list(observations[name]), pipe=self.pipe)

        self.process_mapstat(positions)
        self.process_score(userid, positions, new_station_count)
        self.emit_stats(
            len(reports),
            malformed_reports,
            obs_count,
        )
Beispiel #41
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_slave_session
        cell = Cell()
        cell.lat = 123456781
        cell.lon = 234567892
        cell.radio = 0
        cell.mcc = 123
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        session.add(cell)
        session.commit()

        res = app.post_json('/v1/geolocate?key=test', {
            "radioType":
            "gsm",
            "cellTowers": [
                {
                    "mobileCountryCode": 123,
                    "mobileNetworkCode": 1,
                    "locationAreaCode": 2,
                    "cellId": 1234
                },
            ]
        },
                            status=200)

        self.check_expected_heka_messages(
            counter=['http.request', 'geolocate.api_key.test'])

        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(
            res.json, {
                "location": {
                    "lat": 12.3456781,
                    "lng": 23.4567892
                },
                "accuracy": 35000.0
            })
Beispiel #42
0
    def remove(self, cell_keys):
        cells_removed = 0
        changed_areas = set()

        for key in cell_keys:
            query = Cell.querykey(self.session, key)
            cells_removed += query.delete()
            changed_areas.add(CellArea.to_hashkey(key))

        if changed_areas:
            redis_key = self.task.app.data_queues['cell_area_update']
            self.session.on_post_commit(
                enqueue_areas,
                self.redis_client,
                changed_areas,
                redis_key)

        return cells_removed
Beispiel #43
0
    def new_stations(self, name, station_keys):
        if len(station_keys) == 0:
            return 0

        # assume all stations are unknown
        unknown_keys = set(station_keys)

        if name == 'wifi':
            # there is only one combined table structure
            shards = defaultdict(list)
            for mac in unknown_keys:
                shards[WifiShard.shard_model(mac)].append(mac)
            for shard, macs in shards.items():
                query = (self.session.query(shard.mac)
                                     .filter(shard.mac.in_(macs)))
                unknown_keys -= set([r.mac for r in query.all()])
        elif name == 'cell':
            # first check the station table, which is more likely to contain
            # stations
            station_iter = Cell.iterkeys(
                self.session,
                list(unknown_keys),
                # only load the columns required for the hashkey
                extra=lambda query: query.options(
                    load_only(*tuple(Cell._hashkey_cls._fields))))
            # subtract all stations which are found in the station table
            unknown_keys -= set([sta.hashkey() for sta in station_iter])
            if len(unknown_keys) == 0:  # pragma: no cover
                return 0

            # Only check the blocklist table for the still unknown keys.
            # There is no need to check for the already found keys again.
            block_iter = CellBlocklist.iterkeys(
                self.session,
                list(unknown_keys),
                # only load the columns required for the hashkey
                extra=lambda query: query.options(
                    load_only(*tuple(CellBlocklist._hashkey_cls._fields))))
            # subtract all stations which are found in the blocklist table
            unknown_keys -= set([block.hashkey() for block in block_iter])

        return len(unknown_keys)
Beispiel #44
0
    def test_ok_cell(self):
        app = self.app
        session = self.db_slave_session
        cell = Cell()
        cell.lat = 123456781
        cell.lon = 234567892
        cell.radio = 2
        cell.mcc = 123
        cell.mnc = 1
        cell.lac = 2
        cell.cid = 1234
        session.add(cell)
        session.commit()

        res = app.post_json('/v1/search',
                            {"radio": "gsm",
                             "cell": [{"radio": "umts", "mcc": 123, "mnc": 1,
                                       "lac": 2, "cid": 1234}]},
                            status=200)
        self.assertEqual(res.content_type, 'application/json')
        self.assertEqual(res.body, '{"status": "ok", "lat": 12.3456781, '
                                   '"lon": 23.4567892, "accuracy": 35000}')
Beispiel #45
0
def update_lac(self, radio, mcc, mnc, lac):

    with self.db_session() as session:

        # Select all the cells in this LAC that aren't the virtual
        # cell itself, and derive a bounding box for them.

        q = session.query(Cell).filter(
            Cell.radio == radio).filter(
            Cell.mcc == mcc).filter(
            Cell.mnc == mnc).filter(
            Cell.lac == lac).filter(
            Cell.cid != CELLID_LAC).filter(
            Cell.new_measures == 0).filter(
            Cell.lat.isnot(None)).filter(
            Cell.lon.isnot(None))

        cells = q.all()
        if len(cells) == 0:
            return

        points = [(to_degrees(c.lat),
                   to_degrees(c.lon)) for c in cells]
        min_lat = to_degrees(min([c.min_lat for c in cells]))
        min_lon = to_degrees(min([c.min_lon for c in cells]))
        max_lat = to_degrees(max([c.max_lat for c in cells]))
        max_lon = to_degrees(max([c.max_lon for c in cells]))

        bbox_points = [(min_lat, min_lon),
                       (min_lat, max_lon),
                       (max_lat, min_lon),
                       (max_lat, max_lon)]

        ctr = centroid(points)
        rng = range_to_points(ctr, bbox_points)

        # switch units back to DB preferred centimicrodegres angle
        # and meters distance.
        ctr_lat = from_degrees(ctr[0])
        ctr_lon = from_degrees(ctr[1])
        rng = int(round(rng * 1000.0))

        # Now create or update the LAC virtual cell

        q = session.query(Cell).filter(
            Cell.radio == radio).filter(
            Cell.mcc == mcc).filter(
            Cell.mnc == mnc).filter(
            Cell.lac == lac).filter(
            Cell.cid == CELLID_LAC)

        lac = q.first()

        if lac is None:
            lac = Cell(radio=radio,
                       mcc=mcc,
                       mnc=mnc,
                       lac=lac,
                       cid=CELLID_LAC,
                       lat=ctr_lat,
                       lon=ctr_lon,
                       range=rng)
        else:
            lac.new_measures = 0
            lac.lat = ctr_lat
            lac.lon = ctr_lon
            lac.range = rng

        session.commit()
Beispiel #46
0
def update_lac(self, radio, mcc, mnc, lac):
    try:
        utcnow = util.utcnow()
        with self.db_session() as session:
            # Select all the cells in this LAC that aren't the virtual
            # cell itself, and derive a bounding box for them.

            cell_query = session.query(Cell).filter(
                Cell.radio == radio).filter(
                Cell.mcc == mcc).filter(
                Cell.mnc == mnc).filter(
                Cell.lac == lac).filter(
                Cell.cid != CELLID_LAC).filter(
                Cell.lat.isnot(None)).filter(
                Cell.lon.isnot(None))

            cells = cell_query.all()

            lac_query = session.query(Cell).filter(
                Cell.radio == radio).filter(
                Cell.mcc == mcc).filter(
                Cell.mnc == mnc).filter(
                Cell.lac == lac).filter(
                Cell.cid == CELLID_LAC)

            if len(cells) == 0:
                # If there are no more underlying cells, delete the lac entry
                lac_query.delete()
            else:
                # Otherwise update the lac entry based on all the cells
                lac_obj = lac_query.first()

                points = [(c.lat, c.lon) for c in cells]
                min_lat = min([c.min_lat for c in cells])
                min_lon = min([c.min_lon for c in cells])
                max_lat = max([c.max_lat for c in cells])
                max_lon = max([c.max_lon for c in cells])

                bbox_points = [(min_lat, min_lon),
                               (min_lat, max_lon),
                               (max_lat, min_lon),
                               (max_lat, max_lon)]

                ctr = centroid(points)
                rng = range_to_points(ctr, bbox_points)

                # Switch units back to DB preferred centimicrodegres angle
                # and meters distance.
                ctr_lat = ctr[0]
                ctr_lon = ctr[1]
                rng = int(round(rng * 1000.0))

                # Now create or update the LAC virtual cell
                if lac_obj is None:
                    lac_obj = Cell(radio=radio,
                                   mcc=mcc,
                                   mnc=mnc,
                                   lac=lac,
                                   cid=CELLID_LAC,
                                   lat=ctr_lat,
                                   lon=ctr_lon,
                                   created=utcnow,
                                   modified=utcnow,
                                   range=rng,
                                   total_measures=len(cells))
                    session.add(lac_obj)
                else:
                    lac_obj.total_measures = len(cells)
                    lac_obj.lat = ctr_lat
                    lac_obj.lon = ctr_lon
                    lac_obj.modified = utcnow
                    lac_obj.range = rng

            session.commit()
    except Exception as exc:  # pragma: no cover
        self.heka_client.raven('error')
        raise self.retry(exc=exc)
Beispiel #47
0
    def __call__(self, batch=10):
        all_observations = self.data_queue.dequeue(batch=batch)
        drop_counter = defaultdict(int)
        added = 0
        new_stations = 0
        station_obs = defaultdict(list)

        for obs in all_observations:
            station_obs[Cell.to_hashkey(obs)].append(obs)

        if not station_obs:
            return (0, 0)

        stations = {}
        for station in Cell.iterkeys(self.session, list(station_obs.keys())):
            stations[station.hashkey()] = station

        blocklist = self.blocklisted_stations(station_obs.keys())

        new_station_values = []
        changed_station_values = []
        moving_stations = set()
        for station_key, observations in station_obs.items():
            blocked, first_blocked, block = blocklist.get(
                station_key, (False, None, None))

            if not any(observations):
                continue

            if blocked:
                # Drop observations for blocklisted stations.
                drop_counter['blocklisted'] += len(observations)
                continue

            station = stations.get(station_key, None)
            if station is None and not first_blocked:
                # We discovered an actual new never before seen station.
                new_stations += 1

            moving, new_values, changed_values = self.new_station_values(
                station, station_key, first_blocked, observations)
            if moving:
                moving_stations.add((station_key, block))
            else:
                added += len(observations)
                if new_values:
                    new_station_values.append(new_values)
                if changed_values:
                    changed_station_values.append(changed_values)

            # track potential updates to dependent areas
            self.add_area_update(station_key)

        if new_station_values:
            # do a batch insert of new stations
            stmt = Cell.__table__.insert(
                mysql_on_duplicate='total_measures = total_measures'  # no-op
            )
            # but limit the batch depending on each model
            ins_batch = Cell._insert_batch
            for i in range(0, len(new_station_values), ins_batch):
                batch_values = new_station_values[i:i + ins_batch]
                self.session.execute(stmt.values(batch_values))

        if changed_station_values:
            # do a batch update of changed stations
            ins_batch = Cell._insert_batch
            for i in range(0, len(changed_station_values), ins_batch):
                batch_values = changed_station_values[i:i + ins_batch]
                self.session.bulk_update_mappings(Cell, batch_values)

        if self.updated_areas:
            self.queue_area_updates()

        if moving_stations:
            self.blocklist_stations(moving_stations)

        self.emit_stats(added, drop_counter)
        self.emit_statcounters(added, new_stations)

        if self.data_queue.enough_data(batch=batch):  # pragma: no cover
            self.update_task.apply_async(
                kwargs={'batch': batch},
                countdown=2,
                expires=10)

        return (len(stations) + len(new_station_values), len(moving_stations))