package org.jenkinsci.plugins.github.webhook; import org.jenkinsci.plugins.github.GitHubPlugin; import org.jenkinsci.plugins.github.config.HookSecretConfig; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.jvnet.hudson.test.Issue; import org.jvnet.hudson.test.JenkinsRule; import org.kohsuke.github.GHEvent; import org.kohsuke.stapler.StaplerRequest; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.runners.MockitoJUnitRunner; import java.lang.reflect.InvocationTargetException; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.jenkinsci.plugins.github.test.HookSecretHelper.storeSecret; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.when; /** * @author lanwen (Merkushev Kirill) */ @RunWith(MockitoJUnitRunner.class) public class RequirePostWithGHHookPayloadTest { private static final String SECRET_CONTENT = "secret"; private static final String PAYLOAD = "sample payload"; @Mock private StaplerRequest req; @Rule public JenkinsRule jenkinsRule = new JenkinsRule(); @Spy private RequirePostWithGHHookPayload.Processor processor; @Before public void setSecret() { storeSecret(SECRET_CONTENT); } @Test public void shouldPassOnlyPost() throws Exception { when(req.getMethod()).thenReturn("POST"); new RequirePostWithGHHookPayload.Processor().shouldBePostMethod(req); } @Test(expected = InvocationTargetException.class) public void shouldNotPassOnNotPost() throws Exception { when(req.getMethod()).thenReturn("GET"); new RequirePostWithGHHookPayload.Processor().shouldBePostMethod(req); } @Test public void shouldPassOnGHEventAndNotBlankPayload() throws Exception { new RequirePostWithGHHookPayload.Processor().shouldContainParseablePayload( new Object[]{GHEvent.PUSH, "{}"}); } @Test(expected = InvocationTargetException.class) public void shouldNotPassOnNullGHEventAndNotBlankPayload() throws Exception { new RequirePostWithGHHookPayload.Processor().shouldContainParseablePayload( new Object[]{null, "{}"}); } @Test(expected = InvocationTargetException.class) public void shouldNotPassOnGHEventAndBlankPayload() throws Exception { new RequirePostWithGHHookPayload.Processor().shouldContainParseablePayload( new Object[]{GHEvent.PUSH, " "}); } @Test(expected = InvocationTargetException.class) public void shouldNotPassOnNulls() throws Exception { new RequirePostWithGHHookPayload.Processor().shouldContainParseablePayload( new Object[]{null, null}); } @Test(expected = InvocationTargetException.class) public void shouldNotPassOnGreaterCountOfArgs() throws Exception { new RequirePostWithGHHookPayload.Processor().shouldContainParseablePayload( new Object[]{GHEvent.PUSH, "{}", " "} ); } @Test(expected = InvocationTargetException.class) public void shouldNotPassOnLessCountOfArgs() throws Exception { new RequirePostWithGHHookPayload.Processor().shouldContainParseablePayload( new Object[]{GHEvent.PUSH} ); } @Test public void shouldPassOnAbsentSignatureInRequest() throws Exception { doReturn(PAYLOAD).when(processor).payloadFrom(req, null); processor.shouldProvideValidSignature(req, null); } @Test(expected = InvocationTargetException.class) public void shouldNotPassOnInvalidSignature() throws Exception { final String signature = "sha1=a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"; when(req.getHeader(RequirePostWithGHHookPayload.Processor.SIGNATURE_HEADER)).thenReturn(signature); doReturn(PAYLOAD).when(processor).payloadFrom(req, null); processor.shouldProvideValidSignature(req, null); } @Test(expected = InvocationTargetException.class) public void shouldNotPassOnMalformedSignature() throws Exception { final String signature = "49d5f5cf800a81f257324912969a2d325d13d3fc"; when(req.getHeader(RequirePostWithGHHookPayload.Processor.SIGNATURE_HEADER)).thenReturn(signature); doReturn(PAYLOAD).when(processor).payloadFrom(req, null); processor.shouldProvideValidSignature(req, null); } @Test public void shouldPassWithValidSignature() throws Exception { final String signature = "sha1=49d5f5cf800a81f257324912969a2d325d13d3fc"; when(req.getHeader(RequirePostWithGHHookPayload.Processor.SIGNATURE_HEADER)).thenReturn(signature); doReturn(PAYLOAD).when(processor).payloadFrom(req, null); processor.shouldProvideValidSignature(req, null); } @Test @Issue("JENKINS-37481") public void shouldIgnoreSignHeaderOnNotDefinedSignInConfig() throws Exception { GitHubPlugin.configuration().setHookSecretConfig(new HookSecretConfig(null)); final String signature = "sha1=49d5f5cf800a81f257324912969a2d325d13d3fc"; when(req.getHeader(RequirePostWithGHHookPayload.Processor.SIGNATURE_HEADER)).thenReturn(signature); processor.shouldProvideValidSignature(req, null); } @Test public void shouldReturnValidPayloadOnApplicationJson() { final String payload = "test"; doReturn(GHEventPayload.PayloadHandler.APPLICATION_JSON).when(req).getContentType(); final String body = processor.payloadFrom(req, new Object[]{null, payload}); assertThat("valid returned body", body, equalTo(payload)); } @Test public void shouldReturnValidPayloadOnFormUrlEncoded() { final String payload = "test"; doReturn(GHEventPayload.PayloadHandler.FORM_URLENCODED).when(req).getContentType(); final String body = processor.payloadFrom(req, new Object[]{null, payload}); assertThat("valid returned body", body, equalTo("payload=" + payload)); } }