11package io .jenkins .plugins .casc ;
22
3+ import static java .nio .file .Files .createTempFile ;
4+ import static java .nio .file .Files .write ;
5+ import static java .util .Arrays .asList ;
36import static org .junit .Assert .assertEquals ;
47import static org .junit .Assert .assertFalse ;
58import static org .junit .Assert .assertTrue ;
811import io .jenkins .plugins .casc .misc .EnvVarsRule ;
912import io .jenkins .plugins .casc .misc .Envs ;
1013import io .jenkins .plugins .casc .misc .JenkinsConfiguredWithCodeRule ;
14+ import jakarta .servlet .ServletException ;
1115import jakarta .servlet .http .HttpServletResponse ;
1216import java .io .IOException ;
17+ import java .net .URL ;
18+ import java .nio .file .Files ;
19+ import java .nio .file .Path ;
1320import java .util .Collections ;
1421import java .util .Date ;
1522import java .util .HashMap ;
1623import java .util .List ;
1724import java .util .Map ;
1825import java .util .logging .Level ;
1926import java .util .logging .LogRecord ;
27+ import org .htmlunit .HttpMethod ;
28+ import org .htmlunit .WebRequest ;
29+ import org .htmlunit .WebResponse ;
2030import org .junit .Before ;
2131import org .junit .Rule ;
2232import org .junit .Test ;
2333import org .junit .contrib .java .lang .system .RestoreSystemProperties ;
2434import org .junit .rules .RuleChain ;
35+ import org .jvnet .hudson .test .JenkinsRule ;
2536import org .jvnet .hudson .test .LoggerRule ;
2637import org .kohsuke .stapler .RequestImpl ;
2738import org .kohsuke .stapler .ResponseImpl ;
@@ -91,7 +102,7 @@ public void setUp() {
91102 }
92103
93104 @ Test
94- public void reloadIsDisabledByDefault () throws IOException {
105+ public void reloadIsDisabledByDefault () throws IOException , ServletException {
95106 System .clearProperty ("casc.reload.token" );
96107
97108 RequestImpl request = newRequest (null );
@@ -108,7 +119,7 @@ public void reloadIsDisabledByDefault() throws IOException {
108119 }
109120
110121 @ Test
111- public void reloadReturnsUnauthorizedIfTokenDoesNotMatch () throws IOException {
122+ public void reloadReturnsUnauthorizedIfTokenDoesNotMatch () throws IOException , ServletException {
112123 System .setProperty ("casc.reload.token" , "someSecretValue" );
113124
114125 RequestImpl request = newRequest (null );
@@ -118,7 +129,7 @@ public void reloadReturnsUnauthorizedIfTokenDoesNotMatch() throws IOException {
118129 }
119130
120131 @ Test
121- public void reloadReturnsOkWhenCalledWithValidToken () throws IOException {
132+ public void reloadReturnsOkWhenCalledWithValidToken () throws IOException , ServletException {
122133 System .setProperty ("casc.reload.token" , "someSecretValue" );
123134
124135 tokenReloadAction .doIndex (newRequest ("someSecretValue" ), new ResponseImpl (null , response ));
@@ -128,15 +139,15 @@ public void reloadReturnsOkWhenCalledWithValidToken() throws IOException {
128139
129140 @ Test
130141 @ Envs ({@ Env (name = "CASC_RELOAD_TOKEN" , value = "someSecretValue" )})
131- public void reloadReturnsOkWhenCalledWithValidTokenSetByEnvVar () throws IOException {
142+ public void reloadReturnsOkWhenCalledWithValidTokenSetByEnvVar () throws IOException , ServletException {
132143 tokenReloadAction .doIndex (newRequest ("someSecretValue" ), new ResponseImpl (null , response ));
133144
134145 assertConfigReloaded ();
135146 }
136147
137148 @ Test
138149 @ Envs ({@ Env (name = "CASC_RELOAD_TOKEN" , value = "someSecretValue" )})
139- public void reloadShouldNotUseTokenFromPropertyIfEnvVarIsSet () throws IOException {
150+ public void reloadShouldNotUseTokenFromPropertyIfEnvVarIsSet () throws IOException , ServletException {
140151 System .setProperty ("casc.reload.token" , "otherSecretValue" );
141152
142153 tokenReloadAction .doIndex (newRequest ("otherSecretValue" ), new ResponseImpl (null , response ));
@@ -146,7 +157,7 @@ public void reloadShouldNotUseTokenFromPropertyIfEnvVarIsSet() throws IOExceptio
146157
147158 @ Test
148159 @ Envs ({@ Env (name = "CASC_RELOAD_TOKEN" , value = "" )})
149- public void reloadShouldUsePropertyAsTokenIfEnvVarIsEmpty () throws IOException {
160+ public void reloadShouldUsePropertyAsTokenIfEnvVarIsEmpty () throws IOException , ServletException {
150161 System .setProperty ("casc.reload.token" , "someSecretValue" );
151162
152163 tokenReloadAction .doIndex (newRequest ("someSecretValue" ), new ResponseImpl (null , response ));
@@ -158,4 +169,58 @@ public void reloadShouldUsePropertyAsTokenIfEnvVarIsEmpty() throws IOException {
158169 public void displayName () {
159170 assertEquals ("Reload Configuration as Code" , tokenReloadAction .getDisplayName ());
160171 }
172+
173+ @ Test
174+ public void reloadReturnsInternalServerErrorAndJsonOnFailure () throws Exception {
175+ String oldToken = System .getProperty ("casc.reload.token" );
176+ String oldConfig = System .getProperty ("casc.jenkins.config" );
177+
178+ System .setProperty ("casc.reload.token" , "someSecretValue" );
179+
180+ Path tempFile = createTempFile ("invalid-casc-config" , ".yaml" );
181+ write (tempFile , asList ("unclassified:" , " this_fake_property_forces_a_configurator_exception: true" ));
182+ System .setProperty ("casc.jenkins.config" , tempFile .toAbsolutePath ().toString ());
183+
184+ try {
185+ JenkinsRule .WebClient wc = j .createWebClient ();
186+ wc .getOptions ().setThrowExceptionOnFailingStatusCode (false );
187+
188+ URL url = new URL (j .getURL (), "reload-configuration-as-code/?casc-reload-token=someSecretValue" );
189+ WebRequest request = new WebRequest (url , HttpMethod .POST );
190+ WebResponse response = wc .getPage (request ).getWebResponse ();
191+
192+ assertEquals (HttpServletResponse .SC_OK , response .getStatusCode ());
193+ assertTrue ("Content-Type should be JSON" , response .getContentType ().contains ("application/json" ));
194+
195+ String body = response .getContentAsString ();
196+ assertTrue (
197+ "Response body should contain the failure contextual message" ,
198+ body .contains ("Failed to reload configuration" ));
199+ assertTrue (
200+ "Response body should expose the specific invalid YAML property" ,
201+ body .contains ("this_fake_property_forces_a_configurator_exception" ));
202+
203+ List <LogRecord > messages = loggerRule .getRecords ();
204+ boolean hasSevereLog = messages .stream ()
205+ .anyMatch (record -> record .getLevel () == Level .SEVERE
206+ && record .getMessage ()
207+ .contains ("Failed to reload Jenkins Configuration as Code via token" ));
208+
209+ assertTrue ("Expected a SEVERE log message regarding reload failure" , hasSevereLog );
210+
211+ } finally {
212+ Files .deleteIfExists (tempFile );
213+ if (oldToken != null ) {
214+ System .setProperty ("casc.reload.token" , oldToken );
215+ } else {
216+ System .clearProperty ("casc.reload.token" );
217+ }
218+
219+ if (oldConfig != null ) {
220+ System .setProperty ("casc.jenkins.config" , oldConfig );
221+ } else {
222+ System .clearProperty ("casc.jenkins.config" );
223+ }
224+ }
225+ }
161226}
0 commit comments