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 = "/tmp/build/" 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 if os.environ.get("TOASTER_TEST_USE_SSTATE_MIRROR"): 120 ProjectVariable.objects.get_or_create( 121 name="SSTATE_MIRRORS", 122 value="file://.* http://sstate.yoctoproject.org/PATH;downloadfilename=PATH", 123 project=project) 124 125 ProjectTarget.objects.create(project=project, 126 target=target, 127 task="") 128 build_request = project.schedule_build() 129 130 # run runbuilds command to dispatch the build 131 # e.g. manage.py runubilds 132 RunBuildsCommand().runbuild() 133 134 build_pk = build_request.build.pk 135 while Build.objects.get(pk=build_pk).outcome == Build.IN_PROGRESS: 136 sys.stdout.write("\rBuilding %s %d%%" % 137 (target, 138 build_request.build.completeper())) 139 sys.stdout.flush() 140 time.sleep(1) 141 142 self.assertEqual(Build.objects.get(pk=build_pk).outcome, 143 Build.SUCCEEDED, 144 "Build did not SUCCEEDED") 145 146 logger.info("\nBuild finished %s" % build_request.build.outcome) 147 return build_request.build 148 149 def target_already_built(self, target): 150 """ If the target is already built no need to build it again""" 151 for build in Build.objects.filter( 152 project__name=BuildTest.PROJECT_NAME): 153 targets = build.target_set.values_list('target', flat=True) 154 if target in targets: 155 return build 156 157 return None 158