Merge ~sbeattie/qa-regression-testing:moar-ci-tests into qa-regression-testing:master

Proposed by Steve Beattie
Status: Merged
Merged at revision: a0489c38532078c29c32c97f97c47af0b38ceaba
Proposed branch: ~sbeattie/qa-regression-testing:moar-ci-tests
Merge into: qa-regression-testing:master
Diff against target: 213 lines (+93/-6)
4 files modified
.launchpad.yaml (+14/-0)
lpcraft-runner (+8/-2)
scripts/README.md (+28/-0)
scripts/test-busybox.py (+43/-4)
Reviewer Review Type Date Requested Status
Alex Murray Approve
Review via email: mp+442935@code.launchpad.net

Commit message

tests: add busybox tests to lpci plus infra to skip tests in lpci

Steve Beattie (7):
   * [0012d86b] test-busybox.py: switch to python3
   * [4c70d4a0] test-busybox.py: tests requires root due to udhcpc
   * [fa8ea339] test-busybox.py: older busybox wget doesn't support https
   * [4550df63] test-busybox.py: fix bitwise op test across all releases
   * [175e1a2b] lpcraft-runner: export env var for skipping tests in lpci
   * [841581fe] scripts/README.md: add notes on lpci
   * [14a0bc5f] .launchpad.yaml: add busybox QRT script to CI tests

Description of the change

The overall point of this branch is to enable the busybox qrt scripts in lpci. Along the way, I corrected some issues, including some behavioral differencs in 14.04's busybox, to make sure the tests run across all supported versions and also in lpci; in particular some tests that would work in a local vm would fail to run in the lp test environment.

In particular, the script would attempt to exercise busybox's simple dhcp client (udhcpc) as well as use busybox's wget implementation to access https URLs and the ubuntu archive via ftp. To skip those, I set an environment variable LPCRAFT_QRT_RUNNER in the lpcraft-runner script and then skip tests if that environment variable is set, using python unittest's skipIf decorator (the busybox tests is also converted to python3).

Arguably, this variable could be set in the launchpad.yaml file, and maybe it should be. The idea behind setting it in the runner script was so that local testing with lpci would get the same behavior, but opinions appreciated here.

I also added a bit on lpci and skipping tests to the README for the scripts.

To post a comment you must log in.
Revision history for this message
Alex Murray (alexmurray) wrote :

Thanks Steve, this looks awesome - I would have hoped that setting the variable inside the .launchpad.yaml would then mean that lpci would also set it when running locally - however, this would also mean we would have to duplicate that into every job entry in the yaml as well - so setting it in lpcraft-runner means we only have to put it in one place.

