-
Notifications
You must be signed in to change notification settings - Fork 750
[JENKINS-68518] Email-ext treats transient SMTP errors as fatal errors #1473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
akash-manna-sky
wants to merge
12
commits into
jenkinsci:main
Choose a base branch
from
akash-manna-sky:JENKINS-68518
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+226
−7
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
40ac28d
Email-ext treats transient SMTP errors as fatal errors
akash-manna-sky c77848c
apply mvn spotless:apply command
akash-manna-sky 79292b4
removed FQNs
akash-manna-sky dcc9fe3
fix spotbugs warnings
akash-manna-sky fbcc0d4
Merge branch 'main' into JENKINS-68518
akash-manna-sky 49173f1
Improve error handling for transient SMTP errors in email sending
akash-manna-sky 9e694ac
Merge branch 'main' into JENKINS-68518
akash-manna-sky eb6c654
add author
akash-manna-sky 344792d
Merge branch 'main' into JENKINS-68518
akash-manna-sky 52d24ec
Merge branch 'main' into JENKINS-68518
akash-manna-sky 6503b83
Merge branch 'main' into JENKINS-68518
akash-manna-sky bc105e8
Merge branch 'main' into JENKINS-68518
akash-manna-sky File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
126 changes: 126 additions & 0 deletions
126
src/test/java/hudson/plugins/emailext/SmtpRetryTest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,126 @@ | ||
| package hudson.plugins.emailext; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.*; | ||
|
|
||
| import jakarta.mail.MessagingException; | ||
| import jakarta.mail.SendFailedException; | ||
| import java.io.IOException; | ||
| import java.lang.reflect.Method; | ||
| import java.net.SocketException; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.jvnet.hudson.test.Issue; | ||
|
|
||
| /** | ||
| * Unit tests for SMTP retry logic, particularly for transient SMTP errors (4xx codes). | ||
| * Since SMTP-specific exception classes are not available at compile time, these tests | ||
| * focus on the message parsing and exception chain traversal logic. | ||
| * | ||
| * @author Akash Manna | ||
| */ | ||
| class SmtpRetryTest { | ||
|
|
||
| /** | ||
| * Calls the package-private isTransientSmtpError() method using reflection. | ||
| */ | ||
| private boolean callIsTransientSmtpError(Exception e) throws Exception { | ||
| ExtendedEmailPublisher publisher = new ExtendedEmailPublisher(); | ||
| Method method = ExtendedEmailPublisher.class.getDeclaredMethod("isTransientSmtpError", Exception.class); | ||
| method.setAccessible(true); | ||
| return (Boolean) method.invoke(publisher, e); | ||
| } | ||
|
|
||
| @Test | ||
| @Issue("JENKINS-68518") | ||
| void testIsTransientSmtpErrorWithMessageParsing() throws Exception { | ||
| MessagingException ex421 = new MessagingException("421 Service not available, try again later"); | ||
| MessagingException ex450 = new MessagingException("450 Requested mail action not taken: mailbox unavailable"); | ||
| MessagingException ex451 = new MessagingException("451 Requested action aborted: error in processing"); | ||
| MessagingException ex452 = new MessagingException("452 Insufficient system storage"); | ||
|
|
||
| assertTrue( | ||
| callIsTransientSmtpError(ex421), | ||
| "MessagingException with '421' in message should be identified as transient"); | ||
| assertTrue( | ||
| callIsTransientSmtpError(ex450), | ||
| "MessagingException with '450' in message should be identified as transient"); | ||
| assertTrue( | ||
| callIsTransientSmtpError(ex451), | ||
| "MessagingException with '451' in message should be identified as transient"); | ||
| assertTrue( | ||
| callIsTransientSmtpError(ex452), | ||
| "MessagingException with '452' in message should be identified as transient"); | ||
|
|
||
| MessagingException ex500 = new MessagingException("500 Syntax error"); | ||
| MessagingException ex550 = new MessagingException("550 Requested action not taken"); | ||
|
|
||
| assertFalse( | ||
| callIsTransientSmtpError(ex500), | ||
| "MessagingException with '500' in message should NOT be identified as transient"); | ||
| assertFalse( | ||
| callIsTransientSmtpError(ex550), | ||
| "MessagingException with '550' in message should NOT be identified as transient"); | ||
| } | ||
|
|
||
| @Test | ||
| @Issue("JENKINS-68518") | ||
| void testIsTransientSmtpErrorWithNonSmtpExceptions() throws Exception { | ||
| assertFalse( | ||
| callIsTransientSmtpError(new IOException("Connection error")), | ||
| "IOException should NOT be identified as transient SMTP error"); | ||
| assertFalse( | ||
| callIsTransientSmtpError(new MessagingException("Generic messaging error")), | ||
| "MessagingException without SMTP code should NOT be identified as transient"); | ||
| assertFalse( | ||
| callIsTransientSmtpError(new SocketException("Connection reset")), | ||
| "SocketException should NOT be identified as transient SMTP error"); | ||
| } | ||
|
|
||
| @Test | ||
| @Issue("JENKINS-68518") | ||
| void testIsTransientSmtpErrorInCauseChain() throws Exception { | ||
| MessagingException smtpError = new MessagingException("421 Service not available"); | ||
| SendFailedException wrapped = new SendFailedException("Send failed", smtpError); | ||
| MessagingException doubleWrapped = new MessagingException("Multiple errors", wrapped); | ||
|
|
||
| assertTrue( | ||
| callIsTransientSmtpError(wrapped), | ||
| "SMTP 421 error wrapped in SendFailedException should be identified as transient"); | ||
| assertTrue( | ||
| callIsTransientSmtpError(doubleWrapped), | ||
| "SMTP 421 error deep in exception chain should be identified as transient"); | ||
| } | ||
|
|
||
| @Test | ||
| @Issue("JENKINS-68518") | ||
| void testIsTransientSmtpErrorBoundaryCases() throws Exception { | ||
| MessagingException ex399 = new MessagingException("399 Below 4xx range"); | ||
| MessagingException ex400 = new MessagingException("400 First 4xx code"); | ||
| MessagingException ex499 = new MessagingException("499 Last 4xx code"); | ||
| MessagingException ex500 = new MessagingException("500 First 5xx code"); | ||
|
|
||
| assertFalse(callIsTransientSmtpError(ex399), "SMTP 399 should NOT be identified as transient"); | ||
| assertTrue(callIsTransientSmtpError(ex400), "SMTP 400 should be identified as transient"); | ||
| assertTrue(callIsTransientSmtpError(ex499), "SMTP 499 should be identified as transient"); | ||
| assertFalse(callIsTransientSmtpError(ex500), "SMTP 500 should NOT be identified as transient"); | ||
| } | ||
|
|
||
| @Test | ||
| @Issue("JENKINS-68518") | ||
| void testIsTransientSmtpErrorWithNextException() throws Exception { | ||
| MessagingException inner = new MessagingException("450 Mailbox unavailable"); | ||
| MessagingException outer = new MessagingException("Failed to send"); | ||
| outer.setNextException(inner); | ||
|
|
||
| assertTrue(callIsTransientSmtpError(outer), "Should detect transient error in nextException chain"); | ||
| } | ||
|
|
||
| @Test | ||
| @Issue("JENKINS-68518") | ||
| void testIsTransientSmtpErrorWithNullCheck() throws Exception { | ||
| ExtendedEmailPublisher publisher = new ExtendedEmailPublisher(); | ||
| Method method = ExtendedEmailPublisher.class.getDeclaredMethod("isTransientSmtpError", Exception.class); | ||
| method.setAccessible(true); | ||
|
|
||
| assertFalse((Boolean) method.invoke(publisher, new Object[] {null}), "Should return false for null exception"); | ||
| } | ||
| } |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.