1#! /usr/bin/env python3 2# 3# BitBake Toaster Implementation 4# 5# Copyright (C) 2016 Intel Corporation 6# 7# SPDX-License-Identifier: GPL-2.0-only 8# 9 10import os 11import sys 12import time 13import unittest 14 15from orm.models import Project, Release, ProjectTarget, Build, ProjectVariable 16from bldcontrol.models import BuildEnvironment 17 18from bldcontrol.management.commands.runbuilds import Command\ 19 as RunBuildsCommand 20 21from django.core.management import call_command 22 23import subprocess 24import logging 25 26logger = logging.getLogger("toaster") 27 28# We use unittest.TestCase instead of django.test.TestCase because we don't 29# want to wrap everything in a database transaction as an external process 30# (bitbake needs access to the database) 31 32def load_build_environment(): 33 call_command('loaddata', 'settings.xml', app_label="orm") 34 call_command('loaddata', 'poky.xml', app_label="orm") 35 36 current_builddir = os.environ.get("BUILDDIR") 37 if current_builddir: 38 BuildTest.BUILDDIR = current_builddir 39 else: 40 # Setup a builddir based on default layout 41 # bitbake inside openebedded-core 42 oe_init_build_env_path = os.path.join( 43 os.path.dirname(os.path.abspath(__file__)), 44 os.pardir, 45 os.pardir, 46 os.pardir, 47 os.pardir, 48 os.pardir, 49 'oe-init-build-env' 50 ) 51 if not os.path.exists(oe_init_build_env_path): 52 raise Exception("We had no BUILDDIR set and couldn't " 53 "find oe-init-build-env to set this up " 54 "ourselves please run oe-init-build-env " 55 "before running these tests") 56 57 oe_init_build_env_path = os.path.realpath(oe_init_build_env_path) 58 cmd = "bash -c 'source oe-init-build-env %s'" % BuildTest.BUILDDIR 59 p = subprocess.Popen( 60 cmd, 61 cwd=os.path.dirname(oe_init_build_env_path), 62 shell=True, 63 stdout=subprocess.PIPE, 64 stderr=subprocess.PIPE) 65 66 output, err = p.communicate() 67 p.wait() 68 69 logger.info("oe-init-build-env %s %s" % (output, err)) 70 71 os.environ['BUILDDIR'] = BuildTest.BUILDDIR 72 73 # Setup the path to bitbake we know where to find this 74 bitbake_path = os.path.join( 75 os.path.dirname(os.path.abspath(__file__)), 76 os.pardir, 77 os.pardir, 78 os.pardir, 79 os.pardir, 80 'bin', 81 'bitbake') 82 if not os.path.exists(bitbake_path): 83 raise Exception("Could not find bitbake at the expected path %s" 84 % bitbake_path) 85 86 os.environ['BBBASEDIR'] = bitbake_path 87 88class BuildTest(unittest.TestCase): 89 90 PROJECT_NAME = "Testbuild" 91 BUILDDIR = os.environ.get("BUILDDIR") 92 93 def build(self, target): 94 # So that the buildinfo helper uses the test database' 95 self.assertEqual( 96 os.environ.get('DJANGO_SETTINGS_MODULE', ''), 97 'toastermain.settings_test', 98 "Please initialise django with the tests settings: " 99 "DJANGO_SETTINGS_MODULE='toastermain.settings_test'") 100 101 built = self.target_already_built(target) 102 if built: 103 return built 104 105 load_build_environment() 106 107 BuildEnvironment.objects.get_or_create( 108 betype=BuildEnvironment.TYPE_LOCAL, 109 sourcedir=BuildTest.BUILDDIR, 110 builddir=BuildTest.BUILDDIR 111 ) 112 113 release = Release.objects.get(name='local') 114 115 # Create a project for this build to run in 116 project = Project.objects.create_project(name=BuildTest.PROJECT_NAME, 117 release=release) 118 119 passthrough_variable_names = ["SSTATE_DIR", "DL_DIR", "SSTATE_MIRRORS", "BB_HASHSERVE", "BB_HASHSERVE_UPSTREAM"] 120 for variable_name in passthrough_variable_names: 121 current_variable = os.environ.get(variable_name) 122 if current_variable: 123 ProjectVariable.objects.get_or_create( 124 name=variable_name, 125 value=current_variable, 126 project=project) 127 128 if os.environ.get("TOASTER_TEST_USE_SSTATE_MIRROR"): 129 ProjectVariable.objects.get_or_create( 130 name="SSTATE_MIRRORS", 131 value="file://.* http://cdn.jsdelivr.net/yocto/sstate/all/PATH;downloadfilename=PATH", 132 project=project) 133 134 ProjectTarget.objects.create(project=project, 135 target=target, 136 task="") 137 build_request = project.schedule_build() 138 139 # run runbuilds command to dispatch the build 140 # e.g. manage.py runubilds 141 RunBuildsCommand().runbuild() 142 143 build_pk = build_request.build.pk 144 while Build.objects.get(pk=build_pk).outcome == Build.IN_PROGRESS: 145 sys.stdout.write("\rBuilding %s %d%%" % 146 (target, 147 build_request.build.completeper())) 148 sys.stdout.flush() 149 time.sleep(1) 150 151 self.assertEqual(Build.objects.get(pk=build_pk).outcome, 152 Build.SUCCEEDED, 153 "Build did not SUCCEEDED") 154 155 logger.info("\nBuild finished %s" % build_request.build.outcome) 156 return build_request.build 157 158 def target_already_built(self, target): 159 """ If the target is already built no need to build it again""" 160 for build in Build.objects.filter( 161 project__name=BuildTest.PROJECT_NAME): 162 targets = build.target_set.values_list('target', flat=True) 163 if target in targets: 164 return build 165 166 return None 167