Vipul Gupta
Vipul is a software engineer at balena and a documentarian running his docs initiative called Mixster. He advocates strongly for open-source, cheesecakes and party parrots.
@vipulgupta2048
A Journey from Pull Request to Release
@vipulgupta2048
We-pull
@vipulgupta2048
@vipulgupta2048
@vipulgupta2048
BalenaOS runs containers on CO2 sensors, farms, smart dustbins, trucks...
First to run Docker containers in space.
... underwater drones, museums, photo booths, parkings, forklifts, and the rare wireless speakers
@vipulgupta2048
@vipulgupta2048
With smart cities & even your toaster getting firmware updates. The stakes have never been higher
@vipulgupta2048
@vipulgupta2048
@vipulgupta2048
Autokit
(controller)
Raspberry Pi 4
(Device Under Test)
With Autokit, we enabled a Hardware in loop testing pipeline for balenaOS
balenaOS Hardware in the loop testing pipeline
A contributor opens a pull request on the balenaOS meta-balena repository.
This triggers a Jenkins job that builds balenaOS releases for every device we support.
Artifacts built by upstream jobs are copied to downstream testing jobs managed by our testing framework, Leviathan.
Leviathan is the software layer that interacts with balenaOS images, does configuration and talks with the hardware, autokit.
Leviathan abstracts away complexities by enabling developers to write one test suite to target all devices. No matter their power requirements, boot process, or flash procedure. Leviathan takes care of everything.
// Leviathan test to flash a device connected to the autokit (Sample)
await this.worker.off(); // Ensure test device is off before flashing
await this.worker.flash(this.os.image.path); // Flash the device with balenaOS image
await this.worker.on(); // Turn on the device
test.true(
true,
`${this.os.image.path} should be flashed properly`,
);
Autokit automatically flashes the device under test with the OS, provides power, network & executes our commands on the test.
[
{
"suite": "Managed BalenaOS release suite",
"stats": {
"tests": 12,
"ran": 10,
"skipped": 2,
"passed": 10,
"failed": 0
},
"tests": {
"Image preload test": "passed",
"Move device to hostapd test App": "skipped",
"Move device back to original app": "skipped",
"Provisioning without deltas": "passed",
"Override lock test": "passed",
"Update supervisor randomized timer": "passed",
"Set device environment variables": "passed",
"Set service environment variables": "passed",
"SSH authentication in production mode": "passed",
"SSH authentication in development mode": "passed",
"os-config service on boot": "passed",
"os-config service randomized timer": "passed"
},
"dateTime": "Thu Apr 27 2023 11:43:52 GMT+0000 (Coordinated Universal Time)"
},
{
"suite": "Hostapp update suite",
"stats": {
"tests": 5,
"ran": 5,
"skipped": 0,
"passed": 5,
"failed": 0
},
"tests": {
"Broken balena-engine": "passed",
"Broken VPN": "passed",
"Rollback altboot (broken init) test": "passed",
"HUP from previous release": "passed",
"HUP from this release": "passed"
},
"dateTime": "Thu Apr 27 2023 11:58:25 GMT+0000 (Coordinated Universal Time)"
},
{
"suite": "Unmanaged BalenaOS release suite",
"stats": {
"tests": 45,
"ran": 36,
"skipped": 9,
"passed": 36,
"failed": 0
},
"tests": {
"check secure boot": "passed",
"BeagleBone Black u-boot overlay test: deactivate HDMI": "skipped",
"243390-rpi3 - CUS/EUS chipsets test": "skipped",
"fingerprint file test": "passed",
"ext4 filesystems are checked on boot": "passed",
"OS-release file check": "passed",
"Installer used migrator module": "passed",
"issue file check": "passed",
"issue.net file check": "passed",
"Chronyd service": "passed",
"Sync test": "passed",
"Source test": "passed",
"Offline sources test": "passed",
"System time skew test": "passed",
"kernel-overlap test": "passed",
"Bluetooth scanning test": "skipped",
"Container healthcheck test": "passed",
"Container exposed variables test": "passed",
"Identification test": "skipped",
"Cellular tests": "passed",
"hostname configuration test": "passed",
"ntpServer test": "passed",
"dnsServers test": "passed",
"os.network.connectivity test": "passed",
"os.network.wifi.randomMacAddressScan test": "passed",
"udevRules test": "passed",
"persistentLogging configuration test": "passed",
"Reboot test": "skipped",
"Wired test": "skipped",
"Wireless test": "skipped",
"Socks5 test": "passed",
"Http-connect test": "passed",
"Engine socket is exposed in development images": "passed",
"Engine socket is not exposed in production images": "passed",
"Engine watchdog recovery": "passed",
"Engine healthcheck performance": "passed",
"Under-voltage test": "passed",
"Ramdisks, zram and loop devices are not scanned for rootfs": "passed",
"by-state links are created": "passed",
"DToverlay & DTparam tests": "skipped",
"state partition reset": "passed",
"data partition reset": "passed",
"RevPi Core 3 DIO module test": "skipped",
"zram is enabled and configured as swap": "passed",
"Internet sharing iptables rules test": "passed"
},
"dateTime": "Thu Apr 27 2023 11:24:52 GMT+0000 (Coordinated Universal Time)"
}
]
[
{
"suite": "Managed BalenaOS release suite",
"stats": {
"tests": 12,
"ran": 10,
"skipped": 2,
"passed": 10,
"failed": 0
},
"tests": {
"Image preload test": "passed",
"Move device to hostapd test App": "skipped",
"Move device back to original app": "skipped",
"Provisioning without deltas": "passed",
"Override lock test": "passed",
"Update supervisor randomized timer": "passed",
"Set device environment variables": "passed",
"Set service environment variables": "passed",
"SSH authentication in production mode": "passed",
"SSH authentication in development mode": "passed",
"os-config service on boot": "passed",
"os-config service randomized timer": "passed"
},
"dateTime": "Thu Apr 27 2023 11:43:52 GMT+0000 (Coordinated Universal Time)"
},
{
"suite": "Hostapp update suite",
"stats": {
"tests": 5,
"ran": 5,
"skipped": 0,
"passed": 5,
"failed": 0
},
"tests": {
"Broken balena-engine": "passed",
"Broken VPN": "passed",
"Rollback altboot (broken init) test": "passed",
"HUP from previous release": "passed",
"HUP from this release": "passed"
},
"dateTime": "Thu Apr 27 2023 11:58:25 GMT+0000 (Coordinated Universal Time)"
},
{
"suite": "Unmanaged BalenaOS release suite",
"stats": {
"tests": 45,
"ran": 36,
"skipped": 9,
"passed": 36,
"failed": 0
},
"tests": {
"check secure boot": "passed",
"BeagleBone Black u-boot overlay test: deactivate HDMI": "skipped",
"243390-rpi3 - CUS/EUS chipsets test": "skipped",
"fingerprint file test": "passed",
"ext4 filesystems are checked on boot": "passed",
"OS-release file check": "passed",
"Installer used migrator module": "passed",
"issue file check": "passed",
"issue.net file check": "passed",
"Chronyd service": "passed",
"Sync test": "passed",
"Source test": "passed",
"Offline sources test": "passed",
"System time skew test": "passed",
"kernel-overlap test": "passed",
"Bluetooth scanning test": "skipped",
"Container healthcheck test": "passed",
"Container exposed variables test": "passed",
"Identification test": "skipped",
"Cellular tests": "passed",
"hostname configuration test": "passed",
"ntpServer test": "passed",
"dnsServers test": "passed",
"os.network.connectivity test": "passed",
"os.network.wifi.randomMacAddressScan test": "passed",
"udevRules test": "passed",
"persistentLogging configuration test": "passed",
"Reboot test": "skipped",
"Wired test": "skipped",
"Wireless test": "skipped",
"Socks5 test": "passed",
"Http-connect test": "passed",
"Engine socket is exposed in development images": "passed",
"Engine socket is not exposed in production images": "passed",
"Engine watchdog recovery": "passed",
"Engine healthcheck performance": "passed",
"Under-voltage test": "passed",
"Ramdisks, zram and loop devices are not scanned for rootfs": "passed",
"by-state links are created": "passed",
"DToverlay & DTparam tests": "skipped",
"state partition reset": "passed",
"data partition reset": "passed",
"RevPi Core 3 DIO module test": "skipped",
"zram is enabled and configured as swap": "passed",
"Internet sharing iptables rules test": "passed"
},
"dateTime": "Thu Apr 27 2023 11:24:52 GMT+0000 (Coordinated Universal Time)"
}
]
Breaking things intentionally to see if the OS can recover & update
With each downstream test job completed, Jenkins updates statuses of these jobs back on GitHub for the PR to be reviewed.
With each downstream test job completed, Jenkins updates statuses of these jobs back on GitHub for the PR to be reviewed.
Device repositories use this new meta-balena layer now available to deploy device-specific releases. These are built again, tested, and then merged to be deployed automatically. All using Jenkins.
This is hardware in loop testing with Jenkins
With Hardware in Loop Testing & Jenkins for CI/CD, we have managed to:
Most importantly, we even added QEMU support for testing virtual devices. Thanks to the Chip Shortage 2022
Autokit
(controller)
Devices that need to be controlled, automated and maintained using scripts
Autokit
(controller)
Feedback on changes
Testing software directly on hardware
in a CI/CD pipeline
?
Autokit
(controller)
?
?
?
?
?
?
?
?
?
?
?
Quality Assurance, stress testing, random testing, environmental testing
Questions? Collaborate? Work with us? Reach out!
Vipul Gupta
Reviews cheesecakes, solves GitHub issues & runs memeservice.
Feedback please + Link to the slides
By Vipul Gupta
This presentation is about using Jenkins to test hundreds of OS images, specifically focusing on balenaOS and the challenges that come with testing embedded operating systems. It was used for a talk on balenaOS's testing pipeline using Jenkins that took place at cdCon + GitOpsCon 2023 in Vancouver, Canada.
Vipul is a software engineer at balena and a documentarian running his docs initiative called Mixster. He advocates strongly for open-source, cheesecakes and party parrots.