def post(self): """Retrieve the next queued work item from the run log queue. The next work item is determined based on the browser version and token. URL Params: tokens: A string that uniquely identifies an instance of a test run. instance_id: A string that uniquely identifies the machine making the request. useragent: A string representing the browser useragent string. """ # Get the parameters from the request token = self.GetRequiredParameter('tokens') instance_id = self.GetRequiredParameter('instance_id') useragent = urllib.unquote(self.GetRequiredParameter('useragent')) # Log the parameters logging.info( '\n'.join(['token: %s', 'instance_id: %s', 'useragent: %s']), token, instance_id, useragent) browser_version = AcceptNextWorkItem._ParseBrowserVersion(useragent) if not browser_version: logging.error('Could not parse the given useragent.') self.response.out.write('null') return log = db.GqlQuery( 'SELECT * FROM RunLog WHERE token = :1 AND browser_version = :2 AND ' 'status = :3 ORDER BY creation_time ASC, priority DESC LIMIT 1', token, browser_version, enum.CASE_STATUS.QUEUED).get() # Write out a null response if no log exists for the given criteria if not log: self.response.out.write('null') logging.info( 'No more test cases remain, shutting down the machine "%s".', instance_id) deferred.defer(launch_tasks.TerminateFinishedMachine, instance_id, _countdown=launch_tasks.DEFAULT_COUNTDOWN, _queue=launch_tasks.DEFAULT_QUEUE) return self.response.out.write(AcceptNextWorkItem._GetTestDataJson(log)) # Update the work item status log.status = enum.CASE_STATUS.IN_PROGRESS log.client_id = instance_id log.start_time = datetime.datetime.now() log.put() # Update the machine status client_machine.SetMachineStatus(instance_id, enum.MACHINE_STATUS.RUNNING)
def RebootMachine(instance_id): """Reboot the machine associated with the given instance id. The status of the machine is set to RUNNING. Args: instance_id: A string that uniquely identifies a machine. """ # Terminate the EC2 instance. ec2 = ec2_manager.EC2Manager() logging.info('Rebooting machine with instance id "%s".', instance_id) ec2.RebootInstances([instance_id]) # Update the corresponding client machine model. client_machine.SetMachineStatus(instance_id, enum.MACHINE_STATUS.RUNNING) client_machine.IncrementRetryCount(instance_id)
def TerminateMachine(instance_id, status): """Terminate the machine associated with the given instance id. Args: instance_id: A string that uniquely identifies a machine. status: An integer representing an enum.MACHINE_STATUS value. """ # Terminate the EC2 instance. ec2 = ec2_manager.EC2Manager() if TERMINATE_INSTANCES: logging.info('Terminating the machine with instance id "%s".', instance_id) ec2.TerminateInstances([instance_id]) else: logging.info('Stopping the machine with instance id "%s".', instance_id) ec2.StopInstances([instance_id]) # Update the corresponding client machine model. client_machine.SetMachineStatus(instance_id, status)
def post(self): """Change the state of a run log entry from IN_PROGRESS to FINISHED. URL Params: key: A string that represents the run log entry key in the datastore. instance_id: A string that uniquely identifies the machine making the request. result: A string result for the finished work item. Raises: base.InvalidParameterValueError: The given key does not correspond with an existing run log in the datastore. """ # Get the parameters from the request key = self.GetRequiredParameter('key') instance_id = self.GetRequiredParameter('instance_id') result = self.GetOptionalParameter('result', default_value=WORK_ITEM_SUCCESS) # Log the parameters logging.info('\n'.join(['key: %s', 'instance_id: %s', 'result: %s']), key, instance_id, result) log = db.get(key) if not log: raise base.InvalidParameterValueError('key', key) logging.info('Current log status: "%d".', log.status) if log.status != enum.CASE_STATUS.IN_PROGRESS: # The run log has an invalid run status for finishing, just return logging.error( 'The test case "%s" has an invalid status for finishing.', key) return if result == WORK_ITEM_SUCCESS: # Update the work item status log.status = enum.CASE_STATUS.FINISHED log.end_time = datetime.datetime.now() if log.start_time: duration = log.end_time - log.start_time log.duration = FinishWorkItem._TimedeltaToMilliseconds( duration) logging.info('Work item finished successfully.') elif result == WORK_ITEM_FAILURE: FinishWorkItem._HandleFailureCase(log, enum.CASE_STATUS.UNKNOWN_ERROR, 'failure') elif result == WORK_ITEM_UPLOAD_ERROR: FinishWorkItem._HandleFailureCase(log, enum.CASE_STATUS.UPLOAD_ERROR, 'upload error') elif result == WORK_ITEM_TIMEOUT_ERROR: FinishWorkItem._HandleFailureCase(log, enum.CASE_STATUS.TIMEOUT_ERROR, 'timeout error') log.put() # Update the machine status client_machine.SetMachineStatus(instance_id, enum.MACHINE_STATUS.RUNNING)
def post(self): """Put the given result data into the database.""" data = self._GetRequestData() # Touch the machine instance if the instance id is provided. if 'instance_id' in data: client_machine.SetMachineStatus(data['instance_id'], enum.MACHINE_STATUS.RUNNING) if 'key' not in data: update_suite_info = False suite_data = simplejson.loads(data['suiteInfo']) suite = test_suite.GetOrInsertSuite( suite_data['date'], suite_data['refBrowser'], suite_data['refBrowserChannel']) channel = None if 'channel' in data: channel = data['channel'] # Following code is to take care of the scenario where test browser comes # up first with the data. Hence, at that time we don't have sufficient # data to put in ref browser. # If reference browser information is incomplete then let's mark # it for update. if suite.ref_browser.os is None: parser = useragent_parser.UAParser(data['userAgent']) if (parser.GetBrowserVersion() == suite.ref_browser.version and channel==suite_data['refBrowserChannel']): # If flag is present anywhere then it has to match. if 'flag' in data or suite.ref_browser.flag: if suite.ref_browser.flag == data['flag']: update_suite_info = True else: update_suite_info = True test_data = page_data.PageData() if 'screenshot' in data: test_data.screenshot = screenshot.AddScreenshot(data['screenshot']) test_data.test_suite = suite flag = None if 'flag' in data: flag = data['flag'] test_data.browser = browser.GetOrInsertBrowser( data['userAgent'], channel=channel, flag=flag) if update_suite_info: logging.info('Updating Reference Browser in Test Suite. old_ref: %s,' ' new_ref: %s', suite.ref_browser.key(), test_data.browser.key()) test_suite.UpdateRefBrowser(suite, test_data.browser, delete_old_ref=True) # Let's get run log key from suite_data. if 'key' not in suite_data: raise PutDataError('The run log "key" is a required parameter.') my_run_log = db.get(db.Key(suite_data['key'])) url_config_key = my_run_log.config.key() test_data.site = site.GetOrInsertSiteFromUrl(data['url'], url_config_key) test_data.nodes_table = data['nodesTable'] test_data.dynamic_content_table = data['dynamicContentTable'] test_data.layout_table = data_list.CreateEmptyDataList() test_data.width = int(data['width']) test_data.height = int(data['height']) if 'metaData' in data: test_data.metadata = data['metaData'] # If browser key matches with test_suite's ref browser then # let's mark the page_data as reference. if str(test_data.browser.key()) == str(suite.ref_browser.key()): test_data.is_reference = True else: test_data.is_reference = False test_data.put() if not test_data.is_reference: suite.AddTestBrowser(test_data.browser) response = { 'key': str(test_data.key()), 'nPieces': data_list.NUM_ENTRIES} self.response.out.write(simplejson.dumps(response)) else: test_data = db.get(db.Key(data['key'])) layout_table = simplejson.loads(data['layoutTable']) test_data.layout_table.AddEntry(int(data['i']), layout_table) self.response.out.write('received')