Failing builds on test failures in Jenkins - Time & Space Complexity
We want to understand how the time to run a Jenkins build changes when tests are involved.
Specifically, how does the build time grow as the number of tests increases?
Analyze the time complexity of the following Jenkins pipeline snippet.
pipeline {
agent any
stages {
stage('Test') {
steps {
script {
def testResults = runTests() // runs all tests
if (testResults.hasFailures()) {
error('Tests failed, stopping build')
}
}
}
}
}
}
This code runs a set of tests and fails the build if any test fails.
Look for repeated actions that take time.
- Primary operation: Running each test in the test suite.
- How many times: Once per test, repeated for all tests.
As the number of tests grows, the time to run them grows too.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | Runs 10 tests |
| 100 | Runs 100 tests |
| 1000 | Runs 1000 tests |
Pattern observation: The time grows roughly in direct proportion to the number of tests.
Time Complexity: O(n)
This means the build time increases linearly as the number of tests increases.
[X] Wrong: "Failing early on the first test failure makes the build time constant regardless of test count."
[OK] Correct: Even if the build stops early, in the worst case all tests run before failure, so time still grows with test count.
Understanding how test execution time affects build time helps you design efficient pipelines and explain build performance clearly.
What if we parallelize running tests? How would the time complexity change?
Practice
Solution
Step 1: Understand Jenkins build behavior on command failure
Jenkins treats any shell or batch command that returns a non-zero exit code as a failure.Step 2: Relate test command failure to build status
If tests fail and return a failure code, Jenkins marks the entire build as failed automatically.Final Answer:
The build fails automatically to indicate test failure. -> Option DQuick Check:
Test failure exit code causes build failure [OK]
- Thinking Jenkins ignores test failures by default
- Assuming manual intervention is needed on test failure
- Believing Jenkins retries failed test commands automatically
Solution
Step 1: Analyze each shell command's effect on build status
sh 'run_tests.sh' // fails build if script exits non-zero runs the test script normally; if it exits non-zero, Jenkins fails the build.Step 2: Identify commands that ignore failure
sh 'run_tests.sh || true' // ignores test failures uses '|| true' which forces success, ignoring failures; C runs in background, not failing build; D always succeeds due to echo.Final Answer:
sh 'run_tests.sh' // fails build if script exits non-zero -> Option CQuick Check:
Normal shell command fails build on error [OK]
- Adding '|| true' to shell commands
- Running tests in background without waiting
- Appending commands that always succeed after tests
pytest finds failing tests?
pipeline {
agent any
stages {
stage('Test') {
steps {
sh 'pytest'
}
}
}
}Solution
Step 1: Understand Jenkins behavior on shell step failure
Theshstep fails the build if the command exits with a non-zero code.Step 2: Recognize
pytestexit codespytestreturns non-zero exit code if any test fails, causing Jenkins to fail the build.Final Answer:
Build will fail ifpytestreturns a failure exit code. -> Option BQuick Check:
Failing tests cause non-zero exit, fail build [OK]
- Assuming build passes despite test failures
- Confusing unstable with failed build
- Thinking Jenkins skips failing test stages
Solution
Step 1: Identify why build ignores test failures
Using '|| true' after test commands forces success regardless of test results.Step 2: Exclude other causes
Missing 'agent any' causes pipeline failure, server offline stops build, post section can't override success if test fails.Final Answer:
The test command is run with '|| true' which ignores failures. -> Option AQuick Check:
'|| true' masks test failures causing success [OK]
- Blaming missing agent for test failure ignoring
- Assuming Jenkins server offline lets build succeed
- Misconfiguring post section to override failure
Solution
Step 1: Use catchError to catch test failures and mark build unstable
Wrapping test commands withcatchError(buildResult: 'UNSTABLE')prevents build failure but marks unstable.Step 2: Use post section to publish test results
Publishing test results withjunitreports test failures and sets build status accordingly.Final Answer:
Usepost { always { junit '**/test-results.xml' } }andcatchError(buildResult: 'UNSTABLE')around test step. -> Option AQuick Check:
catchError + junit marks unstable, not failed [OK]
- Ignoring test failures with '|| true' instead of marking unstable
- Misusing post failure block without changing status
- Skipping test stages after unstable status
Ready to prove it?
Pass the test and this pattern moves unknown
