aboutsummaryrefslogtreecommitdiff
path: root/helpers/jenkins_lava.py
blob: c7a7a1c244381d865822144f787889f9053bffb4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
import re
import ast
import json
import logging
from datetime import datetime
from django.conf import settings
from testplanner.models import (
    Device,
    TestDefinition,
    TestDefinitionRevision
)
from testrunner.models import (
    JenkinsJob,
    JenkinsBuild,
    JenkinsBuildStatus,
    LavaJob,
    LavaJobStatus,
    LavaJobResult,
    LavaJobResultStatus,
    LavaJobTestResult,
    LavaJobTestResultUnit
)
#ToDo - get rid of lava_tool. Rewrite XML-RPC using token stored in settings
from lava_tool.authtoken import (
    AuthenticatingServerProxy, 
    KeyringAuthBackend
)

RUNNING = "RUNNING"
log = logging.getLogger('testrunner')

def fetch_jenkins_builds(jenkins_db_job, jenkins_job, jenkins_build):
    lava_server = AuthenticatingServerProxy(
        settings.LAVA_SERVER_URL,
        verbose=False,
        auth_backend=KeyringAuthBackend())

    lava_job_regexp = re.compile(settings.LAVA_JOB_ID_REGEXP)
    build = jenkins_job.get_build(jenkins_build)
    # create umbrella build in DB
    db_build = create_jenkins_build(build, jenkins_db_job)
    log.debug("master build: {0} {1}".format(db_build.number, db_build.name))
    is_matrix = False
    log.debug("fetching matrix builds")
    for run in build.get_matrix_runs():
        is_matrix = True
        db_run = create_jenkins_build(run, jenkins_db_job, False, db_build)
        if 'description' in run._data and run._data['description']:
            log.debug("Jenkins build description: {0}".format(run._data['description']))
            r = lava_job_regexp.search(run._data['description'])
            if r:
                log.debug('LAVA job ID: {0}'.format(r.group('lava_job_id')))
                get_lava_job_details(r.group('lava_job_id'), db_run, lava_server)
        else:
            log.debug("no description for build")
            for r in lava_job_regexp.finditer(run.get_console()):
                log.debug('LAVA job ID: {0}'.format(r.group('lava_job_id')))
                get_lava_job_details(r.group('lava_job_id'), db_run, lava_server)
    if not is_matrix:
        db_run = create_jenkins_build(build, jenkins_db_job, False, db_build)
        if 'description' in build._data and build._data['description']:
            log.debug("Jenkins build description: {0}".format(build._data['description']))
            r = lava_job_regexp.search(build._data['description'])
            if r:
                #print 'LAVA job ID:', r.group('lava_job_id')
                get_lava_job_details(r.group('lava_job_id'), db_run, lava_server)