So FWIW I think your current approach is great.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/.launchpad.yaml b/.launchpad.yaml
index fa27693..242a4d9 100644
--- a/.launchpad.yaml
+++ b/.launchpad.yaml
@@ -6,6 +6,7 @@ pipeline:
6 - sudo6 - sudo
7 - git7 - git
8 - ghostscript8 - ghostscript
9 - busybox
910
10jobs:11jobs:
11 imagemagick:12 imagemagick:
@@ -85,3 +86,16 @@ jobs:
85 - sudo86 - sudo
86 run: |87 run: |
87 ./lpcraft-runner ghostscript88 ./lpcraft-runner ghostscript
89
90 busybox:
91 matrix:
92 - series: jammy
93 architectures: amd64
94 - series: focal
95 architectures: amd64
96 - series: bionic
97 architectures: amd64
98 packages:
99 - sudo
100 run: |
101 ./lpcraft-runner busybox
diff --git a/lpcraft-runner b/lpcraft-runner
index 0a6f690..ca94a85 100755
--- a/lpcraft-runner
+++ b/lpcraft-runner
@@ -2,16 +2,22 @@
2set -euo pipefail2set -euo pipefail
33
4test=$14test=$1
5script="./scripts/test-${test}.py"
6tarball="${TMPDIR:-/tmp}/qrt-test-${test}.tar.gz"
7
8# export this so that QRT test scripts can skip tests that will work in
9# a local VM but not function in the lpci environment
10export LPCRAFT_QRT_RUNNER=true
511
6# setup an unprivileged user12# setup an unprivileged user
7getent passwd ubuntu >/dev/null || useradd -m -U ubuntu13getent passwd ubuntu >/dev/null || useradd -m -U ubuntu
8# allow sudo access14# allow sudo access
9grep -q "ubuntu ALL=(ALL) NOPASSWD: ALL" /etc/sudoers || echo "ubuntu ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers15grep -q "ubuntu ALL=(ALL) NOPASSWD: ALL" /etc/sudoers || echo "ubuntu ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers
10# one test for each require_nonroot, require_sudo and require_root16# one test for each require_nonroot, require_sudo and require_root
11script="./scripts/test-${test}.py"17
12tarball="${TMPDIR:-/tmp}/qrt-test-${test}.tar.gz"
13rm -f "$tarball"18rm -f "$tarball"
14./scripts/make-test-tarball "$script"19./scripts/make-test-tarball "$script"
20
15# figure out what user we need to run as21# figure out what user we need to run as
16user=ubuntu22user=ubuntu
17if grep -q '^\s*testlib.require_sudo()' "$script"; then23if grep -q '^\s*testlib.require_sudo()' "$script"; then
diff --git a/scripts/README.md b/scripts/README.md
index 143fae0..41b0a85 100644
--- a/scripts/README.md
+++ b/scripts/README.md
@@ -99,6 +99,34 @@ dependencies explicitly. Eg, `testlib_data.py` has in it:
9999
100so you don't need to specify `data` if you specify `testlib_data.py`.100so you don't need to specify `data` if you specify `testlib_data.py`.
101101
102
103Running tests under launchpad CI (aka lpci)
104-------------------------------------------
105
106Reference: <https://lpci.readthedocs.io/en/latest/>
107
108Enabling a given test script in lpci is fairly straightforward... in
109most cases. For the easy cases, editing the top level `.launchpad.yaml`
110will suffice; name a job and create a similar matrix as the existing
111ones. Note that the initial job order definition and the later
112definition should be in matching order.
113
114Some test cases will need to be skipped when run in the lpci
115environment; generally we should try to avid this but sometimes it's
116unavoidable. The lpcraft-runner script defines the environment variable
117`LPCRAFT_QRT_RUNNER` for this reason. Python unitest's `skipIf()`
118decorator can be used to do this:
119
120```python
121 @unittest.skipIf(
122 'LPCRAFT_QRT_RUNNER' in os.environ,
123 'External URLs not allowed in lpci environ'
124 )
125 def test_that_accesses_external_url(self):
126```
127
128
129
102Notes on unittest idioms130Notes on unittest idioms
103------------------------131------------------------
104132
diff --git a/scripts/test-busybox.py b/scripts/test-busybox.py
index 48054fd..227f6d2 100755
--- a/scripts/test-busybox.py
+++ b/scripts/test-busybox.py
@@ -1,4 +1,4 @@
1#!/usr/bin/python21#!/usr/bin/python3
2#2#
3# test-busybox.py quality assurance test script for busybox3# test-busybox.py quality assurance test script for busybox
4# Copyright (C) 2019-2021 Canonical Ltd.4# Copyright (C) 2019-2021 Canonical Ltd.
@@ -18,6 +18,7 @@
18#18#
19# packages required for test to run:19# packages required for test to run:
20# QRT-Packages: busybox-static busybox-initramfs udhcpc20# QRT-Packages: busybox-static busybox-initramfs udhcpc
21# QRT-Privilege: root
21# QRT-Depends: testlib_archive.py testlib_compressor.py data22# QRT-Depends: testlib_archive.py testlib_compressor.py data
2223
23'''24'''
@@ -254,6 +255,10 @@ class BusyboxUdhcpcTest(testlib.TestlibCase):
254 def tearDown(self):255 def tearDown(self):
255 '''Clean up after each test_* function'''256 '''Clean up after each test_* function'''
256257
258 @unittest.skipIf(
259 'LPCRAFT_QRT_RUNNER' in os.environ,
260 'unable to attach to interface in lpci environment'
261 )
257 def test_dhcpc(self):262 def test_dhcpc(self):
258 '''Test dhcpc renew'''263 '''Test dhcpc renew'''
259264
@@ -278,9 +283,16 @@ class BusyboxWgetTest(testlib.TestlibCase):
278283
279 def _test_url_wget(self, url="http://localhost/", content="", invert=False, expected=0, extra_opts=[]):284 def _test_url_wget(self, url="http://localhost/", content="", invert=False, expected=0, extra_opts=[]):
280 '''Test the given url with wget'''285 '''Test the given url with wget'''
286
287 if self.lsb_release['Release'] < 18.04 and url.startswith("https://"):
288 self._skipped('busybox wget does not support https before bionic')
289 expected = 1
290
281 report = self._get_page_wget(url, expected=expected, extra_opts=extra_opts)291 report = self._get_page_wget(url, expected=expected, extra_opts=extra_opts)
282292
283 if content != "":293 if self.lsb_release['Release'] < 18.04 and url.startswith("https://"):
294 self._word_find(report, "wget: not an http or ftp url:", invert)
295 elif content != "":
284 self._word_find(report, content, invert)296 self._word_find(report, content, invert)
285297
286 def _get_page_wget(self, url="http://localhost/", expected=0, extra_opts=[]):298 def _get_page_wget(self, url="http://localhost/", expected=0, extra_opts=[]):
@@ -304,21 +316,37 @@ class BusyboxWgetTest(testlib.TestlibCase):
304 self._test_url_wget("http://cdimage.ubuntu.com/",316 self._test_url_wget("http://cdimage.ubuntu.com/",
305 "ubuntu-server")317 "ubuntu-server")
306318
319 @unittest.skipIf(
320 'LPCRAFT_QRT_RUNNER' in os.environ,
321 'External https URLs not allowed in lpci environ'
322 )
307 def test_https(self):323 def test_https(self):
308 '''Test https'''324 '''Test https'''
309 self._test_url_wget("https://cdimage.ubuntu.com/",325 self._test_url_wget("https://cdimage.ubuntu.com/",
310 "ubuntu-server")326 "ubuntu-server")
311327
328 @unittest.skipIf(
329 'LPCRAFT_QRT_RUNNER' in os.environ,
330 'External https URLs not allowed in lpci environ'
331 )
312 def test_bad_https_selfsigned(self):332 def test_bad_https_selfsigned(self):
313 '''Test bad https (self-signed)'''333 '''Test bad https (self-signed)'''
314 self._test_url_wget("https://self-signed.badssl.com/",334 self._test_url_wget("https://self-signed.badssl.com/",
315 content="error getting response", expected=1)335 content="error getting response", expected=1)
316336
337 @unittest.skipIf(
338 'LPCRAFT_QRT_RUNNER' in os.environ,
339 'External https URLs not allowed in lpci environ'
340 )
317 def test_bad_https_wrong_host(self):341 def test_bad_https_wrong_host(self):
318 '''Test bad https (wrong host)'''342 '''Test bad https (wrong host)'''
319 self._test_url_wget("https://wrong.host.badssl.com/",343 self._test_url_wget("https://wrong.host.badssl.com/",
320 content="error getting response", expected=1)344 content="error getting response", expected=1)
321345
346 @unittest.skipIf(
347 'LPCRAFT_QRT_RUNNER' in os.environ,
348 'External ftp URLs not allowed in lpci environ'
349 )
322 def test_ftp(self):350 def test_ftp(self):
323 '''Test ftp (ftp.ubuntu.com)'''351 '''Test ftp (ftp.ubuntu.com)'''
324352
@@ -334,10 +362,18 @@ class BusyboxAwkTest(testlib.TestlibCase):
334 def test_bitwise_op(self):362 def test_bitwise_op(self):
335 expected = 0363 expected = 0
336 rc, report = testlib.cmd_pipe(['echo', ''],364 rc, report = testlib.cmd_pipe(['echo', ''],
337 ['busybox', 'awk', '{ print or(4294967295,1) }'])365 ['busybox', 'awk', r'{ printf "%8x\n", or(4294967295,1) }'])
366 result = 'Got exit code %d, expected %d\n' % (rc, expected)
367 self.assertEqual(expected, rc, result + report)
368 self.assertTrue("80000000" in report, "Couldn't find search string.\n" + report)
369
370 def test_bitwise_op_2(self):
371 expected = 0
372 rc, report = testlib.cmd_pipe(['echo', ''],
373 ['busybox', 'awk', r'{ printf "%8x\n", or(4294967294,1) }'])
338 result = 'Got exit code %d, expected %d\n' % (rc, expected)374 result = 'Got exit code %d, expected %d\n' % (rc, expected)
339 self.assertEqual(expected, rc, result + report)375 self.assertEqual(expected, rc, result + report)
340 self.assertTrue("4294967295" in report, "Couldn't find search string.\n")376 self.assertTrue("80000000" in report, "Couldn't find search string.\n" + report)
341377
342 def test_dash_f(self):378 def test_dash_f(self):
343 expected = 0379 expected = 0
@@ -354,6 +390,9 @@ class BusyboxAwkTest(testlib.TestlibCase):
354 self.assertTrue("2" in report, "Couldn't find search string.\n")390 self.assertTrue("2" in report, "Couldn't find search string.\n")
355391
356if __name__ == '__main__':392if __name__ == '__main__':
393 # needed for udhcpc tests
394 testlib.require_root()
395
357 # more configurable396 # more configurable
358 suite = unittest.TestSuite()397 suite = unittest.TestSuite()
359 suite.addTest(unittest.TestLoader().loadTestsFromTestCase(BusyboxTarTest))398 suite.addTest(unittest.TestLoader().loadTestsFromTestCase(BusyboxTarTest))

Subscribers

People subscribed via source and target branches