def update_result(result_id): """Update an individual result.""" orig = Result.objects(id=result_id).first() update_event = events.UpdateEvent(before=orig) update = read_request() print((repr(update))) if 'status' in update and update['status'] != None and update['status'] != orig.status: atomic_update = { 'dec__summary__resultsByStatus__' + orig.status: 1, 'inc__summary__resultsByStatus__' + update['status']: 1 } update_testrun_event = None testrun = None if app.config['events']: testrun = Testrun.objects(id=orig.testrun.testrunId).first() update_testrun_event = events.UpdateEvent(before=testrun) Testrun.objects(id=orig.testrun.testrunId).update_one(**atomic_update) if app.config['events']: testrun.reload() update_testrun_event.after(testrun) deserialize_that(update, orig) apply_triage_notes(orig) orig.save() update_event.after(orig) return JsonResponse(orig)
def cancel_individual_result(result_id): """Reschedule a single result, only works on a result that was originally scheduled.""" orig = Result.objects(id=result_id).first() orig_status = orig.status if orig_status == "NO_RESULT": decrement_orig_status_by = "dec__summary__resultsByStatus__" + orig_status increment_skipped_status_by = "inc__summary__resultsByStatus__SKIPPED" Testrun.objects(id=orig.testrun.testrunId).update_one(**{decrement_orig_status_by: 1, increment_skipped_status_by: 1}) Result.objects(id=result_id).update(runstatus="FINISHED", status="SKIPPED", reason="Run cancelled from slick.") orig.reload() return JsonResponse(orig)
def reschedule_individual_result(result_id): """Reschedule a single result, only works on a result that was originally scheduled.""" orig = Result.objects(id=result_id).first() orig_status = orig.status if orig_status != "NO_RESULT": decrement_orig_status_by = "dec__summary__resultsByStatus__" + orig_status increment_noresult_status_by = "inc__summary__resultsByStatus__NO_RESULT" Testrun.objects(id=orig.testrun.testrunId).update_one(**{decrement_orig_status_by: 1, increment_noresult_status_by: 1}) Result.objects(id=result_id).update(log=[], files=[], runstatus="SCHEDULED", status="NO_RESULT", unset__hostname=True, unset__started=True, unset__finished=True, unset__runlength=True, unset__reason=True) orig.reload() return JsonResponse(orig)
def cancel_results_from_testrun(testrun_id): """Cancel all results that are scheduled for this testrun.""" testrun = Testrun.objects(id=testrun_id).first() results_to_cancel = Result.objects(testrun__testrunId=testrun.id, status='NO_RESULT', runstatus__in=['SCHEDULED', 'TO_BE_RUN']) for result in results_to_cancel: cancel_individual_result(result.id) return JsonResponse(Result.objects(testrun__testrunId=testrun.id, status="FINISHED", runstatus="SKIPPED"))
def get_build_reports(project_name, release_name): """Get all summary of all the builds for a particular release.""" limit = 15 if request.args.get("limit"): try: limit = int(request.args.get("limit")) except: pass groupType = "SERIAL" if request.args.get("groupType"): groupType = request.args.get("groupType") project_id, release_id, build_id = Project.lookup_project_release_build_ids(project_name, release_name, None, get_all_builds=True, limit=limit) report = {} report['name'] = "Release Report for {} {}".format(project_name, release_name) report['builds'] = [] report['grouptype'] = groupType if build_id is None: return JsonResponse({}) for build_object in build_id: testrun_group = TestrunGroup() testrun_group.name = "Build Report for {} {} Build {}".format(project_name, release_name, build_object['name']) testrun_group.grouptype = groupType testrun_group.testruns = Testrun.objects(build__buildId=build_object['id']).order_by("-dateCreated") report['builds'].append(testrun_group) return JsonResponse(report)
def cancel_individual_result(result_id): """Reschedule a single result, only works on a result that was originally scheduled.""" orig = Result.objects(id=result_id).first() orig_status = orig.status if orig_status == "NO_RESULT": decrement_orig_status_by = "dec__summary__resultsByStatus__" + orig_status increment_skipped_status_by = "inc__summary__resultsByStatus__SKIPPED" Testrun.objects(id=orig.testrun.testrunId).update_one(**{decrement_orig_status_by: 1, increment_skipped_status_by: 1}) testrun = Testrun.objects(id=orig.testrun.testrunId).first() if testrun and testrun.summary.resultsByStatus.NO_RESULT == 0: # finish testrun testrun.runFinished = datetime.datetime.utcnow() testrun.state = "FINISHED" Testrun.objects(id=orig.testrun.testrunId).update_one(runFinished=testrun.runFinished, state=testrun.state) reason = request.args.get("reason") if request.args.get("reason") else "Run cancelled from slick." Result.objects(id=result_id).update(runstatus="FINISHED", status="SKIPPED", reason=reason) orig.reload() return JsonResponse(orig)
def find_testrun_by_reference(ref): """Find a testrun using a testrun reference instance. A testrun reference contains the name and the id, and those will be used to find the testrun. :param ref: a slickqaweb.model.testrunReference.TestrunReference instance :return: An instance of Testrun from mongo if found, None otherwise """ if ref is None: return None assert isinstance(ref, TestrunReference) retval = None if ref.testrunId is not None: retval = Testrun.objects(id=ref.testrunId).first() if retval is None and ref.name is not None and ref.name != '': retval = Testrun.objects(name=ref.name).first() return retval
def add_testrun_to_testrun_group(testrungroup_id, testrun_id): """Add a testrun to a testrun group""" orig = TestrunGroup.objects(id=ObjectId(testrungroup_id)).first() testrun = Testrun.objects(id=ObjectId(testrun_id)).first() if (not hasattr(orig, 'testruns')) or orig.testruns is None: orig.testruns = [] orig.testruns.append(testrun) orig.save() return JsonResponse(orig)
def update_testrun(testrun_id): """Update the properties of a testrun.""" orig = Testrun.objects(id=testrun_id).first() update_event = events.UpdateEvent(before=orig) deserialize_that(read_request(), orig) if orig.state == "FINISHED" and is_not_provided(orig, 'runFinished'): orig.runFinished = datetime.datetime.utcnow() orig.save() update_event.after(orig) return JsonResponse(orig)
def reschedule_results_with_status_on_build(project_name, release_name, build_name, status): """Reschedule all results with a particular status for a build.""" project_id, release_id, build_id = Project.lookup_project_release_build_ids(project_name, release_name, build_name) rescheduled_results = [] if build_id is None: return JsonResponse(None) for testrun in Testrun.objects(build__buildId=build_id).order_by("-dateCreated"): results_to_reschedule = Result.objects(testrun__testrunId=testrun.id, status=status) rescheduled_results.extend(results_to_reschedule) for result in results_to_reschedule: reschedule_individual_result(result.id) return JsonResponse(rescheduled_results)
def cancel_results_for_build(project_name, release_name, build_name): """Cancel all results that are scheduled for this build.""" project_id, release_id, build_id = Project.lookup_project_release_build_ids(project_name, release_name, build_name) canceled_results = [] if build_id is None: return JsonResponse(None) for testrun in Testrun.objects(build__buildId=build_id).order_by("-dateCreated"): results_to_cancel = Result.objects(testrun__testrunId=testrun.id, status='NO_RESULT', runstatus__in=['SCHEDULED', 'TO_BE_RUN']) canceled_results.extend(results_to_cancel) for result in results_to_cancel: cancel_individual_result(result.id) return JsonResponse(canceled_results)
def delete_testrun(testrun_id): """Remove a testrun.""" orig = Testrun.objects(id=testrun_id).first() # delete the reference from any testrun groups trdbref = bson.DBRef('testruns', bson.ObjectId("531e4d26ded43258823d9c3a")) TestrunGroup.objects(__raw__={'testruns': {'$elemMatch': trdbref}}).update(pull__testruns=trdbref) # add an event events.DeleteEvent(orig) orig.delete() return JsonResponse(orig)
def reschedule_individual_result(result_id): """Reschedule a single result, only works on a result that was originally scheduled.""" orig = Result.objects(id=result_id).first() orig_status = orig.status log = [] if orig.log: log = orig.log if 'retry_count' in orig.attributes: orig.attributes['retry_count'] = str(int(orig.attributes['retry_count']) + 1) else: orig.attributes['retry_count'] = "1" if 'max_retry' not in orig.attributes: orig.attributes['max_retry'] = "3" if orig_status != "NO_RESULT": decrement_orig_status_by = "dec__summary__resultsByStatus__" + orig_status increment_noresult_status_by = "inc__summary__resultsByStatus__NO_RESULT" Testrun.objects(id=orig.testrun.testrunId).update_one(**{decrement_orig_status_by: 1, increment_noresult_status_by: 1}) log.append({"entryTime": datetime.datetime.utcnow(), "level": "INFO", "loggerName": "slick.note", "message": "Rescheduled. Count: {}. Max: {} {} {}".format(orig.attributes['retry_count'], orig.attributes['max_retry'], orig.hostname, orig.reason), "exceptionMessage": ""}) Result.objects(id=result_id).update(log=log, files=[], links=[], runstatus="SCHEDULED", status="NO_RESULT", recorded=datetime.datetime.utcnow(), unset__hostname=True, unset__started=True, unset__finished=True, unset__runlength=True, unset__reason=True, attributes=orig.attributes) orig.reload() return JsonResponse(orig)
def get_build_report(project_name, release_name, build_name): """Get all summary of all the testruns run against a particular build.""" project_id, release_id, build_id = Project.lookup_project_release_build_ids(project_name, release_name, build_name) report = TestrunGroup() report.name = "Build Report for {} {} Build {}".format(project_name, release_name, build_name) report.grouptype = "PARALLEL" report.testruns = [] testplans = [] for testrun in Testrun.objects(build__buildId=build_id).order_by("-dateCreated"): assert isinstance(testrun, Testrun) if testrun.testplanId not in testplans: report.testruns.append(testrun) testplans.append(testrun.testplanId) return JsonResponse(report)
def get_tps_report(project_name, release_name, testplan_name): """Get all summary of all the testruns run against a particular build.""" project_id, release_id, _ = Project.lookup_project_release_build_ids(project_name, release_name, None) testplan = TestPlan.objects(project__id=project_id, name=testplan_name) if len(testplan) > 0: testplan = testplan[0] report = TestrunGroup() report.name = "{} Summary for {}".format(testplan_name, release_name) report.grouptype = "SERIAL" report.testruns = [] report.testruns.extend(Testrun.objects(project__id=project_id, release__releaseId=release_id, testplanId=testplan.id).order_by('-dateCreated').limit(50)) report.testruns.reverse() return JsonResponse(report) else: return JsonResponse({})
def reschedule_results_with_status_on_testrun(testrun_id, status): """Reschedule all results with a particular status for a testrun.""" testrun = Testrun.objects(id=testrun_id).first() results_to_reschedule = Result.objects(testrun__testrunId=testrun.id, status=status) for result in results_to_reschedule: reschedule_individual_result(result.id) # how_many = Result.objects(testrun__testrunId=testrun.id, status=status).update(log=[], files=[], # runstatus="SCHEDULED", # status="NO_RESULT", # unset__hostname=True, # unset__started=True, # unset__finished=True, # unset__runlength=True, # unset__reason=True) # setattr(testrun.summary.resultsByStatus, status, getattr(testrun.summary.resultsByStatus, status) - how_many) # testrun.summary.resultsByStatus.NO_RESULT += how_many # testrun.save() return JsonResponse(Result.objects(testrun__testrunId=testrun.id, status="NO_RESULT", runstatus="SCHEDULED"))
def get_build_report(project_name, release_name, build_name): """Get all summary of all the testruns run against a particular build.""" project_id, release_id, build_id = Project.lookup_project_release_build_ids(project_name, release_name, build_name) report = TestrunGroup() report.name = "Build Report for {} {} Build {}".format(project_name, release_name, build_name) report.grouptype = "PARALLEL" report.testruns = [] testplans = [] if build_id is None: return JsonResponse(None) for testrun in Testrun.objects(build__buildId=build_id).order_by("-dateCreated"): assert isinstance(testrun, Testrun) if testrun.testplanId not in testplans: report.testruns.append(testrun) testplans.append(testrun.testplanId) if report.state() == "FINISHED" and not report.finished: report.finished = datetime.datetime.utcnow() # report.save() Warning, be careful not to do this, build reports don't get saved # this will create a new testrungroup every time the build report is # queried return JsonResponse(report)
def add_result(testrun_id=None): """Create a new result.""" raw = read_request() new_result = deserialize_that(raw, Result()) assert isinstance(new_result, Result) # validate -------------------------------------------------------------- # you must have a testcase reference (some info about the testcase) and a # status for the result. Otherwise it's not really a result. errors = [] if is_not_provided(new_result, 'status'): errors.append("status must be set") if is_not_provided(new_result, 'testcase') or (is_not_provided(new_result.testcase, 'name') and is_not_provided(new_result.testcase, 'testcaseId') and is_not_provided(new_result.testcase, 'automationId') and is_not_provided(new_result.testcase, 'automationKey')): errors.append("testcase must be provided with at least one identifying piece of data") if len(errors) > 0: return Response('\r\n'.join(errors), status=400, mimetype="text/plain") # fill in defaults ------------------------------------------------------- # a few fields can easily be inferred or set to a default if is_not_provided(new_result, 'runstatus'): if new_result.status == "NO_RESULT": new_result.runstatus = "TO_BE_RUN" else: new_result.runstatus = "FINISHED" if is_not_provided(new_result, 'recorded'): new_result.recorded = datetime.datetime.utcnow() # resolve references ----------------------------------------------------- testrun = None project = None testcase = None release = None build = None component = None configuration = None if testrun_id is not None: testrun = Testrun.objects(id=testrun_id).first() if testrun is not None: new_result.testrun = create_testrun_reference(testrun) # the order in this section is important. We try to find information any way we can, # so if it's not provided in the result, we look at the testrun, if it's not in the testrun, # but it is in the testcase we get it from there. # first lookup the testrun and resolve it if we can if is_provided(new_result, 'testrun') and testrun is None: testrun = find_testrun_by_reference(new_result.testrun) # don't create a new testrun if it's null, we'll do that later after we resolve the other # pieces of information # try to resolve the testcase, we won't try to create it if it's none yet. # for that we need to resolve as much of the other information we can. testcase = find_testcase_by_reference(new_result.testcase) # try to find the project from the data provided in the result. If that doesn't work, # and we do have a testrun, see if we can get it from there. If we do have a name of a # project and we still haven't found the project, create it! if is_provided(new_result, 'project'): project = find_project_by_reference(new_result.project) if project is None and testrun is not None and is_provided(testrun, 'project'): project = find_project_by_reference(testrun.project) if project is None and is_provided(new_result.project, 'name'): project = Project() project.name = new_result.project.name project.save() # if they didn't provide any project data, but did provide testrun data, try # to resolve the project from the testrun if project is None and testrun is not None and is_provided(testrun, 'project'): project = find_project_by_reference(testrun.project) # if we couldn't resolve the project previously, but we can resolve the testcase # see if we can get the project from the testcase if project is None and testcase is not None and is_provided(testcase, 'project'): project = find_project_by_reference(testcase.project) # finally, make sure that the reference we have in the result has all the info in it if project is not None: new_result.project = create_project_reference(project) # resolve the component if is_provided(new_result, 'component'): if project is not None: component = find_component_by_reference(project, new_result.component) if component is None: component = Component() component.id = ObjectId() component.name = new_result.component.name if is_provided(new_result.component, 'code'): component.code = new_result.component.code else: component.code = component.name.lower().replace(' ', '-') project.components.append(component) project.save() if component is not None: new_result.component = create_component_reference(component) # create a testcase if needed if testcase is None and is_not_provided(new_result.testcase, 'name'): return Response('Existing testcase not found, please provide a testcase name if you want one to be created.\n', status=400, mimetype="text/plain") elif testcase is None: testcase = Testcase() testcase.created = datetime.datetime.utcnow() testcase.name = new_result.testcase.name if is_provided(new_result.testcase, 'automationId'): testcase.automationId = new_result.testcase.automationId if is_provided(new_result.testcase, 'automationKey'): testcase.automationKey = new_result.testcase.automationKey if project is not None: testcase.project = create_project_reference(project) if component is not None: testcase.component = create_component_reference(component) testcase.save() testcase_changed = False if 'steps' in raw['testcase']: testcase.steps = [] for raw_step in raw['testcase']['steps']: step = deserialize_that(raw_step, Step()) testcase.steps.append(step) testcase_changed = True if 'purpose' in raw['testcase']: testcase.purpose = raw['testcase']['purpose'] testcase_changed = True if 'requirements' in raw['testcase']: testcase.requirements = raw['testcase']['requirements'] testcase_changed = True if 'author' in raw['testcase']: testcase.author = raw['testcase']['author'] testcase_changed = True # TODO: feature and automationTool if testcase_changed: testcase.save() # no matter what testcase should not be None at this point, but just in case I made a mistake if testcase is None: return Response('Somehow I was unable to find or create a testcase for this result.\n', status=400, mimetype="text/plain") new_result.testcase = create_testcase_reference(testcase) # dereference release and build if possible if is_provided(new_result, 'release') and project is not None: release = find_release_by_reference(project, new_result.release) if release is None and testrun is not None and project is not None and is_provided(testrun, 'release'): release = find_release_by_reference(project, testrun.release) if release is None and project is not None and is_provided(new_result, 'release') and is_provided(new_result.release, 'name'): release = Release() release.id = ObjectId() release.name = new_result.release.name project.releases.append(release) project.save() if release is not None: new_result.release = create_release_reference(release) if is_provided(new_result, 'build'): build = find_build_by_reference(release, new_result.build) if build is None and testrun is not None and is_provided(testrun, 'build'): build = find_build_by_reference(release, testrun.build) if build is None and project is not None and is_provided(new_result, 'build') and is_provided(new_result.build, 'name'): build = Build() build.id = ObjectId() build.name = new_result.build.name build.built = datetime.datetime.utcnow() release.builds.append(build) project.save() if build is not None: new_result.build = create_build_reference(build) # dereference configuration if is_provided(new_result, 'config'): configuration = find_configuration_by_reference(new_result.config) if configuration is None and testrun is not None and is_provided(testrun, 'config'): configuration = find_configuration_by_reference(testrun.config) if configuration is None and is_provided(new_result, 'config') and is_provided(new_result.config, 'name'): configuration = Configuration() configuration.name = new_result.config.name if is_provided(new_result.config, 'filename'): configuration.filename = new_result.config.filename configuration.save() if configuration is not None: new_result.config = create_configuration_reference(configuration) # if there is no testrun, create one with the information provided if testrun is None: testrun = Testrun() if is_provided(new_result, 'testrun') and is_provided(new_result.testrun, 'name'): testrun.name = new_result.testrun.name else: testrun.name = 'Testrun starting %s' % str(datetime.datetime.utcnow()) if project is not None: testrun.project = create_project_reference(project) if configuration is not None: testrun.config = create_configuration_reference(configuration) if release is not None: testrun.release = create_release_reference(release) if build is not None: testrun.build = create_build_reference(build) testrun.dateCreated = datetime.datetime.utcnow() testrun.runStarted = datetime.datetime.utcnow() testrun.state = 'RUNNING' testrun.save() if testrun is not None: new_result.testrun = create_testrun_reference(testrun) status_name = "inc__summary__resultsByStatus__" + new_result.status Testrun.objects(id=testrun.id).update_one(**{status_name: 1}) apply_triage_notes(new_result, testcase) new_result.history, estimatedRuntime = find_history(new_result) if new_result.attributes is None: new_result.attributes = {} new_result.attributes['estimatedRuntime'] = str(estimatedRuntime) new_result.save() events.CreateEvent(new_result) return JsonResponse(new_result)
def get_testrun_by_id(testrun_id): """Retrieve a testrun using it's id.""" return JsonResponse(Testrun.objects(id=testrun_id).first())