def testDevicePropertiesUpdate(self): # Test that updates to the device properties are counted correctly. device = self._CreateFakeDevices(n=1)[0] self.assertEqual(device.num_updates(), 1) new_properties = model.DeviceProperties() new_properties.device_info = device new_properties.put() self.assertEqual(device.num_updates(), 2) new_properties = model.DeviceProperties() new_properties.device_info = device new_properties.put() self.assertEqual(device.num_updates(), 3)
def PostMeasurement(self, **unused_args): """Handler used to post a measurement from a device.""" if self.request.method.lower() != 'post': raise error.BadRequest('Not a POST request.') try: measurement_list = json.loads(self.request.body) logging.info('PostMeasurement: Got %d measurements to write', len(measurement_list)) for measurement_dict in measurement_list: device_info = model.DeviceInfo.get_or_insert( measurement_dict['device_id']) # Write new device properties, if present if 'properties' in measurement_dict: device_properties = model.DeviceProperties( parent=device_info) device_properties.device_info = device_info properties_dict = measurement_dict['properties'] # TODO(wenjiezeng): Sanitize input that contains bad fields util.ConvertFromDict(device_properties, properties_dict) # Don't want the embedded properties in the Measurement object del measurement_dict['properties'] else: # Get most recent device properties device_properties = device.GetLatestDeviceProperties( device_info, create_new_if_none=True) device_properties.put() measurement = model.Measurement(parent=device_info) util.ConvertFromDict(measurement, measurement_dict) measurement.device_properties = device_properties measurement.put() except Exception, e: logging.exception('Got exception posting measurements')
def _CreateFakeDevices(self, n=3, extra_info=None): """Create fake devices. Args: n: Number of devices to create. extra_info: optional list of dictionaries, where dictionary x will be written to the device properties of fake device x. Returns: A list of the created device objects. """ devices = [] for dev_num in range(n): dev_name = 'fakedevice%d' % dev_num new_device = model.DeviceInfo(key_name=dev_name) new_device.id = dev_name new_device.user = users.User(MobiperfTest.TEST_USER) new_device.manufacturer = MobiperfTest.TEST_DEVICE_MANUFACTURER new_device.model = MobiperfTest.TEST_DEVICE_MODEL new_device.os = MobiperfTest.TEST_DEVICE_OS new_device.put() properties = model.DeviceProperties() properties.device_info = new_device properties.app_version = MobiperfTest.TEST_DEVICE_PROPERTIES_APP_VERSION properties.os_version = MobiperfTest.TEST_DEVICE_PROPERTIES_OS_VERSION if extra_info and extra_info[dev_num]: for k, v in extra_info[dev_num].iteritems(): setattr(properties, k, v) properties.put() devices.append(new_device) return devices
def testDeviceLastUpdateTime(self): # Test that DeviceInfo.LastUpdateTime() works as expected. device = self._CreateFakeDevices(n=1)[0] new_properties = model.DeviceProperties() new_properties.device_info = device now = datetime.datetime.utcnow() new_properties.timestamp = now new_properties.put() self.assertEqual(device.LastUpdateTime(), now)
def testDevicePropertiesCreate(self): # Test that a DeviceProperties can be created. device = self._CreateFakeDevices(n=1)[0] self.assertEqual(1, len(model.DeviceProperties().all().fetch(2))) result = device.last_update() self.assertEqual(result.device_info.key().name(), 'fakedevice0') self.assertEqual(result.device_info.manufacturer, test.MobiperfTest.TEST_DEVICE_MANUFACTURER) self.assertEqual(result.os_version, test.MobiperfTest.TEST_DEVICE_PROPERTIES_OS_VERSION)
def Checkin(self, **unused_args): """Handler for checkin requests.""" if self.request.method.lower() != 'post': url = self.request.get('url') if not url: raise error.BadRequest('No contrib url.') blob = GetContrib(url) if not blob: raise error.BadRequest('No this contrib in db.') self.response.headers['Content-type'] = 'application/java-archive' self.response.out.write(blob) return checkin = json.loads(self.request.body) logging.info('Got checkin: %s', self.request.body) try: # Extract DeviceInfo device_id = checkin['id'] logging.info('Checkin from device %s', device_id) device_info = model.DeviceInfo.get_or_insert(device_id) device_info.user = users.get_current_user() # Don't want the embedded properties in the device_info structure device_info_dict = dict(checkin) del device_info_dict['properties'] util.ConvertFromDict(device_info, device_info_dict) device_info.put() # Extract DeviceProperties device_properties = model.DeviceProperties(parent=device_info) device_properties.device_info = device_info util.ConvertFromDict(device_properties, checkin['properties']) device_properties.put() device_schedule = GetDeviceSchedule(device_properties) device_schedule_json = EncodeScheduleAsJson(device_schedule) logging.info('Sending checkin response: %s', device_schedule_json) self.response.headers['Content-Type'] = 'application/json' self.response.out.write(device_schedule_json) except Exception, e: logging.error('Got exception during checkin: %s', e) self.response.headers['Content-Type'] = 'application/json' self.response.out.write(json.dumps([]))
def Checkin(self, **unused_args): """Handler for checkin requests.""" if self.request.method.lower() != 'post': raise error.BadRequest('Not a POST request.') checkin = json.loads(self.request.body) logging.info('Got checkin: %s', self.request.body) try: # Change device id such that it is anonymized, but preserve TAC. checkin['tac'] = util.GetTypeAllocationCode(checkin['id']) # We need the actual id, because we need to make a decision which ue need to take the task. # checkin['id'] = util.HashDeviceId(checkin['id']) # Extract DeviceInfo. device_id = checkin['id'] logging.info('Checkin from device %s', device_id) device_info = model.DeviceInfo.get_or_insert(device_id) device_info.user = users.get_current_user() # Don't want the embedded properties in the device_info structure. device_info_dict = dict(checkin) del device_info_dict['properties'] util.ConvertFromDict(device_info, device_info_dict) device_info.put() # Extract DeviceProperties. device_properties = model.DeviceProperties(parent=device_info) device_properties.device_info = device_info util.ConvertFromDict(device_properties, checkin['properties']) device_properties.put() device_schedule = GetDeviceSchedule(device_properties) device_schedule_json = EncodeScheduleAsJson(device_schedule) logging.info('Sending checkin response: %s', device_schedule_json) self.response.headers['Content-Type'] = 'application/json' self.response.out.write(device_schedule_json) except Exception, e: logging.error('Got exception during checkin: %s', e) self.response.headers['Content-Type'] = 'application/json' self.response.out.write(json.dumps([]))
def GetLatestDeviceProperties(device_info, create_new_if_none=False): """Retrieve the latest device properties corresponding to this device_info. Arguments: device_info: The DeviceInfo object on which to retrieve the properties. create_new_if_none: Whether to create a new DeviceProperties if none exists. Returns: A DeviceProperties object, or None. """ query = device_info.deviceproperties_set query.order('-timestamp') device_properties_list = query.fetch(1) if not device_properties_list: if create_new_if_none: device_properties = model.DeviceProperties(parent=device_info) device_properties.device_info = device_info return device_properties else: return None else: return device_properties_list[0]
def PostMeasurement(self, **unused_args): """Handler used to post a measurement from a device.""" if self.request.method.lower() != 'post': raise error.BadRequest('Not a POST request.') try: measurement_list = json.loads(self.request.body) logging.info('PostMeasurement: Got %d measurements to write', len(measurement_list)) for measurement_dict in measurement_list: # Change device id such that it is anonymized, but preserve the TAC. measurement_dict['tac'] = util.GetTypeAllocationCode( measurement_dict['device_id']) measurement_dict['device_id'] = util.HashDeviceId( measurement_dict['device_id']) device_info = model.DeviceInfo.get_or_insert( measurement_dict['device_id']) # Write new device properties, if present if 'properties' in measurement_dict: device_properties = model.DeviceProperties( parent=device_info) device_properties.device_info = device_info properties_dict = measurement_dict['properties'] # TODO(wenjiezeng): Sanitize input that contains bad fields util.ConvertFromDict(device_properties, properties_dict) # Don't want the embedded properties in the Measurement object del measurement_dict['properties'] else: # Get most recent device properties device_properties = device.GetLatestDeviceProperties( device_info, create_new_if_none=True) device_properties.put() if 'context_results' in measurement_dict: if 'values' in measurement_dict: measurement_dict['values']['context_results'] = str( measurement_dict['context_results']) del measurement_dict['context_results'] measurement = model.Measurement(parent=device_info) util.ConvertFromDict(measurement, measurement_dict) measurement.device_properties = device_properties measurement.put() #extracting the IPs from the ping measurement results to the main CDN domain if measurement.success == True and measurement.type == "ping": if ('target' in measurement_dict['parameters'] ) and measurement_dict['parameters'][ 'target'] in CDN_TARGETS: ipdata = model.CDNIpData() target_ip = measurement_dict['values'][ 'target_ip'].replace('"', '') if ':' in target_ip: continue prefix = target_ip[:target_ip.rfind('.') + 1].replace( '"', '') q = model.CDNIpData.all() q.filter("prefix =", prefix) record = q.get() if record != None: #updating timestamp (expiration time) record.put() else: #inserting the new IP record to the data store record = model.CDNIpData() record.ip = target_ip record.prefix = prefix record.cdn_domain = measurement_dict['parameters'][ 'target'] record.put() nettype = properties_dict['network_type'].lower().replace( " ", "") # map from deviceid to the list of high ping rtts low_performance_devices = {} if measurement.success == True and measurement.type == "ping" and nettype != "wifi": if ('target' in measurement_dict['parameters'] ) and measurement_dict['parameters'][ 'target'] in CDN_TARGETS: mean_rtt = float( measurement_dict['values']['mean_rtt_ms']) if util.IsLowPerformance("ping", nettype, mean_rtt): lat = float( properties_dict['location']['latitude']) lon = float( properties_dict['location']['longitude']) carrier = properties_dict['carrier'].lower( ).replace(" ", "") timestamp = measurement_dict['timestamp'] target = measurement_dict['parameters']['target'] # get all the measurement results from the last 24 hours q = model.Measurement.all() q.filter("type =", "ping") q.filter("success =", True) q.filter("timestamp >", datetime.now() - timedelta(hours=24)) for record in q.run(): record_nettype = record.device_properties.network_type.lower( ).replace(" ", "") if record.GetParam( 'target' ) == target and record_nettype != "wifi": record_rtt = record.GetValue('mean_rtt_ms') if util.IsLowPerformance( "ping", record_nettype, record_rtt): record_location = record.device_properties.location record_carrier = record.device_properties.carrier distance = -1 if record_location.lat != 0.0 and record_location.lon != 0.0: distance = util.Distance( lat, lon, record_location.lat, record_location.lon) if ( distance != -1 and distance < 2000 ) or record_carrier == carrier: #distance in km if not (record.device_properties. device_info.id in low_performance_devices): low_performance_devices[ record.device_properties. device_info.id] = [] low_performance_devices[ record.device_properties. device_info.id].append( record_rtt) #the number of devices should be at-least two if len(low_performance_devices.keys()) >= 2: query = model.Task.all() query.filter( "tag = ", "DIAG_TARGET" ) #specific ping tasks for target diagnosis, for example, ping to www.facebook.com for diag_target_task in query.run(): filter = diag_target_task.filter if not (str(device_info.id) in filter): if filter == None: diag_target_task.filter = "id = " + str( device_info.id) else: diag_target_task.filter = diag_target_task.filter + " OR id = " + str( device_info.id) diag_target_task.put() except Exception, e: logging.exception('Got exception posting measurements')