def get_lava_job_details(job_id, jenkins_build, lava_server=None):
    if lava_server is None:
        lava_server = AuthenticatingServerProxy(
            settings.LAVA_SERVER_URL,
            verbose=False,
            auth_backend=KeyringAuthBackend())

    job_details = lava_server.scheduler.job_details(job_id)
    #pprint(job_details)
    db_device = None
    if 'requested_device_type_id' in job_details and job_details['requested_device_type_id']:
        db_device, created = Device.objects.get_or_create(name = job_details['requested_device_type_id'])
    else:
        # try to decode the device type from the device name
        # it is assumed that device ID ends with 2 digit number added to device type
        db_device, created = Device.objects.get_or_create(name = job_details['actual_device_id'][0:-2])
    job_status = lava_server.scheduler.job_status(job_id)
    #print 'LAVA job status:', job_status['job_status']
    lava_db_job_status, created = LavaJobStatus.objects.get_or_create(name = job_status['job_status'])
    lava_job_defaults = {
        'status': lava_db_job_status,
        'device_type': db_device
    }
    #lava_db_job = LavaJob(
    #    jenkins_build = jenkins_build,
    #    number = job_details['id'],
    #    status = lava_db_job_status,
    #    
    #    )
    lava_db_job, lava_db_job_created = LavaJob.objects.get_or_create(
        jenkins_build = jenkins_build, 
        number = job_details['id'], 
        defaults = lava_job_defaults)
    # make sure the fields are updated if the job object already exists
    if not lava_db_job_created:
        lava_db_job.status = lava_db_job_status
        lava_db_job.device_type = db_device
        lava_db_job.save()
    log.debug(db_device)
    #if db_device:
    #    log.debug("adding db_device {0} to lava job {1}".format(db_device, lava_db_job))
    #    lava_db_job.device_type = db_device
    log.debug("Submit time: {0}".format(job_details['submit_time']))
    log.debug("Submit time: {0}".format(job_details['submit_time'].__class__.__name__))
     
    lava_db_job.submit_time = datetime.strptime(str(job_details['submit_time']), '%Y%m%dT%H:%M:%S')
    if 'start_time' in job_details and job_details['start_time']:
        log.debug("Start time: {0}".format(job_details['start_time']))
        lava_db_job.start_time = datetime.strptime(str(job_details['start_time']), '%Y%m%dT%H:%M:%S')

    job_definition = ast.literal_eval(job_details['definition'].replace("\n","").replace(" ","").replace("false","False"))

    job_definition_tests = []
    for action in job_definition['actions']:
        if action['command'] == "lava_test_shell":
            # ignore lava_android_test_run as these are not in db yet
            #or action['command'] == "lava_android_test_run":
            job_definition_tests += action['parameters']['testdef_repos']

    #lava_db_job.save()
    #print "Test runs scheduled", len(job_definition_tests)
    for test_def in job_definition_tests:
        # find test definition object
        log.debug("adding test definition {0} from repository {1} to LAVA {2}".format(test_def['testdef'], test_def['git-repo'], lava_db_job))
        db_test_def_list = TestDefinition.objects.filter(
            test_file_name = test_def['testdef'], 
            repository__url = test_def['git-repo'])
        if db_test_def_list:
            # attach first test in the list to lava job
            lava_db_job.test_definitions.add(db_test_def_list[0])
    lava_db_job.save()

    if 'bundle_sha1' in job_status and job_status['bundle_sha1']:
        bundle_hash = job_status['bundle_sha1']
        bundle = json.loads(lava_server.dashboard.get(bundle_hash)['content'])
        log.debug("Test runs executed: {0}".format(len(bundle['test_runs'])))
        for run in iter(bundle['test_runs']):
            if run['test_id'] != 'lava':
                # find test definition corresponding to the results
                # lava should not execute test that wasn't requested
                log.debug("trying to find test definition with ID: {0} from LAVA {1}".format(run['test_id'], lava_db_job))
                # test_id is not unique, but there is no better way of matching results to definition at this point
                result_test_definition = lava_db_job.test_definitions.filter(test_id = run['test_id'])
                log.debug(run['test_id'])
                lava_db_result = LavaJobResult(
                    lava_job = lava_db_job
                )
                if result_test_definition:
                    result_test_definition = result_test_definition[0]
                    lava_db_result.test_definition = result_test_definition
                if 'testdef_metadata' in run and result_test_definition:
                    # check if there is a corresponding version in db
                    test_definition_revision_list = result_test_definition.testdefinitionrevision_set.filter(revision = run['testdef_metadata']['version'])
                    if test_definition_revision_list:
                        lava_db_result.test_revision = test_definition_revision_list[0]

                lava_db_result.save()
                for test_result in iter(run['test_results']):
                    log.debug("trying to save test results {0}".format(test_result['test_case_id']))
                    test_result_status, created = LavaJobResultStatus.objects.get_or_create(name = test_result['result'])
                    lava_db_test_result = LavaJobTestResult(
                        lava_job_result = lava_db_result,
                        status = test_result_status,
                        test_case_id = test_result['test_case_id']
                        )
                    if 'measurement' in test_result:
                        db_unit, created = LavaJobTestResultUnit.objects.get_or_create(name = test_result['units'])
                        lava_db_test_result.is_measurement = True
                        lava_db_test_result.value = test_result['measurement'] 
                        lava_db_test_result.unit = db_unit
                    lava_db_test_result.save()

def create_jenkins_build(jenkins_build, jenkins_db_job, is_umbrella = True, umbrella_db_build = None):
    status_name = RUNNING
    if not jenkins_build.is_running():
        status_name = jenkins_build.get_status()
    build_status, created = JenkinsBuildStatus.objects.get_or_create(name = status_name)
    jenkins_build_defaults = {
        "status": build_status,
        "is_umbrella": is_umbrella,
        "timestamp": jenkins_build.get_timestamp()
    }
    db_build, db_build_created = JenkinsBuild.objects.get_or_create(
        name = jenkins_build.name,
        job = jenkins_db_job,
        number = jenkins_build.get_number(),
        defaults = jenkins_build_defaults
        )
    if not is_umbrella and umbrella_db_build:
        db_build.umbrella_build = umbrella_db_build
    if not db_build_created:
        db_build.status = build_status
        db_build.is_umbrella = is_umbrella
        db_build.timestamp = jenkins_build.get_timestamp()
    db_build.save()
    if db_build_created:
        log.debug("Jenkins build {0} created ({1})".format(jenkins_build.get_number(), jenkins_build.name))
    else:
        log.debug("Jenkins build {0} updated ({1})".format(jenkins_build.get_number(), jenkins_build.name))
    return db_build