diff options
Diffstat (limited to 'meta/lib/oeqa')
37 files changed, 1386 insertions, 0 deletions
diff --git a/meta/lib/oeqa/__init__.py b/meta/lib/oeqa/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/meta/lib/oeqa/__init__.py | |||
diff --git a/meta/lib/oeqa/oetest.py b/meta/lib/oeqa/oetest.py new file mode 100644 index 0000000000..529abdc19a --- /dev/null +++ b/meta/lib/oeqa/oetest.py | |||
@@ -0,0 +1,120 @@ | |||
1 | # Copyright (C) 2013 Intel Corporation | ||
2 | # | ||
3 | # Released under the MIT license (see COPYING.MIT) | ||
4 | |||
5 | # Main unittest module used by testimage.bbclass | ||
6 | # This provides the oeRuntimeTest base class which is inherited by all tests in meta/lib/oeqa/runtime. | ||
7 | |||
8 | # It also has some helper functions and it's responsible for actually starting the tests | ||
9 | |||
10 | import os, re, mmap | ||
11 | import unittest | ||
12 | import inspect | ||
13 | import bb | ||
14 | from oeqa.utils.sshcontrol import SSHControl | ||
15 | |||
16 | |||
17 | def runTests(tc): | ||
18 | |||
19 | # set the context object passed from the test class | ||
20 | setattr(oeRuntimeTest, "tc", tc) | ||
21 | # set ps command to use | ||
22 | setattr(oeRuntimeTest, "pscmd", "ps -ef" if oeRuntimeTest.hasPackage("procps") else "ps") | ||
23 | # prepare test suite, loader and runner | ||
24 | suite = unittest.TestSuite() | ||
25 | testloader = unittest.TestLoader() | ||
26 | testloader.sortTestMethodsUsing = None | ||
27 | runner = unittest.TextTestRunner(verbosity=2) | ||
28 | |||
29 | bb.note("Test modules %s" % tc.testslist) | ||
30 | suite = testloader.loadTestsFromNames(tc.testslist) | ||
31 | bb.note("Found %s tests" % suite.countTestCases()) | ||
32 | |||
33 | result = runner.run(suite) | ||
34 | |||
35 | return result | ||
36 | |||
37 | |||
38 | |||
39 | class oeRuntimeTest(unittest.TestCase): | ||
40 | |||
41 | longMessage = True | ||
42 | testFailures = [] | ||
43 | testSkipped = [] | ||
44 | testErrors = [] | ||
45 | |||
46 | def __init__(self, methodName='runTest'): | ||
47 | self.target = oeRuntimeTest.tc.target | ||
48 | super(oeRuntimeTest, self).__init__(methodName) | ||
49 | |||
50 | |||
51 | def run(self, result=None): | ||
52 | super(oeRuntimeTest, self).run(result) | ||
53 | |||
54 | # we add to our own lists the results, we use those for decorators | ||
55 | if len(result.failures) > len(oeRuntimeTest.testFailures): | ||
56 | oeRuntimeTest.testFailures.append(str(result.failures[-1][0]).split()[0]) | ||
57 | if len(result.skipped) > len(oeRuntimeTest.testSkipped): | ||
58 | oeRuntimeTest.testSkipped.append(str(result.skipped[-1][0]).split()[0]) | ||
59 | if len(result.errors) > len(oeRuntimeTest.testErrors): | ||
60 | oeRuntimeTest.testErrors.append(str(result.errors[-1][0]).split()[0]) | ||
61 | |||
62 | @classmethod | ||
63 | def hasPackage(self, pkg): | ||
64 | |||
65 | pkgfile = os.path.join(oeRuntimeTest.tc.d.getVar("WORKDIR", True), "installed_pkgs.txt") | ||
66 | |||
67 | with open(pkgfile) as f: | ||
68 | data = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) | ||
69 | match = re.search(pkg, data) | ||
70 | data.close() | ||
71 | |||
72 | if match: | ||
73 | return True | ||
74 | |||
75 | return False | ||
76 | |||
77 | @classmethod | ||
78 | def hasFeature(self,feature): | ||
79 | |||
80 | if feature in oeRuntimeTest.tc.d.getVar("IMAGE_FEATURES", True).split() or \ | ||
81 | feature in oeRuntimeTest.tc.d.getVar("DISTRO_FEATURES", True).split(): | ||
82 | return True | ||
83 | else: | ||
84 | return False | ||
85 | |||
86 | @classmethod | ||
87 | def restartTarget(self,params=None): | ||
88 | |||
89 | if oeRuntimeTest.tc.qemu.restart(params): | ||
90 | oeRuntimeTest.tc.target.host = oeRuntimeTest.tc.qemu.ip | ||
91 | else: | ||
92 | raise Exception("Restarting target failed") | ||
93 | |||
94 | |||
95 | def getmodule(pos=2): | ||
96 | # stack returns a list of tuples containg frame information | ||
97 | # First element of the list the is current frame, caller is 1 | ||
98 | frameinfo = inspect.stack()[pos] | ||
99 | modname = inspect.getmodulename(frameinfo[1]) | ||
100 | #modname = inspect.getmodule(frameinfo[0]).__name__ | ||
101 | return modname | ||
102 | |||
103 | def skipModule(reason, pos=2): | ||
104 | modname = getmodule(pos) | ||
105 | if modname not in oeRuntimeTest.tc.testsrequired: | ||
106 | raise unittest.SkipTest("%s: %s" % (modname, reason)) | ||
107 | else: | ||
108 | raise Exception("\nTest %s wants to be skipped.\nReason is: %s" \ | ||
109 | "\nTest was required in TEST_SUITES, so either the condition for skipping is wrong" \ | ||
110 | "\nor the image really doesn't have the requred feature/package when it should." % (modname, reason)) | ||
111 | |||
112 | def skipModuleIf(cond, reason): | ||
113 | |||
114 | if cond: | ||
115 | skipModule(reason, 3) | ||
116 | |||
117 | def skipModuleUnless(cond, reason): | ||
118 | |||
119 | if not cond: | ||
120 | skipModule(reason, 3) | ||
diff --git a/meta/lib/oeqa/runtime/__init__.py b/meta/lib/oeqa/runtime/__init__.py new file mode 100644 index 0000000000..4cf3fa76b6 --- /dev/null +++ b/meta/lib/oeqa/runtime/__init__.py | |||
@@ -0,0 +1,3 @@ | |||
1 | # Enable other layers to have tests in the same named directory | ||
2 | from pkgutil import extend_path | ||
3 | __path__ = extend_path(__path__, __name__) | ||
diff --git a/meta/lib/oeqa/runtime/buildcvs.py b/meta/lib/oeqa/runtime/buildcvs.py new file mode 100644 index 0000000000..f024dfa99a --- /dev/null +++ b/meta/lib/oeqa/runtime/buildcvs.py | |||
@@ -0,0 +1,32 @@ | |||
1 | from oeqa.oetest import oeRuntimeTest | ||
2 | from oeqa.utils.decorators import * | ||
3 | from oeqa.utils.targetbuild import TargetBuildProject | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasFeature("tools-sdk"): | ||
7 | skipModule("Image doesn't have tools-sdk in IMAGE_FEATURES") | ||
8 | |||
9 | class BuildCvsTest(oeRuntimeTest): | ||
10 | |||
11 | @classmethod | ||
12 | def setUpClass(self): | ||
13 | self.restartTarget("-m 512") | ||
14 | self.project = TargetBuildProject(oeRuntimeTest.tc.target, | ||
15 | "http://ftp.gnu.org/non-gnu/cvs/source/feature/1.12.13/cvs-1.12.13.tar.bz2") | ||
16 | self.project.download_archive() | ||
17 | |||
18 | @skipUnlessPassed("test_ssh") | ||
19 | def test_cvs(self): | ||
20 | self.assertEqual(self.project.run_configure(), 0, | ||
21 | msg="Running configure failed") | ||
22 | |||
23 | self.assertEqual(self.project.run_make(), 0, | ||
24 | msg="Running make failed") | ||
25 | |||
26 | self.assertEqual(self.project.run_install(), 0, | ||
27 | msg="Running make install failed") | ||
28 | |||
29 | @classmethod | ||
30 | def tearDownClass(self): | ||
31 | self.project.clean() | ||
32 | self.restartTarget() | ||
diff --git a/meta/lib/oeqa/runtime/buildiptables.py b/meta/lib/oeqa/runtime/buildiptables.py new file mode 100644 index 0000000000..88ece3bd8a --- /dev/null +++ b/meta/lib/oeqa/runtime/buildiptables.py | |||
@@ -0,0 +1,32 @@ | |||
1 | from oeqa.oetest import oeRuntimeTest | ||
2 | from oeqa.utils.decorators import * | ||
3 | from oeqa.utils.targetbuild import TargetBuildProject | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasFeature("tools-sdk"): | ||
7 | skipModule("Image doesn't have tools-sdk in IMAGE_FEATURES") | ||
8 | |||
9 | class BuildIptablesTest(oeRuntimeTest): | ||
10 | |||
11 | @classmethod | ||
12 | def setUpClass(self): | ||
13 | self.restartTarget("-m 512") | ||
14 | self.project = TargetBuildProject(oeRuntimeTest.tc.target, | ||
15 | "http://netfilter.org/projects/iptables/files/iptables-1.4.13.tar.bz2") | ||
16 | self.project.download_archive() | ||
17 | |||
18 | @skipUnlessPassed("test_ssh") | ||
19 | def test_iptables(self): | ||
20 | self.assertEqual(self.project.run_configure(), 0, | ||
21 | msg="Running configure failed") | ||
22 | |||
23 | self.assertEqual(self.project.run_make(), 0, | ||
24 | msg="Running make failed") | ||
25 | |||
26 | self.assertEqual(self.project.run_install(), 0, | ||
27 | msg="Running make install failed") | ||
28 | |||
29 | @classmethod | ||
30 | def tearDownClass(self): | ||
31 | self.project.clean() | ||
32 | self.restartTarget() | ||
diff --git a/meta/lib/oeqa/runtime/buildsudoku.py b/meta/lib/oeqa/runtime/buildsudoku.py new file mode 100644 index 0000000000..0a7306ddc7 --- /dev/null +++ b/meta/lib/oeqa/runtime/buildsudoku.py | |||
@@ -0,0 +1,29 @@ | |||
1 | from oeqa.oetest import oeRuntimeTest | ||
2 | from oeqa.utils.decorators import * | ||
3 | from oeqa.utils.targetbuild import TargetBuildProject | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasFeature("tools-sdk"): | ||
7 | skipModule("Image doesn't have tools-sdk in IMAGE_FEATURES") | ||
8 | |||
9 | class SudokuTest(oeRuntimeTest): | ||
10 | |||
11 | @classmethod | ||
12 | def setUpClass(self): | ||
13 | self.restartTarget("-m 512") | ||
14 | self.project = TargetBuildProject(oeRuntimeTest.tc.target, | ||
15 | "http://downloads.sourceforge.net/project/sudoku-savant/sudoku-savant/sudoku-savant-1.3/sudoku-savant-1.3.tar.bz2") | ||
16 | self.project.download_archive() | ||
17 | |||
18 | @skipUnlessPassed("test_ssh") | ||
19 | def test_sudoku(self): | ||
20 | self.assertEqual(self.project.run_configure(), 0, | ||
21 | msg="Running configure failed") | ||
22 | |||
23 | self.assertEqual(self.project.run_make(), 0, | ||
24 | msg="Running make failed") | ||
25 | |||
26 | @classmethod | ||
27 | def tearDownClass(self): | ||
28 | self.project.clean() | ||
29 | self.restartTarget() | ||
diff --git a/meta/lib/oeqa/runtime/connman.py b/meta/lib/oeqa/runtime/connman.py new file mode 100644 index 0000000000..5ef96f6b06 --- /dev/null +++ b/meta/lib/oeqa/runtime/connman.py | |||
@@ -0,0 +1,29 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasPackage("connman"): | ||
7 | skipModule("No connman package in image") | ||
8 | |||
9 | |||
10 | class ConnmanTest(oeRuntimeTest): | ||
11 | |||
12 | @skipUnlessPassed('test_ssh') | ||
13 | def test_connmand_help(self): | ||
14 | (status, output) = self.target.run('/usr/sbin/connmand --help') | ||
15 | self.assertEqual(status, 0, msg="status and output: %s and %s" % (status,output)) | ||
16 | |||
17 | |||
18 | @skipUnlessPassed('test_connmand_help') | ||
19 | def test_connmand_running(self): | ||
20 | (status, output) = self.target.run(oeRuntimeTest.pscmd + ' | grep [c]onnmand') | ||
21 | self.assertEqual(status, 0, msg="no connmand process, ps output: %s" % self.target.run(oeRuntimeTest.pscmd)[1]) | ||
22 | |||
23 | @skipUnlessPassed('test_connmand_running') | ||
24 | def test_connmand_unique(self): | ||
25 | self.target.run('/usr/sbin/connmand') | ||
26 | output = self.target.run(oeRuntimeTest.pscmd + ' | grep -c [c]onnmand')[1] | ||
27 | self.assertEqual(output, "1", msg="more than one connmand running in background, ps output: %s\n%s" % (output, self.target.run(oeRuntimeTest.pscmd)[1])) | ||
28 | |||
29 | |||
diff --git a/meta/lib/oeqa/runtime/date.py b/meta/lib/oeqa/runtime/date.py new file mode 100644 index 0000000000..a208e29ada --- /dev/null +++ b/meta/lib/oeqa/runtime/date.py | |||
@@ -0,0 +1,22 @@ | |||
1 | from oeqa.oetest import oeRuntimeTest | ||
2 | from oeqa.utils.decorators import * | ||
3 | import re | ||
4 | |||
5 | class DateTest(oeRuntimeTest): | ||
6 | |||
7 | @skipUnlessPassed("test_ssh") | ||
8 | def test_date(self): | ||
9 | (status, output) = self.target.run('date +"%Y-%m-%d %T"') | ||
10 | self.assertEqual(status, 0, msg="Failed to get initial date, output: %s" % output) | ||
11 | oldDate = output | ||
12 | |||
13 | sampleDate = '"2016-08-09 10:00:00"' | ||
14 | (status, output) = self.target.run("date -s %s" % sampleDate) | ||
15 | self.assertEqual(status, 0, msg="Date set failed, output: %s" % output) | ||
16 | |||
17 | (status, output) = self.target.run("date -R") | ||
18 | p = re.match('Tue, 09 Aug 2016 10:00:.. \+0000', output) | ||
19 | self.assertTrue(p, msg="The date was not set correctly, output: %s" % output) | ||
20 | |||
21 | (status, output) = self.target.run('date -s "%s"' % oldDate) | ||
22 | self.assertEqual(status, 0, msg="Failed to reset date, output: %s" % output) | ||
diff --git a/meta/lib/oeqa/runtime/df.py b/meta/lib/oeqa/runtime/df.py new file mode 100644 index 0000000000..b6da35027c --- /dev/null +++ b/meta/lib/oeqa/runtime/df.py | |||
@@ -0,0 +1,11 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | |||
6 | class DfTest(oeRuntimeTest): | ||
7 | |||
8 | @skipUnlessPassed("test_ssh") | ||
9 | def test_df(self): | ||
10 | (status,output) = self.target.run("df / | sed -n '2p' | awk '{print $4}'") | ||
11 | self.assertTrue(int(output)>5120, msg="Not enough space on image. Current size is %s" % output) | ||
diff --git a/meta/lib/oeqa/runtime/dmesg.py b/meta/lib/oeqa/runtime/dmesg.py new file mode 100644 index 0000000000..a53d1f0bf3 --- /dev/null +++ b/meta/lib/oeqa/runtime/dmesg.py | |||
@@ -0,0 +1,11 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | |||
6 | class DmesgTest(oeRuntimeTest): | ||
7 | |||
8 | @skipUnlessPassed('test_ssh') | ||
9 | def test_dmesg(self): | ||
10 | (status, output) = self.target.run('dmesg | grep -v mmci-pl18x | grep -v "error changing net interface name" | grep -i error') | ||
11 | self.assertEqual(status, 1, msg = "Error messages in dmesg log: %s" % output) | ||
diff --git a/meta/lib/oeqa/runtime/files/test.c b/meta/lib/oeqa/runtime/files/test.c new file mode 100644 index 0000000000..2d8389c92e --- /dev/null +++ b/meta/lib/oeqa/runtime/files/test.c | |||
@@ -0,0 +1,26 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <math.h> | ||
3 | #include <stdlib.h> | ||
4 | |||
5 | double convert(long long l) | ||
6 | { | ||
7 | return (double)l; | ||
8 | } | ||
9 | |||
10 | int main(int argc, char * argv[]) { | ||
11 | |||
12 | long long l = 10; | ||
13 | double f; | ||
14 | double check = 10.0; | ||
15 | |||
16 | f = convert(l); | ||
17 | printf("convert: %lld => %f\n", l, f); | ||
18 | if ( f != check ) exit(1); | ||
19 | |||
20 | f = 1234.67; | ||
21 | check = 1234.0; | ||
22 | printf("floorf(%f) = %f\n", f, floorf(f)); | ||
23 | if ( floorf(f) != check) exit(1); | ||
24 | |||
25 | return 0; | ||
26 | } | ||
diff --git a/meta/lib/oeqa/runtime/files/test.pl b/meta/lib/oeqa/runtime/files/test.pl new file mode 100644 index 0000000000..689c8f1635 --- /dev/null +++ b/meta/lib/oeqa/runtime/files/test.pl | |||
@@ -0,0 +1,2 @@ | |||
1 | $a = 9.01e+21 - 9.01e+21 + 0.01; | ||
2 | print ("the value of a is ", $a, "\n"); | ||
diff --git a/meta/lib/oeqa/runtime/files/testmakefile b/meta/lib/oeqa/runtime/files/testmakefile new file mode 100644 index 0000000000..ca1844e930 --- /dev/null +++ b/meta/lib/oeqa/runtime/files/testmakefile | |||
@@ -0,0 +1,5 @@ | |||
1 | test: test.o | ||
2 | gcc -o test test.o -lm | ||
3 | test.o: test.c | ||
4 | gcc -c test.c | ||
5 | |||
diff --git a/meta/lib/oeqa/runtime/gcc.py b/meta/lib/oeqa/runtime/gcc.py new file mode 100644 index 0000000000..b63badd3e4 --- /dev/null +++ b/meta/lib/oeqa/runtime/gcc.py | |||
@@ -0,0 +1,36 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
4 | from oeqa.utils.decorators import * | ||
5 | |||
6 | def setUpModule(): | ||
7 | if not oeRuntimeTest.hasFeature("tools-sdk"): | ||
8 | skipModule("Image doesn't have tools-sdk in IMAGE_FEATURES") | ||
9 | |||
10 | |||
11 | class GccCompileTest(oeRuntimeTest): | ||
12 | |||
13 | @classmethod | ||
14 | def setUpClass(self): | ||
15 | oeRuntimeTest.tc.target.copy_to(os.path.join(oeRuntimeTest.tc.filesdir, "test.c"), "/tmp/test.c") | ||
16 | oeRuntimeTest.tc.target.copy_to(os.path.join(oeRuntimeTest.tc.filesdir, "testmakefile"), "/tmp/testmakefile") | ||
17 | |||
18 | def test_gcc_compile(self): | ||
19 | (status, output) = self.target.run('gcc /tmp/test.c -o /tmp/test -lm') | ||
20 | self.assertEqual(status, 0, msg="gcc compile failed, output: %s" % output) | ||
21 | (status, output) = self.target.run('/tmp/test') | ||
22 | self.assertEqual(status, 0, msg="running compiled file failed, output %s" % output) | ||
23 | |||
24 | def test_gpp_compile(self): | ||
25 | (status, output) = self.target.run('g++ /tmp/test.c -o /tmp/test -lm') | ||
26 | self.assertEqual(status, 0, msg="g++ compile failed, output: %s" % output) | ||
27 | (status, output) = self.target.run('/tmp/test') | ||
28 | self.assertEqual(status, 0, msg="running compiled file failed, output %s" % output) | ||
29 | |||
30 | def test_make(self): | ||
31 | (status, output) = self.target.run('cd /tmp; make -f testmakefile') | ||
32 | self.assertEqual(status, 0, msg="running make failed, output %s" % output) | ||
33 | |||
34 | @classmethod | ||
35 | def tearDownClass(self): | ||
36 | oeRuntimeTest.tc.target.run("rm /tmp/test.c /tmp/test.o /tmp/test /tmp/testmakefile") | ||
diff --git a/meta/lib/oeqa/runtime/ldd.py b/meta/lib/oeqa/runtime/ldd.py new file mode 100644 index 0000000000..4374530fc4 --- /dev/null +++ b/meta/lib/oeqa/runtime/ldd.py | |||
@@ -0,0 +1,19 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasFeature("tools-sdk"): | ||
7 | skipModule("Image doesn't have tools-sdk in IMAGE_FEATURES") | ||
8 | |||
9 | class LddTest(oeRuntimeTest): | ||
10 | |||
11 | @skipUnlessPassed('test_ssh') | ||
12 | def test_ldd_exists(self): | ||
13 | (status, output) = self.target.run('which ldd') | ||
14 | self.assertEqual(status, 0, msg = "ldd does not exist in PATH: which ldd: %s" % output) | ||
15 | |||
16 | @skipUnlessPassed('test_ldd_exists') | ||
17 | def test_ldd_rtldlist_check(self): | ||
18 | (status, output) = self.target.run('for i in $(which ldd | xargs cat | grep "^RTLDLIST"|cut -d\'=\' -f2|tr -d \'"\'); do test -f $i && echo $i && break; done') | ||
19 | self.assertEqual(status, 0, msg = "ldd path not correct or RTLDLIST files don't exist. ") | ||
diff --git a/meta/lib/oeqa/runtime/logrotate.py b/meta/lib/oeqa/runtime/logrotate.py new file mode 100644 index 0000000000..80489a3267 --- /dev/null +++ b/meta/lib/oeqa/runtime/logrotate.py | |||
@@ -0,0 +1,27 @@ | |||
1 | # This test should cover https://bugzilla.yoctoproject.org/tr_show_case.cgi?case_id=289 testcase | ||
2 | # Note that the image under test must have logrotate installed | ||
3 | |||
4 | import unittest | ||
5 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
6 | from oeqa.utils.decorators import * | ||
7 | |||
8 | def setUpModule(): | ||
9 | if not oeRuntimeTest.hasPackage("logrotate"): | ||
10 | skipModule("No logrotate package in image") | ||
11 | |||
12 | |||
13 | class LogrotateTest(oeRuntimeTest): | ||
14 | |||
15 | @skipUnlessPassed("test_ssh") | ||
16 | def test_1_logrotate_setup(self): | ||
17 | (status, output) = self.target.run('mkdir /home/root/logrotate_dir') | ||
18 | self.assertEqual(status, 0, msg = "Could not create logrotate_dir. Output: %s" % output) | ||
19 | (status, output) = self.target.run("sed -i 's#wtmp {#wtmp {\\n olddir /home/root/logrotate_dir#' /etc/logrotate.conf") | ||
20 | self.assertEqual(status, 0, msg = "Could not write to logrotate.conf file. Status and output: %s and %s)" % (status, output)) | ||
21 | |||
22 | @skipUnlessPassed("test_1_logrotate_setup") | ||
23 | def test_2_logrotate(self): | ||
24 | (status, output) = self.target.run('logrotate -f /etc/logrotate.conf') | ||
25 | self.assertEqual(status, 0, msg = "logrotate service could not be reloaded. Status and output: %s and %s" % (status, output)) | ||
26 | output = self.target.run('ls -la /home/root/logrotate_dir/ | wc -l')[1] | ||
27 | self.assertTrue(int(output)>=3, msg = "new logfile could not be created. List of files within log directory: %s" %(self.target.run('ls -la /home/root/logrotate_dir')[1])) | ||
diff --git a/meta/lib/oeqa/runtime/multilib.py b/meta/lib/oeqa/runtime/multilib.py new file mode 100644 index 0000000000..13a3b54b18 --- /dev/null +++ b/meta/lib/oeqa/runtime/multilib.py | |||
@@ -0,0 +1,17 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | def setUpModule(): | ||
6 | multilibs = oeRuntimeTest.tc.d.getVar("MULTILIBS", True) or "" | ||
7 | if "multilib:lib32" not in multilibs: | ||
8 | skipModule("this isn't a multilib:lib32 image") | ||
9 | |||
10 | |||
11 | class MultilibTest(oeRuntimeTest): | ||
12 | |||
13 | @skipUnlessPassed('test_ssh') | ||
14 | def test_file_connman(self): | ||
15 | self.assertTrue(oeRuntimeTest.hasPackage('connman-gnome'), msg="This test assumes connman-gnome is installed") | ||
16 | (status, output) = self.target.run("readelf -h /usr/bin/connman-applet | sed -n '3p' | awk '{print $2}'") | ||
17 | self.assertEqual(output, "ELF32", msg="connman-applet isn't an ELF32 binary. readelf says: %s" % self.target.run("readelf -h /usr/bin/connman-applet")[1]) | ||
diff --git a/meta/lib/oeqa/runtime/pam.py b/meta/lib/oeqa/runtime/pam.py new file mode 100644 index 0000000000..52e1eb88e6 --- /dev/null +++ b/meta/lib/oeqa/runtime/pam.py | |||
@@ -0,0 +1,24 @@ | |||
1 | # This test should cover https://bugzilla.yoctoproject.org/tr_show_case.cgi?case_id=287 testcase | ||
2 | # Note that the image under test must have "pam" in DISTRO_FEATURES | ||
3 | |||
4 | import unittest | ||
5 | from oeqa.oetest import oeRuntimeTest | ||
6 | from oeqa.utils.decorators import * | ||
7 | |||
8 | def setUpModule(): | ||
9 | if not oeRuntimeTest.hasFeature("pam"): | ||
10 | skipModule("target doesn't have 'pam' in DISTRO_FEATURES") | ||
11 | |||
12 | |||
13 | class PamBasicTest(oeRuntimeTest): | ||
14 | |||
15 | @skipUnlessPassed('test_ssh') | ||
16 | def test_pam(self): | ||
17 | (status, output) = self.target.run('login --help') | ||
18 | self.assertEqual(status, 1, msg = "login command does not work as expected. Status and output:%s and %s" %(status, output)) | ||
19 | (status, output) = self.target.run('passwd --help') | ||
20 | self.assertEqual(status, 6, msg = "passwd command does not work as expected. Status and output:%s and %s" %(status, output)) | ||
21 | (status, output) = self.target.run('su --help') | ||
22 | self.assertEqual(status, 2, msg = "su command does not work as expected. Status and output:%s and %s" %(status, output)) | ||
23 | (status, output) = self.target.run('useradd --help') | ||
24 | self.assertEqual(status, 2, msg = "useradd command does not work as expected. Status and output:%s and %s" %(status, output)) | ||
diff --git a/meta/lib/oeqa/runtime/perl.py b/meta/lib/oeqa/runtime/perl.py new file mode 100644 index 0000000000..c9bb684c11 --- /dev/null +++ b/meta/lib/oeqa/runtime/perl.py | |||
@@ -0,0 +1,28 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
4 | from oeqa.utils.decorators import * | ||
5 | |||
6 | def setUpModule(): | ||
7 | if not oeRuntimeTest.hasPackage("perl"): | ||
8 | skipModule("No perl package in the image") | ||
9 | |||
10 | |||
11 | class PerlTest(oeRuntimeTest): | ||
12 | |||
13 | @classmethod | ||
14 | def setUpClass(self): | ||
15 | oeRuntimeTest.tc.target.copy_to(os.path.join(oeRuntimeTest.tc.filesdir, "test.pl"), "/tmp/test.pl") | ||
16 | |||
17 | def test_perl_exists(self): | ||
18 | (status, output) = self.target.run('which perl') | ||
19 | self.assertEqual(status, 0, msg="Perl binary not in PATH or not on target.") | ||
20 | |||
21 | def test_perl_works(self): | ||
22 | (status, output) = self.target.run('perl /tmp/test.pl') | ||
23 | self.assertEqual(status, 0, msg="Exit status was not 0. Output: %s" % output) | ||
24 | self.assertEqual(output, "the value of a is 0.01", msg="Incorrect output: %s" % output) | ||
25 | |||
26 | @classmethod | ||
27 | def tearDownClass(self): | ||
28 | oeRuntimeTest.tc.target.run("rm /tmp/test.pl") | ||
diff --git a/meta/lib/oeqa/runtime/ping.py b/meta/lib/oeqa/runtime/ping.py new file mode 100644 index 0000000000..0d028f9b22 --- /dev/null +++ b/meta/lib/oeqa/runtime/ping.py | |||
@@ -0,0 +1,20 @@ | |||
1 | import subprocess | ||
2 | import unittest | ||
3 | import sys | ||
4 | import time | ||
5 | from oeqa.oetest import oeRuntimeTest | ||
6 | |||
7 | class PingTest(oeRuntimeTest): | ||
8 | |||
9 | def test_ping(self): | ||
10 | output = '' | ||
11 | count = 0 | ||
12 | endtime = time.time() + 60 | ||
13 | while count < 5 and time.time() < endtime: | ||
14 | proc = subprocess.Popen("ping -c 1 %s" % oeRuntimeTest.tc.qemu.ip, shell=True, stdout=subprocess.PIPE) | ||
15 | output += proc.communicate()[0] | ||
16 | if proc.poll() == 0: | ||
17 | count += 1 | ||
18 | else: | ||
19 | count = 0 | ||
20 | self.assertEqual(count, 5, msg = "Expected 5 consecutive replies, got %d.\nping output is:\n%s" % (count,output)) | ||
diff --git a/meta/lib/oeqa/runtime/rpm.py b/meta/lib/oeqa/runtime/rpm.py new file mode 100644 index 0000000000..154cad5014 --- /dev/null +++ b/meta/lib/oeqa/runtime/rpm.py | |||
@@ -0,0 +1,49 @@ | |||
1 | import unittest | ||
2 | import os | ||
3 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
4 | from oeqa.utils.decorators import * | ||
5 | import oe.packagedata | ||
6 | |||
7 | def setUpModule(): | ||
8 | if not oeRuntimeTest.hasFeature("package-management"): | ||
9 | skipModule("rpm module skipped: target doesn't have package-management in IMAGE_FEATURES") | ||
10 | if "package_rpm" != oeRuntimeTest.tc.d.getVar("PACKAGE_CLASSES", True).split()[0]: | ||
11 | skipModule("rpm module skipped: target doesn't have rpm as primary package manager") | ||
12 | |||
13 | |||
14 | class RpmBasicTest(oeRuntimeTest): | ||
15 | |||
16 | @skipUnlessPassed('test_ssh') | ||
17 | def test_rpm_help(self): | ||
18 | (status, output) = self.target.run('rpm --help') | ||
19 | self.assertEqual(status, 0, msg="status and output: %s and %s" % (status,output)) | ||
20 | |||
21 | @skipUnlessPassed('test_rpm_help') | ||
22 | def test_rpm_query(self): | ||
23 | (status, output) = self.target.run('rpm -q rpm') | ||
24 | self.assertEqual(status, 0, msg="status and output: %s and %s" % (status,output)) | ||
25 | |||
26 | class RpmInstallRemoveTest(oeRuntimeTest): | ||
27 | |||
28 | @classmethod | ||
29 | def setUpClass(self): | ||
30 | deploydir = os.path.join(oeRuntimeTest.tc.d.getVar('DEPLOY_DIR', True), "rpm", oeRuntimeTest.tc.d.getVar('TUNE_PKGARCH', True)) | ||
31 | pkgdata = oe.packagedata.read_subpkgdata("rpm-doc", oeRuntimeTest.tc.d) | ||
32 | # pick rpm-doc as a test file to get installed, because it's small and it will always be built for standard targets | ||
33 | testrpmfile = "rpm-doc-%s-%s.%s.rpm" % (pkgdata["PKGV"], pkgdata["PKGR"], oeRuntimeTest.tc.d.getVar('TUNE_PKGARCH', True)) | ||
34 | oeRuntimeTest.tc.target.copy_to(os.path.join(deploydir,testrpmfile), "/tmp/rpm-doc.rpm") | ||
35 | |||
36 | @skipUnlessPassed('test_rpm_help') | ||
37 | def test_rpm_install(self): | ||
38 | (status, output) = self.target.run('rpm -ivh /tmp/rpm-doc.rpm') | ||
39 | self.assertEqual(status, 0, msg="Failed to install rpm-doc package: %s" % output) | ||
40 | |||
41 | @skipUnlessPassed('test_rpm_install') | ||
42 | def test_rpm_remove(self): | ||
43 | (status,output) = self.target.run('rpm -e rpm-doc') | ||
44 | self.assertEqual(status, 0, msg="Failed to remove rpm-doc package: %s" % output) | ||
45 | |||
46 | @classmethod | ||
47 | def tearDownClass(self): | ||
48 | oeRuntimeTest.tc.target.run('rm -f /tmp/rpm-doc.rpm') | ||
49 | |||
diff --git a/meta/lib/oeqa/runtime/scanelf.py b/meta/lib/oeqa/runtime/scanelf.py new file mode 100644 index 0000000000..b9abf24640 --- /dev/null +++ b/meta/lib/oeqa/runtime/scanelf.py | |||
@@ -0,0 +1,26 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasPackage("pax-utils"): | ||
7 | skipModule("pax-utils package not installed") | ||
8 | |||
9 | class ScanelfTest(oeRuntimeTest): | ||
10 | |||
11 | def setUp(self): | ||
12 | self.scancmd = 'scanelf --quiet --recursive --mount --ldpath --path' | ||
13 | |||
14 | @skipUnlessPassed('test_ssh') | ||
15 | def test_scanelf_textrel(self): | ||
16 | # print TEXTREL information | ||
17 | self.scancmd += " --textrel" | ||
18 | (status, output) = self.target.run(self.scancmd) | ||
19 | self.assertEqual(output.strip(), "", "\n".join([self.scancmd, output])) | ||
20 | |||
21 | @skipUnlessPassed('test_ssh') | ||
22 | def test_scanelf_rpath(self): | ||
23 | # print RPATH information | ||
24 | self.scancmd += " --rpath" | ||
25 | (status, output) = self.target.run(self.scancmd) | ||
26 | self.assertEqual(output.strip(), "", "\n".join([self.scancmd, output])) | ||
diff --git a/meta/lib/oeqa/runtime/scp.py b/meta/lib/oeqa/runtime/scp.py new file mode 100644 index 0000000000..03095bf966 --- /dev/null +++ b/meta/lib/oeqa/runtime/scp.py | |||
@@ -0,0 +1,21 @@ | |||
1 | import os | ||
2 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
3 | from oeqa.utils.decorators import skipUnlessPassed | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not (oeRuntimeTest.hasPackage("dropbear") or oeRuntimeTest.hasPackage("openssh-sshd")): | ||
7 | skipModule("No ssh package in image") | ||
8 | |||
9 | class ScpTest(oeRuntimeTest): | ||
10 | |||
11 | @skipUnlessPassed('test_ssh') | ||
12 | def test_scp_file(self): | ||
13 | test_log_dir = oeRuntimeTest.tc.d.getVar("TEST_LOG_DIR", True) | ||
14 | test_file_path = os.path.join(test_log_dir, 'test_scp_file') | ||
15 | with open(test_file_path, 'w') as test_scp_file: | ||
16 | test_scp_file.seek(2 ** 22 - 1) | ||
17 | test_scp_file.write(os.linesep) | ||
18 | (status, output) = self.target.copy_to(test_file_path, '/tmp/test_scp_file') | ||
19 | self.assertEqual(status, 0, msg = "File could not be copied. Output: %s" % output) | ||
20 | (status, output) = self.target.run("ls -la /tmp/test_scp_file") | ||
21 | self.assertEqual(status, 0, msg = "SCP test failed") | ||
diff --git a/meta/lib/oeqa/runtime/skeletoninit.py b/meta/lib/oeqa/runtime/skeletoninit.py new file mode 100644 index 0000000000..557e715a3e --- /dev/null +++ b/meta/lib/oeqa/runtime/skeletoninit.py | |||
@@ -0,0 +1,28 @@ | |||
1 | # This test should cover https://bugzilla.yoctoproject.org/tr_show_case.cgi?case_id=284 testcase | ||
2 | # Note that the image under test must have meta-skeleton layer in bblayers and IMAGE_INSTALL_append = " service" in local.conf | ||
3 | |||
4 | import unittest | ||
5 | from oeqa.oetest import oeRuntimeTest | ||
6 | from oeqa.utils.decorators import * | ||
7 | |||
8 | def setUpModule(): | ||
9 | if not oeRuntimeTest.hasPackage("service"): | ||
10 | skipModule("No service package in image") | ||
11 | |||
12 | |||
13 | class SkeletonBasicTest(oeRuntimeTest): | ||
14 | |||
15 | @skipUnlessPassed('test_ssh') | ||
16 | @unittest.skipIf("systemd" == oeRuntimeTest.tc.d.getVar("VIRTUAL-RUNTIME_init_manager"), "Not appropiate for systemd image") | ||
17 | def test_skeleton_availability(self): | ||
18 | (status, output) = self.target.run('ls /etc/init.d/skeleton') | ||
19 | self.assertEqual(status, 0, msg = "skeleton init script not found. Output:\n%s " % output) | ||
20 | (status, output) = self.target.run('ls /usr/sbin/skeleton-test') | ||
21 | self.assertEqual(status, 0, msg = "skeleton-test not found. Output:\n%s" % output) | ||
22 | |||
23 | @skipUnlessPassed('test_skeleton_availability') | ||
24 | @unittest.skipIf("systemd" == oeRuntimeTest.tc.d.getVar("VIRTUAL-RUNTIME_init_manager"), "Not appropiate for systemd image") | ||
25 | def test_skeleton_script(self): | ||
26 | output1 = self.target.run("/etc/init.d/skeleton start")[1] | ||
27 | (status, output2) = self.target.run(oeRuntimeTest.pscmd + ' | grep [s]keleton-test') | ||
28 | self.assertEqual(status, 0, msg = "Skeleton script could not be started:\n%s\n%s" % (output1, output2)) | ||
diff --git a/meta/lib/oeqa/runtime/smart.py b/meta/lib/oeqa/runtime/smart.py new file mode 100644 index 0000000000..c3fdf7d499 --- /dev/null +++ b/meta/lib/oeqa/runtime/smart.py | |||
@@ -0,0 +1,108 @@ | |||
1 | import unittest | ||
2 | import re | ||
3 | from oeqa.oetest import oeRuntimeTest | ||
4 | from oeqa.utils.decorators import * | ||
5 | from oeqa.utils.httpserver import HTTPService | ||
6 | |||
7 | def setUpModule(): | ||
8 | if not oeRuntimeTest.hasFeature("package-management"): | ||
9 | skipModule("Image doesn't have package management feature") | ||
10 | if not oeRuntimeTest.hasPackage("smart"): | ||
11 | skipModule("Image doesn't have smart installed") | ||
12 | |||
13 | class SmartTest(oeRuntimeTest): | ||
14 | |||
15 | @skipUnlessPassed('test_smart_help') | ||
16 | def smart(self, command, expected = 0): | ||
17 | command = 'smart %s' % command | ||
18 | status, output = self.target.run(command, 1500) | ||
19 | message = os.linesep.join([command, output]) | ||
20 | self.assertEqual(status, expected, message) | ||
21 | self.assertFalse("Cannot allocate memory" in output, message) | ||
22 | return output | ||
23 | |||
24 | class SmartBasicTest(SmartTest): | ||
25 | |||
26 | @skipUnlessPassed('test_ssh') | ||
27 | def test_smart_help(self): | ||
28 | self.smart('--help') | ||
29 | |||
30 | def test_smart_version(self): | ||
31 | self.smart('--version') | ||
32 | |||
33 | def test_smart_info(self): | ||
34 | self.smart('info python-smartpm') | ||
35 | |||
36 | def test_smart_query(self): | ||
37 | self.smart('query python-smartpm') | ||
38 | |||
39 | def test_smart_search(self): | ||
40 | self.smart('search python-smartpm') | ||
41 | |||
42 | def test_smart_stats(self): | ||
43 | self.smart('stats') | ||
44 | |||
45 | class SmartRepoTest(SmartTest): | ||
46 | |||
47 | @classmethod | ||
48 | def setUpClass(self): | ||
49 | self.repo_server = HTTPService(oeRuntimeTest.tc.d.getVar('DEPLOY_DIR', True), oeRuntimeTest.tc.qemu.host_ip) | ||
50 | self.repo_server.start() | ||
51 | |||
52 | @classmethod | ||
53 | def tearDownClass(self): | ||
54 | self.repo_server.stop() | ||
55 | |||
56 | def test_smart_channel(self): | ||
57 | self.smart('channel', 1) | ||
58 | |||
59 | def test_smart_channel_add(self): | ||
60 | image_pkgtype = self.tc.d.getVar('IMAGE_PKGTYPE', True) | ||
61 | deploy_url = 'http://%s:%s/%s' %(self.tc.qemu.host_ip, self.repo_server.port, image_pkgtype) | ||
62 | pkgarchs = self.tc.d.getVar('PACKAGE_ARCHS', True) | ||
63 | for arch in os.listdir('%s/%s' % (self.repo_server.root_dir, image_pkgtype)): | ||
64 | if arch in pkgarchs: | ||
65 | self.smart('channel -y --add {a} type=rpm-md baseurl={u}/{a}'.format(a=arch, u=deploy_url)) | ||
66 | self.smart('update') | ||
67 | |||
68 | def test_smart_channel_help(self): | ||
69 | self.smart('channel --help') | ||
70 | |||
71 | def test_smart_channel_list(self): | ||
72 | self.smart('channel --list') | ||
73 | |||
74 | def test_smart_channel_show(self): | ||
75 | self.smart('channel --show') | ||
76 | |||
77 | def test_smart_channel_rpmsys(self): | ||
78 | self.smart('channel --show rpmsys') | ||
79 | self.smart('channel --disable rpmsys') | ||
80 | self.smart('channel --enable rpmsys') | ||
81 | |||
82 | @skipUnlessPassed('test_smart_channel_add') | ||
83 | def test_smart_install(self): | ||
84 | self.smart('remove -y psplash-default') | ||
85 | self.smart('install -y psplash-default') | ||
86 | |||
87 | @skipUnlessPassed('test_smart_install') | ||
88 | def test_smart_install_dependency(self): | ||
89 | self.smart('remove -y psplash') | ||
90 | self.smart('install -y psplash-default') | ||
91 | |||
92 | @skipUnlessPassed('test_smart_channel_add') | ||
93 | def test_smart_install_from_disk(self): | ||
94 | self.smart('remove -y psplash-default') | ||
95 | self.smart('download psplash-default') | ||
96 | self.smart('install -y ./psplash-default*') | ||
97 | |||
98 | @skipUnlessPassed('test_smart_channel_add') | ||
99 | def test_smart_install_from_http(self): | ||
100 | output = self.smart('download --urls psplash-default') | ||
101 | url = re.search('(http://.*/psplash-default.*\.rpm)', output) | ||
102 | self.assertTrue(url, msg="Couln't find download url in %s" % output) | ||
103 | self.smart('remove -y psplash-default') | ||
104 | self.smart('install -y %s' % url.group(0)) | ||
105 | |||
106 | @skipUnlessPassed('test_smart_install') | ||
107 | def test_smart_reinstall(self): | ||
108 | self.smart('reinstall -y psplash-default') | ||
diff --git a/meta/lib/oeqa/runtime/ssh.py b/meta/lib/oeqa/runtime/ssh.py new file mode 100644 index 0000000000..8c96020e54 --- /dev/null +++ b/meta/lib/oeqa/runtime/ssh.py | |||
@@ -0,0 +1,16 @@ | |||
1 | import subprocess | ||
2 | import unittest | ||
3 | import sys | ||
4 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
5 | from oeqa.utils.decorators import * | ||
6 | |||
7 | def setUpModule(): | ||
8 | if not (oeRuntimeTest.hasPackage("dropbear") or oeRuntimeTest.hasPackage("openssh")): | ||
9 | skipModule("No ssh package in image") | ||
10 | |||
11 | class SshTest(oeRuntimeTest): | ||
12 | |||
13 | @skipUnlessPassed('test_ping') | ||
14 | def test_ssh(self): | ||
15 | (status, output) = self.target.run('uname -a') | ||
16 | self.assertEqual(status, 0, msg="SSH Test failed: %s" % output) | ||
diff --git a/meta/lib/oeqa/runtime/syslog.py b/meta/lib/oeqa/runtime/syslog.py new file mode 100644 index 0000000000..91d79635b7 --- /dev/null +++ b/meta/lib/oeqa/runtime/syslog.py | |||
@@ -0,0 +1,46 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasPackage("syslog"): | ||
7 | skipModule("No syslog package in image") | ||
8 | |||
9 | class SyslogTest(oeRuntimeTest): | ||
10 | |||
11 | @skipUnlessPassed("test_ssh") | ||
12 | def test_syslog_help(self): | ||
13 | (status,output) = self.target.run('/sbin/syslogd --help') | ||
14 | self.assertEqual(status, 1, msg="status and output: %s and %s" % (status,output)) | ||
15 | |||
16 | @skipUnlessPassed("test_syslog_help") | ||
17 | def test_syslog_running(self): | ||
18 | (status,output) = self.target.run(oeRuntimeTest.pscmd + ' | grep -i [s]yslogd') | ||
19 | self.assertEqual(status, 0, msg="no syslogd process, ps output: %s" % self.target.run(oeRuntimeTest.pscmd)[1]) | ||
20 | |||
21 | |||
22 | class SyslogTestConfig(oeRuntimeTest): | ||
23 | |||
24 | @skipUnlessPassed("test_syslog_running") | ||
25 | def test_syslog_logger(self): | ||
26 | (status,output) = self.target.run('logger foobar && test -e /var/log/messages && grep foobar /var/log/messages || logread | grep foobar') | ||
27 | self.assertEqual(status, 0, msg="Test log string not found in /var/log/messages. Output: %s " % output) | ||
28 | |||
29 | @skipUnlessPassed("test_syslog_running") | ||
30 | def test_syslog_restart(self): | ||
31 | if "systemd" != oeRuntimeTest.tc.d.getVar("VIRTUAL-RUNTIME_init_manager"): | ||
32 | (status,output) = self.target.run('/etc/init.d/syslog restart') | ||
33 | else: | ||
34 | (status,output) = self.target.run('systemctl restart syslog.service') | ||
35 | |||
36 | @skipUnlessPassed("test_syslog_restart") | ||
37 | @skipUnlessPassed("test_syslog_logger") | ||
38 | @unittest.skipIf("systemd" == oeRuntimeTest.tc.d.getVar("VIRTUAL-RUNTIME_init_manager"), "Not appropiate for systemd image") | ||
39 | def test_syslog_startup_config(self): | ||
40 | self.target.run('echo "LOGFILE=/var/log/test" >> /etc/syslog-startup.conf') | ||
41 | (status,output) = self.target.run('/etc/init.d/syslog restart') | ||
42 | self.assertEqual(status, 0, msg="Could not restart syslog service. Status and output: %s and %s" % (status,output)) | ||
43 | (status,output) = self.target.run('logger foobar && grep foobar /var/log/test') | ||
44 | self.assertEqual(status, 0, msg="Test log string not found. Output: %s " % output) | ||
45 | self.target.run("sed -i 's#LOGFILE=/var/log/test##' /etc/syslog-startup.conf") | ||
46 | self.target.run('/etc/init.d/syslog restart') | ||
diff --git a/meta/lib/oeqa/runtime/systemd.py b/meta/lib/oeqa/runtime/systemd.py new file mode 100644 index 0000000000..e4f433632f --- /dev/null +++ b/meta/lib/oeqa/runtime/systemd.py | |||
@@ -0,0 +1,59 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasFeature("systemd"): | ||
7 | skipModule("target doesn't have systemd in DISTRO_FEATURES") | ||
8 | if "systemd" != oeRuntimeTest.tc.d.getVar("VIRTUAL-RUNTIME_init_manager", True): | ||
9 | skipModule("systemd is not the init manager for this image") | ||
10 | |||
11 | |||
12 | class SystemdBasicTest(oeRuntimeTest): | ||
13 | |||
14 | @skipUnlessPassed('test_ssh') | ||
15 | def test_systemd_version(self): | ||
16 | (status, output) = self.target.run('systemctl --version') | ||
17 | self.assertEqual(status, 0, msg="status and output: %s and %s" % (status,output)) | ||
18 | |||
19 | class SystemdTests(oeRuntimeTest): | ||
20 | |||
21 | @skipUnlessPassed('test_systemd_version') | ||
22 | def test_systemd_failed(self): | ||
23 | (status, output) = self.target.run('systemctl --failed | grep "0 loaded units listed"') | ||
24 | self.assertEqual(status, 0, msg="Failed systemd services: %s" % self.target.run('systemctl --failed')[1]) | ||
25 | |||
26 | @skipUnlessPassed('test_systemd_version') | ||
27 | def test_systemd_service(self): | ||
28 | (status, output) = self.target.run('systemctl list-unit-files | grep "systemd-hostnamed.service"') | ||
29 | self.assertEqual(status, 0, msg="systemd-hostnamed.service service is not available.") | ||
30 | |||
31 | @skipUnlessPassed('test_systemd_service') | ||
32 | def test_systemd_stop(self): | ||
33 | self.target.run('systemctl stop systemd-hostnamed.service') | ||
34 | (status, output) = self.target.run('systemctl show systemd-hostnamed.service | grep "ActiveState" | grep "=inactive"') | ||
35 | self.assertEqual(status, 0, msg="systemd-hostnamed.service service could not be stopped.Status and output: %s and %s" % (status, output)) | ||
36 | |||
37 | @skipUnlessPassed('test_systemd_stop') | ||
38 | @skipUnlessPassed('test_systemd_version') | ||
39 | def test_systemd_start(self): | ||
40 | self.target.run('systemctl start systemd-hostnamed.service') | ||
41 | (status, output) = self.target.run('systemctl show systemd-hostnamed.service | grep "ActiveState" | grep "=active"') | ||
42 | self.assertEqual(status, 0, msg="systemd-hostnamed.service service could not be started. Status and output: %s and %s" % (status, output)) | ||
43 | |||
44 | @skipUnlessPassed('test_systemd_version') | ||
45 | def test_systemd_enable(self): | ||
46 | self.target.run('systemctl enable machineid.service') | ||
47 | (status, output) = self.target.run('systemctl is-enabled machineid.service') | ||
48 | self.assertEqual(output, 'enabled', msg="machineid.service service could not be enabled. Status and output: %s and %s" % (status, output)) | ||
49 | |||
50 | @skipUnlessPassed('test_systemd_enable') | ||
51 | def test_systemd_disable(self): | ||
52 | self.target.run('systemctl disable machineid.service') | ||
53 | (status, output) = self.target.run('systemctl is-enabled machineid.service') | ||
54 | self.assertEqual(output, 'disabled', msg="machineid.service service could not be disabled. Status and output: %s and %s" % (status, output)) | ||
55 | |||
56 | @skipUnlessPassed('test_systemd_version') | ||
57 | def test_systemd_list(self): | ||
58 | (status, output) = self.target.run('systemctl list-unit-files') | ||
59 | self.assertEqual(status, 0, msg="systemctl list-unit-files command failed. Status: %s" % status) | ||
diff --git a/meta/lib/oeqa/runtime/vnc.py b/meta/lib/oeqa/runtime/vnc.py new file mode 100644 index 0000000000..5ed10727bc --- /dev/null +++ b/meta/lib/oeqa/runtime/vnc.py | |||
@@ -0,0 +1,19 @@ | |||
1 | from oeqa.oetest import oeRuntimeTest | ||
2 | from oeqa.utils.decorators import * | ||
3 | import re | ||
4 | |||
5 | def setUpModule(): | ||
6 | skipModuleUnless(oeRuntimeTest.hasPackage('x11vnc'), "No x11vnc package in image") | ||
7 | |||
8 | class VNCTest(oeRuntimeTest): | ||
9 | |||
10 | @skipUnlessPassed('test_ssh') | ||
11 | def test_vnc(self): | ||
12 | (status, output) = self.target.run('x11vnc -display :0 -bg -o x11vnc.log') | ||
13 | self.assertEqual(status, 0, msg="x11vnc server failed to start: %s" % output) | ||
14 | port = re.search('PORT=[0-9]*', output) | ||
15 | self.assertTrue(port, msg="Listening port not specified in command output: %s" %output) | ||
16 | |||
17 | vncport = port.group(0).split('=')[1] | ||
18 | (status, output) = self.target.run('netstat -ntl | grep ":%s"' % vncport) | ||
19 | self.assertEqual(status, 0, msg="x11vnc server not running on port %s\n\n%s" % (vncport, self.target.run('netstat -ntl; cat x11vnc.log')[1])) | ||
diff --git a/meta/lib/oeqa/runtime/x32lib.py b/meta/lib/oeqa/runtime/x32lib.py new file mode 100644 index 0000000000..6bad201b12 --- /dev/null +++ b/meta/lib/oeqa/runtime/x32lib.py | |||
@@ -0,0 +1,17 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | def setUpModule(): | ||
6 | #check if DEFAULTTUNE is set and it's value is: x86-64-x32 | ||
7 | defaulttune = oeRuntimeTest.tc.d.getVar("DEFAULTTUNE", True) | ||
8 | if "x86-64-x32" not in defaulttune: | ||
9 | skipModule("DEFAULTTUNE is not set to x86-64-x32") | ||
10 | |||
11 | class X32libTest(oeRuntimeTest): | ||
12 | |||
13 | @skipUnlessPassed("test_ssh") | ||
14 | def test_x32_file(self): | ||
15 | status1 = self.target.run("readelf -h /bin/ls | grep Class | grep ELF32")[0] | ||
16 | status2 = self.target.run("readelf -h /bin/ls | grep Machine | grep X86-64")[0] | ||
17 | self.assertTrue(status1 == 0 and status2 == 0, msg="/bin/ls isn't an X86-64 ELF32 binary. readelf says: %s" % self.target.run("readelf -h /bin/ls")[1]) | ||
diff --git a/meta/lib/oeqa/runtime/xorg.py b/meta/lib/oeqa/runtime/xorg.py new file mode 100644 index 0000000000..12dccd8198 --- /dev/null +++ b/meta/lib/oeqa/runtime/xorg.py | |||
@@ -0,0 +1,21 @@ | |||
1 | import unittest | ||
2 | from oeqa.oetest import oeRuntimeTest, skipModule | ||
3 | from oeqa.utils.decorators import * | ||
4 | |||
5 | def setUpModule(): | ||
6 | if not oeRuntimeTest.hasFeature("x11-base"): | ||
7 | skipModule("target doesn't have x11 in IMAGE_FEATURES") | ||
8 | |||
9 | |||
10 | class XorgTest(oeRuntimeTest): | ||
11 | |||
12 | @skipUnlessPassed('test_ssh') | ||
13 | def test_xorg_running(self): | ||
14 | (status, output) = self.target.run(oeRuntimeTest.pscmd + ' | grep -v xinit | grep [X]org') | ||
15 | self.assertEqual(status, 0, msg="Xorg does not appear to be running %s" % self.target.run(oeRuntimeTest.pscmd)[1]) | ||
16 | |||
17 | @skipUnlessPassed('test_ssh') | ||
18 | def test_xorg_error(self): | ||
19 | (status, output) = self.target.run('cat /var/log/Xorg.0.log | grep -v "(EE) error," | grep -v "PreInit" | grep -v "evdev:" | grep -v "glx" | grep "(EE)"') | ||
20 | self.assertEqual(status, 1, msg="Errors in Xorg log: %s" % output) | ||
21 | |||
diff --git a/meta/lib/oeqa/utils/__init__.py b/meta/lib/oeqa/utils/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/meta/lib/oeqa/utils/__init__.py | |||
diff --git a/meta/lib/oeqa/utils/decorators.py b/meta/lib/oeqa/utils/decorators.py new file mode 100644 index 0000000000..33fed5a10b --- /dev/null +++ b/meta/lib/oeqa/utils/decorators.py | |||
@@ -0,0 +1,50 @@ | |||
1 | # Copyright (C) 2013 Intel Corporation | ||
2 | # | ||
3 | # Released under the MIT license (see COPYING.MIT) | ||
4 | |||
5 | # Some custom decorators that can be used by unittests | ||
6 | # Most useful is skipUnlessPassed which can be used for | ||
7 | # creating dependecies between two test methods. | ||
8 | |||
9 | from oeqa.oetest import * | ||
10 | |||
11 | class skipIfFailure(object): | ||
12 | |||
13 | def __init__(self,testcase): | ||
14 | self.testcase = testcase | ||
15 | |||
16 | def __call__(self,f): | ||
17 | def wrapped_f(*args): | ||
18 | if self.testcase in (oeRuntimeTest.testFailures or oeRuntimeTest.testErrors): | ||
19 | raise unittest.SkipTest("Testcase dependency not met: %s" % self.testcase) | ||
20 | return f(*args) | ||
21 | wrapped_f.__name__ = f.__name__ | ||
22 | return wrapped_f | ||
23 | |||
24 | class skipIfSkipped(object): | ||
25 | |||
26 | def __init__(self,testcase): | ||
27 | self.testcase = testcase | ||
28 | |||
29 | def __call__(self,f): | ||
30 | def wrapped_f(*args): | ||
31 | if self.testcase in oeRuntimeTest.testSkipped: | ||
32 | raise unittest.SkipTest("Testcase dependency not met: %s" % self.testcase) | ||
33 | return f(*args) | ||
34 | wrapped_f.__name__ = f.__name__ | ||
35 | return wrapped_f | ||
36 | |||
37 | class skipUnlessPassed(object): | ||
38 | |||
39 | def __init__(self,testcase): | ||
40 | self.testcase = testcase | ||
41 | |||
42 | def __call__(self,f): | ||
43 | def wrapped_f(*args): | ||
44 | if self.testcase in oeRuntimeTest.testSkipped or \ | ||
45 | self.testcase in oeRuntimeTest.testFailures or \ | ||
46 | self.testcase in oeRuntimeTest.testErrors: | ||
47 | raise unittest.SkipTest("Testcase dependency not met: %s" % self.testcase) | ||
48 | return f(*args) | ||
49 | wrapped_f.__name__ = f.__name__ | ||
50 | return wrapped_f | ||
diff --git a/meta/lib/oeqa/utils/httpserver.py b/meta/lib/oeqa/utils/httpserver.py new file mode 100644 index 0000000000..f161a1bddd --- /dev/null +++ b/meta/lib/oeqa/utils/httpserver.py | |||
@@ -0,0 +1,33 @@ | |||
1 | import SimpleHTTPServer | ||
2 | import multiprocessing | ||
3 | import os | ||
4 | |||
5 | class HTTPServer(SimpleHTTPServer.BaseHTTPServer.HTTPServer): | ||
6 | |||
7 | def server_start(self, root_dir): | ||
8 | os.chdir(root_dir) | ||
9 | self.serve_forever() | ||
10 | |||
11 | class HTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): | ||
12 | |||
13 | def log_message(self, format_str, *args): | ||
14 | pass | ||
15 | |||
16 | class HTTPService(object): | ||
17 | |||
18 | def __init__(self, root_dir, host=''): | ||
19 | self.root_dir = root_dir | ||
20 | self.host = host | ||
21 | self.port = 0 | ||
22 | |||
23 | def start(self): | ||
24 | self.server = HTTPServer((self.host, self.port), HTTPRequestHandler) | ||
25 | if self.port == 0: | ||
26 | self.port = self.server.server_port | ||
27 | self.process = multiprocessing.Process(target=self.server.server_start, args=[self.root_dir]) | ||
28 | self.process.start() | ||
29 | |||
30 | def stop(self): | ||
31 | self.server.server_close() | ||
32 | self.process.terminate() | ||
33 | self.process.join() | ||
diff --git a/meta/lib/oeqa/utils/qemurunner.py b/meta/lib/oeqa/utils/qemurunner.py new file mode 100644 index 0000000000..256cf3c6a8 --- /dev/null +++ b/meta/lib/oeqa/utils/qemurunner.py | |||
@@ -0,0 +1,228 @@ | |||
1 | # Copyright (C) 2013 Intel Corporation | ||
2 | # | ||
3 | # Released under the MIT license (see COPYING.MIT) | ||
4 | |||
5 | # This module provides a class for starting qemu images using runqemu. | ||
6 | # It's used by testimage.bbclass. | ||
7 | |||
8 | import subprocess | ||
9 | import os | ||
10 | import time | ||
11 | import signal | ||
12 | import re | ||
13 | import socket | ||
14 | import select | ||
15 | import bb | ||
16 | |||
17 | class QemuRunner: | ||
18 | |||
19 | def __init__(self, machine, rootfs, display = None, tmpdir = None, deploy_dir_image = None, logfile = None, boottime = 400, runqemutime = 60): | ||
20 | # Popen object | ||
21 | self.runqemu = None | ||
22 | |||
23 | self.machine = machine | ||
24 | self.rootfs = rootfs | ||
25 | |||
26 | self.qemupid = None | ||
27 | self.ip = None | ||
28 | |||
29 | self.display = display | ||
30 | self.tmpdir = tmpdir | ||
31 | self.deploy_dir_image = deploy_dir_image | ||
32 | self.logfile = logfile | ||
33 | self.boottime = boottime | ||
34 | self.runqemutime = runqemutime | ||
35 | |||
36 | self.create_socket() | ||
37 | |||
38 | def create_socket(self): | ||
39 | |||
40 | self.bootlog = '' | ||
41 | self.qemusock = None | ||
42 | |||
43 | try: | ||
44 | self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) | ||
45 | self.server_socket.setblocking(0) | ||
46 | self.server_socket.bind(("127.0.0.1",0)) | ||
47 | self.server_socket.listen(2) | ||
48 | self.serverport = self.server_socket.getsockname()[1] | ||
49 | bb.note("Created listening socket for qemu serial console on: 127.0.0.1:%s" % self.serverport) | ||
50 | except socket.error, msg: | ||
51 | self.server_socket.close() | ||
52 | bb.fatal("Failed to create listening socket: %s" %msg[1]) | ||
53 | |||
54 | |||
55 | def log(self, msg): | ||
56 | if self.logfile: | ||
57 | with open(self.logfile, "a") as f: | ||
58 | f.write("%s" % msg) | ||
59 | |||
60 | def launch(self, qemuparams = None): | ||
61 | |||
62 | if self.display: | ||
63 | os.environ["DISPLAY"] = self.display | ||
64 | else: | ||
65 | bb.error("To start qemu I need a X desktop, please set DISPLAY correctly (e.g. DISPLAY=:1)") | ||
66 | return False | ||
67 | if not os.path.exists(self.rootfs): | ||
68 | bb.error("Invalid rootfs %s" % self.rootfs) | ||
69 | return False | ||
70 | if not os.path.exists(self.tmpdir): | ||
71 | bb.error("Invalid TMPDIR path %s" % self.tmpdir) | ||
72 | return False | ||
73 | else: | ||
74 | os.environ["OE_TMPDIR"] = self.tmpdir | ||
75 | if not os.path.exists(self.deploy_dir_image): | ||
76 | bb.error("Invalid DEPLOY_DIR_IMAGE path %s" % self.deploy_dir_image) | ||
77 | return False | ||
78 | else: | ||
79 | os.environ["DEPLOY_DIR_IMAGE"] = self.deploy_dir_image | ||
80 | |||
81 | # Set this flag so that Qemu doesn't do any grabs as SDL grabs interact | ||
82 | # badly with screensavers. | ||
83 | os.environ["QEMU_DONT_GRAB"] = "1" | ||
84 | self.qemuparams = 'bootparams="console=tty1 console=ttyS0,115200n8" qemuparams="-serial tcp:127.0.0.1:%s"' % self.serverport | ||
85 | if qemuparams: | ||
86 | self.qemuparams = self.qemuparams[:-1] + " " + qemuparams + " " + '\"' | ||
87 | |||
88 | launch_cmd = 'runqemu %s %s %s' % (self.machine, self.rootfs, self.qemuparams) | ||
89 | self.runqemu = subprocess.Popen(launch_cmd,shell=True,stdout=subprocess.PIPE,stderr=subprocess.STDOUT,preexec_fn=os.setpgrp) | ||
90 | |||
91 | bb.note("runqemu started, pid is %s" % self.runqemu.pid) | ||
92 | bb.note("waiting at most %s seconds for qemu pid" % self.runqemutime) | ||
93 | endtime = time.time() + self.runqemutime | ||
94 | while not self.is_alive() and time.time() < endtime: | ||
95 | time.sleep(1) | ||
96 | |||
97 | if self.is_alive(): | ||
98 | bb.note("qemu started - qemu procces pid is %s" % self.qemupid) | ||
99 | cmdline = open('/proc/%s/cmdline' % self.qemupid).read() | ||
100 | self.ip, _, self.host_ip = cmdline.split('ip=')[1].split(' ')[0].split(':')[0:3] | ||
101 | if not re.search("^((?:[0-9]{1,3}\.){3}[0-9]{1,3})$", self.ip): | ||
102 | bb.note("Couldn't get ip from qemu process arguments, I got '%s'" % self.ip) | ||
103 | bb.note("Here is the ps output:\n%s" % cmdline) | ||
104 | self.kill() | ||
105 | return False | ||
106 | bb.note("IP found: %s" % self.ip) | ||
107 | bb.note("Waiting at most %d seconds for login banner" % self.boottime ) | ||
108 | endtime = time.time() + self.boottime | ||
109 | socklist = [self.server_socket] | ||
110 | reachedlogin = False | ||
111 | stopread = False | ||
112 | while time.time() < endtime and not stopread: | ||
113 | sread, swrite, serror = select.select(socklist, [], [], 5) | ||
114 | for sock in sread: | ||
115 | if sock is self.server_socket: | ||
116 | self.qemusock, addr = self.server_socket.accept() | ||
117 | self.qemusock.setblocking(0) | ||
118 | socklist.append(self.qemusock) | ||
119 | socklist.remove(self.server_socket) | ||
120 | bb.note("Connection from %s:%s" % addr) | ||
121 | else: | ||
122 | data = sock.recv(1024) | ||
123 | if data: | ||
124 | self.log(data) | ||
125 | self.bootlog += data | ||
126 | lastlines = "\n".join(self.bootlog.splitlines()[-2:]) | ||
127 | if re.search("login:", lastlines): | ||
128 | stopread = True | ||
129 | reachedlogin = True | ||
130 | bb.note("Reached login banner") | ||
131 | else: | ||
132 | socklist.remove(sock) | ||
133 | sock.close() | ||
134 | stopread = True | ||
135 | |||
136 | if not reachedlogin: | ||
137 | bb.note("Target didn't reached login boot in %d seconds" % self.boottime) | ||
138 | lines = "\n".join(self.bootlog.splitlines()[-5:]) | ||
139 | bb.note("Last 5 lines of text:\n%s" % lines) | ||
140 | bb.note("Check full boot log: %s" % self.logfile) | ||
141 | self.kill() | ||
142 | return False | ||
143 | else: | ||
144 | bb.note("Qemu pid didn't appeared in %s seconds" % self.runqemutime) | ||
145 | output = self.runqemu.stdout | ||
146 | self.kill() | ||
147 | bb.note("Output from runqemu:\n%s" % output.read()) | ||
148 | return False | ||
149 | |||
150 | return self.is_alive() | ||
151 | |||
152 | def kill(self): | ||
153 | |||
154 | if self.runqemu: | ||
155 | bb.note("Sending SIGTERM to runqemu") | ||
156 | os.kill(-self.runqemu.pid,signal.SIGTERM) | ||
157 | endtime = time.time() + self.runqemutime | ||
158 | while self.runqemu.poll() is None and time.time() < endtime: | ||
159 | time.sleep(1) | ||
160 | if self.runqemu.poll() is None: | ||
161 | bb.note("Sending SIGKILL to runqemu") | ||
162 | os.kill(-self.runqemu.pid,signal.SIGKILL) | ||
163 | self.runqemu = None | ||
164 | if self.server_socket: | ||
165 | self.server_socket.close() | ||
166 | self.server_socket = None | ||
167 | self.qemupid = None | ||
168 | self.ip = None | ||
169 | |||
170 | def restart(self, qemuparams = None): | ||
171 | bb.note("Restarting qemu process") | ||
172 | if self.runqemu.poll() is None: | ||
173 | self.kill() | ||
174 | self.create_socket() | ||
175 | if self.launch(qemuparams): | ||
176 | return True | ||
177 | return False | ||
178 | |||
179 | def is_alive(self): | ||
180 | qemu_child = self.find_child(str(self.runqemu.pid)) | ||
181 | if qemu_child: | ||
182 | self.qemupid = qemu_child[0] | ||
183 | if os.path.exists("/proc/" + str(self.qemupid)): | ||
184 | return True | ||
185 | return False | ||
186 | |||
187 | def find_child(self,parent_pid): | ||
188 | # | ||
189 | # Walk the process tree from the process specified looking for a qemu-system. Return its [pid'cmd] | ||
190 | # | ||
191 | ps = subprocess.Popen(['ps', 'axww', '-o', 'pid,ppid,command'], stdout=subprocess.PIPE).communicate()[0] | ||
192 | processes = ps.split('\n') | ||
193 | nfields = len(processes[0].split()) - 1 | ||
194 | pids = {} | ||
195 | commands = {} | ||
196 | for row in processes[1:]: | ||
197 | data = row.split(None, nfields) | ||
198 | if len(data) != 3: | ||
199 | continue | ||
200 | if data[1] not in pids: | ||
201 | pids[data[1]] = [] | ||
202 | |||
203 | pids[data[1]].append(data[0]) | ||
204 | commands[data[0]] = data[2] | ||
205 | |||
206 | if parent_pid not in pids: | ||
207 | return [] | ||
208 | |||
209 | parents = [] | ||
210 | newparents = pids[parent_pid] | ||
211 | while newparents: | ||
212 | next = [] | ||
213 | for p in newparents: | ||
214 | if p in pids: | ||
215 | for n in pids[p]: | ||
216 | if n not in parents and n not in next: | ||
217 | next.append(n) | ||
218 | if p not in parents: | ||
219 | parents.append(p) | ||
220 | newparents = next | ||
221 | #print "Children matching %s:" % str(parents) | ||
222 | for p in parents: | ||
223 | # Need to be careful here since runqemu-internal runs "ldd qemu-system-xxxx" | ||
224 | # Also, old versions of ldd (2.11) run "LD_XXXX qemu-system-xxxx" | ||
225 | basecmd = commands[p].split()[0] | ||
226 | basecmd = os.path.basename(basecmd) | ||
227 | if "qemu-system" in basecmd and "-serial tcp" in commands[p]: | ||
228 | return [int(p),commands[p]] | ||
diff --git a/meta/lib/oeqa/utils/sshcontrol.py b/meta/lib/oeqa/utils/sshcontrol.py new file mode 100644 index 0000000000..1539ff2a37 --- /dev/null +++ b/meta/lib/oeqa/utils/sshcontrol.py | |||
@@ -0,0 +1,109 @@ | |||
1 | # Copyright (C) 2013 Intel Corporation | ||
2 | # | ||
3 | # Released under the MIT license (see COPYING.MIT) | ||
4 | |||
5 | # Provides a class for setting up ssh connections, | ||
6 | # running commands and copying files to/from a target. | ||
7 | # It's used by testimage.bbclass and tests in lib/oeqa/runtime. | ||
8 | |||
9 | import subprocess | ||
10 | import time | ||
11 | import os | ||
12 | |||
13 | class SSHControl(object): | ||
14 | |||
15 | def __init__(self, host=None, timeout=300, logfile=None): | ||
16 | self.host = host | ||
17 | self.timeout = timeout | ||
18 | self._starttime = None | ||
19 | self._out = '' | ||
20 | self._ret = 126 | ||
21 | self.logfile = logfile | ||
22 | self.ssh_options = [ | ||
23 | '-o', 'UserKnownHostsFile=/dev/null', | ||
24 | '-o', 'StrictHostKeyChecking=no', | ||
25 | '-o', 'LogLevel=ERROR' | ||
26 | ] | ||
27 | self.ssh = ['ssh', '-l', 'root'] + self.ssh_options | ||
28 | |||
29 | def log(self, msg): | ||
30 | if self.logfile: | ||
31 | with open(self.logfile, "a") as f: | ||
32 | f.write("%s\n" % msg) | ||
33 | |||
34 | def _internal_run(self, cmd): | ||
35 | # We need this for a proper PATH | ||
36 | cmd = ". /etc/profile; " + cmd | ||
37 | command = self.ssh + [self.host, cmd] | ||
38 | self.log("[Running]$ %s" % " ".join(command)) | ||
39 | self._starttime = time.time() | ||
40 | # ssh hangs without os.setsid | ||
41 | proc = subprocess.Popen(command, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=os.setsid) | ||
42 | return proc | ||
43 | |||
44 | def run(self, cmd, timeout=None): | ||
45 | """Run cmd and get it's return code and output. | ||
46 | Let it run for timeout seconds and then terminate/kill it, | ||
47 | if time is 0 will let cmd run until it finishes. | ||
48 | Time can be passed to here or can be set per class instance.""" | ||
49 | |||
50 | if self.host: | ||
51 | sshconn = self._internal_run(cmd) | ||
52 | else: | ||
53 | raise Exception("Remote IP hasn't been set: '%s'" % actualcmd) | ||
54 | |||
55 | if timeout == 0: | ||
56 | self._out = sshconn.communicate()[0] | ||
57 | self._ret = sshconn.poll() | ||
58 | else: | ||
59 | if timeout is None: | ||
60 | tdelta = self.timeout | ||
61 | else: | ||
62 | tdelta = timeout | ||
63 | endtime = self._starttime + tdelta | ||
64 | while sshconn.poll() is None and time.time() < endtime: | ||
65 | time.sleep(1) | ||
66 | # process hasn't returned yet | ||
67 | if sshconn.poll() is None: | ||
68 | self._ret = 255 | ||
69 | sshconn.terminate() | ||
70 | sshconn.kill() | ||
71 | self._out = sshconn.stdout.read() | ||
72 | sshconn.stdout.close() | ||
73 | self._out += "\n[!!! SSH command timed out after %d seconds and it was killed]" % tdelta | ||
74 | else: | ||
75 | self._out = sshconn.stdout.read() | ||
76 | self._ret = sshconn.poll() | ||
77 | # strip the last LF so we can test the output | ||
78 | self._out = self._out.rstrip() | ||
79 | self.log("%s" % self._out) | ||
80 | self.log("[SSH command returned after %d seconds]: %s" % (time.time() - self._starttime, self._ret)) | ||
81 | return (self._ret, self._out) | ||
82 | |||
83 | def _internal_scp(self, cmd): | ||
84 | cmd = ['scp'] + self.ssh_options + cmd | ||
85 | self.log("[Running SCP]$ %s" % " ".join(cmd)) | ||
86 | self._starttime = time.time() | ||
87 | scpconn = subprocess.Popen(cmd, shell=False, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, preexec_fn=os.setsid) | ||
88 | out = scpconn.communicate()[0] | ||
89 | ret = scpconn.poll() | ||
90 | self.log("%s" % out) | ||
91 | self.log("[SCP command returned after %d seconds]: %s" % (time.time() - self._starttime, ret)) | ||
92 | if ret != 0: | ||
93 | # we raise an exception so that tests fail in setUp and setUpClass without a need for an assert | ||
94 | raise Exception("Error running %s, output: %s" % ( " ".join(cmd), out)) | ||
95 | return (ret, out) | ||
96 | |||
97 | def copy_to(self, localpath, remotepath): | ||
98 | actualcmd = [localpath, 'root@%s:%s' % (self.host, remotepath)] | ||
99 | return self._internal_scp(actualcmd) | ||
100 | |||
101 | def copy_from(self, remotepath, localpath): | ||
102 | actualcmd = ['root@%s:%s' % (self.host, remotepath), localpath] | ||
103 | return self._internal_scp(actualcmd) | ||
104 | |||
105 | def get_status(self): | ||
106 | return self._ret | ||
107 | |||
108 | def get_output(self): | ||
109 | return self._out | ||
diff --git a/meta/lib/oeqa/utils/targetbuild.py b/meta/lib/oeqa/utils/targetbuild.py new file mode 100644 index 0000000000..9b2cf53773 --- /dev/null +++ b/meta/lib/oeqa/utils/targetbuild.py | |||
@@ -0,0 +1,63 @@ | |||
1 | # Copyright (C) 2013 Intel Corporation | ||
2 | # | ||
3 | # Released under the MIT license (see COPYING.MIT) | ||
4 | |||
5 | # Provides a class for automating build tests for projects | ||
6 | |||
7 | from oeqa.oetest import oeRuntimeTest | ||
8 | import bb.fetch2 | ||
9 | import bb.data | ||
10 | import os | ||
11 | import re | ||
12 | |||
13 | |||
14 | class TargetBuildProject(): | ||
15 | |||
16 | def __init__(self, target, uri, foldername=None): | ||
17 | self.target = target | ||
18 | self.uri = uri | ||
19 | self.targetdir = "/home/root/" | ||
20 | |||
21 | self.localdata = bb.data.createCopy(oeRuntimeTest.tc.d) | ||
22 | bb.data.update_data(self.localdata) | ||
23 | |||
24 | if not foldername: | ||
25 | self.archive = os.path.basename(uri) | ||
26 | self.fname = re.sub(r'.tar.bz2|tar.gz$', '', self.archive) | ||
27 | else: | ||
28 | self.fname = foldername | ||
29 | |||
30 | def download_archive(self): | ||
31 | |||
32 | try: | ||
33 | self.localdata.delVar("BB_STRICT_CHECKSUM") | ||
34 | fetcher = bb.fetch2.Fetch([self.uri], self.localdata) | ||
35 | fetcher.download() | ||
36 | self.localarchive = fetcher.localpath(self.uri) | ||
37 | except bb.fetch2.BBFetchException: | ||
38 | raise Exception("Failed to download archive: %s" % self.uri) | ||
39 | |||
40 | (status, output) = self.target.copy_to(self.localarchive, self.targetdir) | ||
41 | if status != 0: | ||
42 | raise Exception("Failed to copy archive to target, output: %s" % output) | ||
43 | |||
44 | (status, output) = self.target.run('tar xf %s%s -C %s' % (self.targetdir, self.archive, self.targetdir)) | ||
45 | if status != 0: | ||
46 | raise Exception("Failed to extract archive, output: %s" % output) | ||
47 | |||
48 | #Change targetdir to project folder | ||
49 | self.targetdir = self.targetdir + self.fname | ||
50 | |||
51 | # The timeout parameter of target.run is set to 0 to make the ssh command | ||
52 | # run with no timeout. | ||
53 | def run_configure(self): | ||
54 | return self.target.run('cd %s; ./configure' % self.targetdir, 0)[0] | ||
55 | |||
56 | def run_make(self): | ||
57 | return self.target.run('cd %s; make' % self.targetdir, 0)[0] | ||
58 | |||
59 | def run_install(self): | ||
60 | return self.target.run('cd %s; make install' % self.targetdir, 0)[0] | ||
61 | |||
62 | def clean(self): | ||
63 | self.target.run('rm -rf %s' % self.targetdir) | ||