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