11package com .cloudbees .jenkins ;
22
33import com .google .common .base .Charsets ;
4- import com .google .common .net .HttpHeaders ;
5- import io .restassured .builder .RequestSpecBuilder ;
6- import io .restassured .http .Header ;
7- import io .restassured .specification .RequestSpecification ;
84import jakarta .inject .Inject ;
95import org .apache .commons .io .IOUtils ;
106import org .jenkinsci .plugins .github .config .GitHubPluginConfig ;
1814
1915import java .io .File ;
2016import java .io .IOException ;
17+ import java .net .URI ;
18+ import java .net .http .HttpClient ;
19+ import java .net .http .HttpRequest ;
20+ import java .net .http .HttpResponse ;
2121
22- import static io .restassured .RestAssured .given ;
23- import static io .restassured .config .EncoderConfig .encoderConfig ;
24- import static io .restassured .config .RestAssuredConfig .newConfig ;
2522import static jakarta .servlet .http .HttpServletResponse .SC_BAD_REQUEST ;
2623import static jakarta .servlet .http .HttpServletResponse .SC_METHOD_NOT_ALLOWED ;
2724import static jakarta .servlet .http .HttpServletResponse .SC_OK ;
2825import static java .lang .String .format ;
2926import static org .apache .commons .lang3 .ClassUtils .PACKAGE_SEPARATOR ;
27+ import static org .hamcrest .MatcherAssert .assertThat ;
3028import static org .hamcrest .Matchers .containsString ;
29+ import static org .hamcrest .Matchers .is ;
3130import static org .hamcrest .Matchers .notNullValue ;
3231import static org .jenkinsci .plugins .github .test .HookSecretHelper .removeSecretIn ;
3332import static org .jenkinsci .plugins .github .test .HookSecretHelper .storeSecretIn ;
34- import static org .jenkinsci .plugins .github .webhook .RequirePostWithGHHookPayload .Processor .*;
33+ import static org .jenkinsci .plugins .github .webhook .RequirePostWithGHHookPayload .Processor .SHA256_PREFIX ;
34+ import static org .jenkinsci .plugins .github .webhook .RequirePostWithGHHookPayload .Processor .SIGNATURE_HEADER ;
35+ import static org .jenkinsci .plugins .github .webhook .RequirePostWithGHHookPayload .Processor .SIGNATURE_HEADER_SHA256 ;
3536
3637/**
3738 * @author lanwen (Merkushev Kirill)
3839 */
3940@ WithJenkins
4041public class GitHubWebHookFullTest {
4142
42- // GitHub doesn't send the charset per docs, so re-use the exact content-type from the handler
4343 public static final String APPLICATION_JSON = GHEventPayload .PayloadHandler .APPLICATION_JSON ;
4444 public static final String FORM = GHEventPayload .PayloadHandler .FORM_URLENCODED ;
4545
46- public static final Header JSON_CONTENT_TYPE = new Header (HttpHeaders .CONTENT_TYPE , APPLICATION_JSON );
47- public static final Header FORM_CONTENT_TYPE = new Header (HttpHeaders .CONTENT_TYPE , FORM );
48- public static final String NOT_NULL_VALUE = "nonnull" ;
49-
50- private RequestSpecification spec ;
51-
5246 @ Inject
5347 private GitHubPluginConfig config ;
5448
5549 private JenkinsRule jenkins ;
50+ private HttpClient httpClient ;
5651
5752 @ BeforeEach
5853 void before (JenkinsRule rule ) throws Throwable {
5954 jenkins = rule ;
6055 jenkins .getInstance ().getInjector ().injectMembers (this );
61-
62- spec = new RequestSpecBuilder ()
63- .setConfig (newConfig ()
64- .encoderConfig (encoderConfig ()
65- .defaultContentCharset (Charsets .UTF_8 .name ())
66- // GitHub doesn't add charsets, so don't test with them
67- .appendDefaultContentCharsetToContentTypeIfUndefined (false )))
68- .build ();
56+ httpClient = HttpClient .newHttpClient ();
6957 }
7058
7159 @ Test
7260 void shouldParseJsonWebHookFromGH () throws Exception {
7361 removeSecretIn (config );
74- given ().spec (spec )
75- .header (eventHeader (GHEvent .PUSH ))
76- .header (JSON_CONTENT_TYPE )
77- .body (classpath ("payloads/push.json" ))
78- .log ().all ()
79- .expect ().log ().all ().statusCode (SC_OK ).request ().post (getPath ());
62+ HttpResponse <String > response = httpClient .send (
63+ HttpRequest .newBuilder (URI .create (getPath ()))
64+ .POST (HttpRequest .BodyPublishers .ofString (classpath ("payloads/push.json" )))
65+ .header ("Content-Type" , APPLICATION_JSON )
66+ .header (GHEventHeader .PayloadHandler .EVENT_HEADER , GHEvent .PUSH .name ().toLowerCase ())
67+ .build (),
68+ HttpResponse .BodyHandlers .ofString ());
69+ assertThat ("status" , response .statusCode (), is (SC_OK ));
8070 }
8171
82-
8372 @ Test
8473 void shouldParseJsonWebHookFromGHWithSignHeader () throws Exception {
8574 String hash = "355e155fc3d10c4e5f2c6086a01281d2e947d932" ;
8675 String hash256 = "85e61999573c7023720a12375e1e55d18a0870e1ef880736f6ffc9273d0519e3" ;
8776 String secret = "123" ;
8877
8978 storeSecretIn (config , secret );
90- given ().spec (spec )
91- .header (eventHeader (GHEvent .PUSH ))
92- .header (JSON_CONTENT_TYPE )
93- .header (SIGNATURE_HEADER , format ("sha1=%s" , hash ))
94- .header (SIGNATURE_HEADER_SHA256 , format ("%s%s" , SHA256_PREFIX , hash256 ))
95- .body (classpath (String .format ("payloads/ping_hash_%s_secret_%s.json" , hash , secret )))
96- .log ().all ()
97- .expect ().log ().all ().statusCode (SC_OK ).request ().post (getPath ());
79+ HttpResponse <String > response = httpClient .send (
80+ HttpRequest .newBuilder (URI .create (getPath ()))
81+ .POST (HttpRequest .BodyPublishers .ofString (
82+ classpath (format ("payloads/ping_hash_%s_secret_%s.json" , hash , secret ))))
83+ .header ("Content-Type" , APPLICATION_JSON )
84+ .header (GHEventHeader .PayloadHandler .EVENT_HEADER , GHEvent .PUSH .name ().toLowerCase ())
85+ .header (SIGNATURE_HEADER , format ("sha1=%s" , hash ))
86+ .header (SIGNATURE_HEADER_SHA256 , format ("%s%s" , SHA256_PREFIX , hash256 ))
87+ .build (),
88+ HttpResponse .BodyHandlers .ofString ());
89+ assertThat ("status" , response .statusCode (), is (SC_OK ));
9890 }
9991
10092 @ Test
10193 void shouldParseFormWebHookOrServiceHookFromGH () throws Exception {
102- given ().spec (spec )
103- .header (eventHeader (GHEvent .PUSH ))
104- .header (FORM_CONTENT_TYPE )
105- .formParam ("payload" , classpath ("payloads/push.json" ))
106- .log ().all ()
107- .expect ().log ().all ().statusCode (SC_OK ).request ().post (getPath ());
94+ String encoded = "payload=" + java .net .URLEncoder .encode (classpath ("payloads/push.json" ), "UTF-8" );
95+ HttpResponse <String > response = httpClient .send (
96+ HttpRequest .newBuilder (URI .create (getPath ()))
97+ .POST (HttpRequest .BodyPublishers .ofString (encoded ))
98+ .header ("Content-Type" , FORM )
99+ .header (GHEventHeader .PayloadHandler .EVENT_HEADER , GHEvent .PUSH .name ().toLowerCase ())
100+ .build (),
101+ HttpResponse .BodyHandlers .ofString ());
102+ assertThat ("status" , response .statusCode (), is (SC_OK ));
108103 }
109104
110105 @ Test
111106 void shouldParsePingFromGH () throws Exception {
112- given ().spec (spec )
113- .header (eventHeader (GHEvent .PING ))
114- .header (JSON_CONTENT_TYPE )
115- .body (classpath ("payloads/ping.json" ))
116- .log ().all ()
117- .expect ().log ().all ()
118- .statusCode (SC_OK )
119- .request ()
120- .post (getPath ());
107+ HttpResponse <String > response = httpClient .send (
108+ HttpRequest .newBuilder (URI .create (getPath ()))
109+ .POST (HttpRequest .BodyPublishers .ofString (classpath ("payloads/ping.json" )))
110+ .header ("Content-Type" , APPLICATION_JSON )
111+ .header (GHEventHeader .PayloadHandler .EVENT_HEADER , GHEvent .PING .name ().toLowerCase ())
112+ .build (),
113+ HttpResponse .BodyHandlers .ofString ());
114+ assertThat ("status" , response .statusCode (), is (SC_OK ));
121115 }
122116
123117 @ Test
124118 void shouldReturnErrOnEmptyPayloadAndHeader () throws Exception {
125- given (). spec ( spec )
126- . log (). all ( )
127- . expect (). log (). all ( )
128- . statusCode ( SC_BAD_REQUEST )
129- . body ( containsString ( "Hook should contain event type" ))
130- . request ()
131- . post ( getPath ( ));
119+ HttpResponse < String > response = httpClient . send (
120+ HttpRequest . newBuilder ( URI . create ( getPath ()) )
121+ . POST ( HttpRequest . BodyPublishers . noBody () )
122+ . build (),
123+ HttpResponse . BodyHandlers . ofString ());
124+ assertThat ( "status" , response . statusCode (), is ( SC_BAD_REQUEST ));
125+ assertThat ( "body" , response . body (), containsString ( "Hook should contain event type" ));
132126 }
133127
134128 @ Test
135129 void shouldReturnErrOnEmptyPayload () throws Exception {
136- given (). spec ( spec )
137- . header ( eventHeader ( GHEvent . PUSH ))
138- . log (). all ( )
139- . expect (). log ().all ( )
140- . statusCode ( SC_BAD_REQUEST )
141- . body ( containsString ( "Hook should contain payload" ))
142- . request ()
143- . post ( getPath ( ));
130+ HttpResponse < String > response = httpClient . send (
131+ HttpRequest . newBuilder ( URI . create ( getPath () ))
132+ . POST ( HttpRequest . BodyPublishers . noBody () )
133+ . header ( GHEventHeader . PayloadHandler . EVENT_HEADER , GHEvent . PUSH . name ().toLowerCase () )
134+ . build (),
135+ HttpResponse . BodyHandlers . ofString ());
136+ assertThat ( "status" , response . statusCode (), is ( SC_BAD_REQUEST ));
137+ assertThat ( "body" , response . body (), containsString ( "Hook should contain payload" ));
144138 }
145139
146140 @ Test
147141 void shouldReturnErrOnGetReq () throws Exception {
148- given ().spec (spec )
149- .log ().all ().expect ().log ().all ()
150- .statusCode (SC_METHOD_NOT_ALLOWED )
151- .request ()
152- .get (getPath ());
142+ HttpResponse <String > response = httpClient .send (
143+ HttpRequest .newBuilder (URI .create (getPath ()))
144+ .GET ()
145+ .build (),
146+ HttpResponse .BodyHandlers .ofString ());
147+ assertThat ("status" , response .statusCode (), is (SC_METHOD_NOT_ALLOWED ));
153148 }
154149
155150 @ Test
156151 void shouldProcessSelfTest () throws Exception {
157- given ().spec (spec )
158- .header (new Header (GitHubWebHook .URL_VALIDATION_HEADER , NOT_NULL_VALUE ))
159- .log ().all ()
160- .expect ().log ().all ()
161- .statusCode (SC_OK )
162- .header (GitHubWebHook .X_INSTANCE_IDENTITY , notNullValue ())
163- .request ()
164- .post (getPath ());
165- }
166-
167- public Header eventHeader (GHEvent event ) {
168- return eventHeader (event .name ().toLowerCase ());
152+ HttpResponse <String > response = httpClient .send (
153+ HttpRequest .newBuilder (URI .create (getPath ()))
154+ .POST (HttpRequest .BodyPublishers .noBody ())
155+ .header (GitHubWebHook .URL_VALIDATION_HEADER , "nonnull" )
156+ .build (),
157+ HttpResponse .BodyHandlers .ofString ());
158+ assertThat ("status" , response .statusCode (), is (SC_OK ));
159+ assertThat ("identity header" , response .headers ().firstValue (GitHubWebHook .X_INSTANCE_IDENTITY ).orElse (null ), notNullValue ());
169160 }
170161
171- public Header eventHeader ( String event ) {
172- return new Header ( GHEventHeader . PayloadHandler . EVENT_HEADER , event );
162+ private String getPath ( ) {
163+ return jenkins . getInstance (). getRootUrl () + GitHubWebHook . URLNAME . concat ( "/" );
173164 }
174165
175166 public static String classpath (String path ) {
@@ -185,8 +176,4 @@ public static String classpath(Class<?> clazz, String path) {
185176 throw new RuntimeException (format ("Can't load %s for class %s" , path , clazz ), e );
186177 }
187178 }
188-
189- private String getPath (){
190- return jenkins .getInstance ().getRootUrl () + GitHubWebHook .URLNAME .concat ("/" );
191- }
192179}
0 commit comments