summaryrefslogtreecommitdiffstats
path: root/bitbake/lib/toaster/tests/builds/buildtest.py
blob: fce7b62144d45c470a6811a9b9e62278ba38473d (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
#! /usr/bin/env python
# ex:ts=4:sw=4:sts=4:et
# -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
#
# BitBake Toaster Implementation
#
# Copyright (C) 2016 Intel Corporation
#
# SPDX-License-Identifier: GPL-2.0-only
#

import os
import sys
import time
import unittest

from orm.models import Project, Release, ProjectTarget, Build, ProjectVariable
from bldcontrol.models import BuildEnvironment

from bldcontrol.management.commands.runbuilds import Command\
    as RunBuildsCommand

from django.core.management import call_command

import subprocess
import logging

logger = logging.getLogger("toaster")

# We use unittest.TestCase instead of django.test.TestCase because we don't
# want to wrap everything in a database transaction as an external process
# (bitbake needs access to the database)

def load_build_environment():
    call_command('loaddata', 'settings.xml', app_label="orm")
    call_command('loaddata', 'poky.xml', app_label="orm")

    current_builddir = os.environ.get("BUILDDIR")
    if current_builddir:
        BuildTest.BUILDDIR = current_builddir
    else:
        # Setup a builddir based on default layout
        # bitbake inside openebedded-core
        oe_init_build_env_path = os.path.join(
            os.path.dirname(os.path.abspath(__file__)),
            os.pardir,
            os.pardir,
            os.pardir,
            os.pardir,
            os.pardir,
            'oe-init-build-env'
        )
        if not os.path.exists(oe_init_build_env_path):
            raise Exception("We had no BUILDDIR set and couldn't "
                            "find oe-init-build-env to set this up "
                            "ourselves please run oe-init-build-env "
                            "before running these tests")

        oe_init_build_env_path = os.path.realpath(oe_init_build_env_path)
        cmd = "bash -c 'source oe-init-build-env %s'" % BuildTest.BUILDDIR
        p = subprocess.Popen(
            cmd,
            cwd=os.path.dirname(oe_init_build_env_path),
            shell=True,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE)

        output, err = p.communicate()
        p.wait()

        logger.info("oe-init-build-env %s %s" % (output, err))

        os.environ['BUILDDIR'] = BuildTest.BUILDDIR

    # Setup the path to bitbake we know where to find this
    bitbake_path = os.path.join(
        os.path.dirname(os.path.abspath(__file__)),
        os.pardir,
        os.pardir,
        os.pardir,
        os.pardir,
        'bin',
        'bitbake')
    if not os.path.exists(bitbake_path):
        raise Exception("Could not find bitbake at the expected path %s"
                        % bitbake_path)

    os.environ['BBBASEDIR'] = bitbake_path

class BuildTest(unittest.TestCase):

    PROJECT_NAME = "Testbuild"
    BUILDDIR = "/tmp/build/"

    def build(self, target):
        # So that the buildinfo helper uses the test database'
        self.assertEqual(
            os.environ.get('DJANGO_SETTINGS_MODULE', ''),
            'toastermain.settings_test',
            "Please initialise django with the tests settings:  "
            "DJANGO_SETTINGS_MODULE='toastermain.settings_test'")

        built = self.target_already_built(target)
        if built:
            return built

        load_build_environment()

        BuildEnvironment.objects.get_or_create(
            betype=BuildEnvironment.TYPE_LOCAL,
            sourcedir=BuildTest.BUILDDIR,
            builddir=BuildTest.BUILDDIR
        )

        release = Release.objects.get(name='local')

        # Create a project for this build to run in
        project = Project.objects.create_project(name=BuildTest.PROJECT_NAME,
                                                 release=release)

        if os.environ.get("TOASTER_TEST_USE_SSTATE_MIRROR"):
            ProjectVariable.objects.get_or_create(
                name="SSTATE_MIRRORS",
                value="file://.* http://autobuilder.yoctoproject.org/pub/sstate/PATH;downloadfilename=PATH",
                project=project)

        ProjectTarget.objects.create(project=project,
                                     target=target,
                                     task="")
        build_request = project.schedule_build()

        # run runbuilds command to dispatch the build
        # e.g. manage.py runubilds
        RunBuildsCommand().runbuild()

        build_pk = build_request.build.pk
        while Build.objects.get(pk=build_pk).outcome == Build.IN_PROGRESS:
            sys.stdout.write("\rBuilding %s %d%%" %
                             (target,
                              build_request.build.completeper()))
            sys.stdout.flush()
            time.sleep(1)

        self.assertEqual(Build.objects.get(pk=build_pk).outcome,
                         Build.SUCCEEDED,
                         "Build did not SUCCEEDED")

        logger.info("\nBuild finished %s" % build_request.build.outcome)
        return build_request.build

    def target_already_built(self, target):
        """ If the target is already built no need to build it again"""
        for build in Build.objects.filter(
                project__name=BuildTest.PROJECT_NAME):
            targets = build.target_set.values_list('target', flat=True)
            if target in targets:
                return build

        return None