/* * Copyright 2000-2013 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jetbrains.buildServer.buildTriggers.url; import jetbrains.buildServer.BaseTestCase; import jetbrains.buildServer.util.FileUtil; import jetbrains.buildServer.util.SimpleFileHttpServer; import org.apache.http.conn.ConnectTimeoutException; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.net.UnknownHostException; import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; /** * User: Victory.Bedrosova * Date: 10/2/12 * Time: 6:01 PM */ @Test public class HttpResourceHashProviderTest extends BaseTestCase { MySimpleFileHttpServer myServer; File myHome; private boolean mySubstituteEtag; @BeforeMethod public void setUp() throws Exception { mySubstituteEtag = false; myHome = createTempDir(); myServer = new MySimpleFileHttpServer(); myServer.start(); } @AfterMethod public void tearDown() throws Exception { myServer.stop(); } @Test public void testNoServer() throws Exception { try { getResourceHash("http://unexisting"); } catch (ResourceHashProviderException e) { assertTrue(e.getCause() instanceof UnknownHostException); // expected } } @Test public void testNoFile() throws Exception { try { getResourceHash(getUrl(null, "unexisting")); } catch (ResourceHashProviderException e) { // expected } } @Test public void testFile() throws Exception { final File file = new File(myHome, "file"); final String fileUrl = toUrl(file, true); write(file, "A"); assertHash(getETag(file), fileUrl); write(file, "BC"); assertHash(getETag(file), fileUrl); write(file, "DEF"); assertHash(getETag(file), fileUrl); } @Test public void testAuthFails() throws Exception { final File file = new File(myHome, "file"); final String fileUrl = toUrl(file, false); try { getResourceHash(fileUrl); } catch (ResourceHashProviderException e) { // expected } } @Test public void testSeparateCredentials() throws Exception { final File file = new File(myHome, "file"); final String fileUrl = toUrl(file, false); write(file, "A"); assertEquals( getETag(file), createHttpHashProvider().getResourceHash(TriggerParameters.create(fileUrl, "admin", "admin"))); } @NotNull private String getETag(File file) { // SimpleFileHttpServer returns file.hashCode() as ETag and quotes it return "\"" + String.valueOf(file.hashCode()) + "\""; } // https://youtrack.jetbrains.com/issue/TW-44604 @Test public void testPreemptiveAuth() throws Exception { myServer.stop(); final MySimpleFileHttpServer server = new MySimpleFileHttpServer() { @Override protected Response getResponse(String request) { if (!request.contains("Authorization: Basic")) throw new IllegalArgumentException("Authorization header expected"); return super.getResponse(request); } }; server.start(); try { final File file = new File(myHome, "file"); final String fileUrl = toUrl(file, false); write(file, "A"); assertEquals( getETag(file), createHttpHashProvider().getResourceHash(TriggerParameters.create(fileUrl, "admin", "admin"))); } finally { server.stop(); } } @Test public void testConnectionTimeout() throws Exception { final long before = new Date().getTime(); try { createHttpHashProvider().getResourceHash(TriggerParameters.create("http://www.jetbrains.com:81", "admin", "admin", 10)); } catch (Throwable e) { final Collection causes = ResourceHashProviderTestUtil.getCauses(e); for (Throwable t : causes) { if (t instanceof ConnectTimeoutException) { // expected return; } } System.out.println(causes); fail(); } assertTrue(new Date().getTime() - before < 1000); } @Test public void testEtagCaseInsensitive() throws Exception { final File file = new File(myHome, "file"); final String fileUrl = toUrl(file, true); write(file, "A"); mySubstituteEtag = true; assertHash(getETag(file), fileUrl); } @NotNull private String getResourceHash(@NotNull String url) throws Exception { return createHttpHashProvider().getResourceHash(url); } @NotNull private HttpResourceHashProvider createHttpHashProvider() { HttpClientProvider httpClientProvider = new HttpClientProvider(null); return new HttpResourceHashProvider(httpClientProvider, new OAuthCredentialsProvider(httpClientProvider)); } @NotNull private static String getUrl(@NotNull MySimpleFileHttpServer server, @Nullable String userInfo, @NotNull String path) { return "http://" + (userInfo == null ? "" : userInfo + "@") + "localhost:" + server.getPort() + "/" + path; } @NotNull private String getUrl(@Nullable String userInfo, @NotNull String path) { return getUrl(myServer, userInfo, path); } @NotNull private String toUrl(@NotNull File file, boolean withCredentials) throws IOException { final String relativePath = getRelativePath(file); assertNotNull(relativePath); return getUrl(withCredentials ? "admin:admin" : null, relativePath.replace("\\", "/")); } @Nullable private String getRelativePath(@NotNull File file) { return FileUtil.getRelativePath(myHome, file); } private void write(@NotNull File f, @NotNull String text) throws IOException { ResourceHashProviderTestUtil.write(f, text); } private void assertHash(@NotNull String hash, @NotNull String url) throws Exception { assertEquals(url, hash, getResourceHash(url)); } private class MySimpleFileHttpServer extends SimpleFileHttpServer { public MySimpleFileHttpServer() { super(myHome); } @Nullable @Override protected String getRequestPath(@NotNull String request) { final Matcher matcher = Pattern.compile(".*(GET|HEAD)\\s+(\\S+)\\s.*", Pattern.DOTALL).matcher(request); if (matcher.matches()) { return matcher.group(2); } return null; } @Override protected Response getResponse(String request) { final Response initial = super.getResponse(request); if (mySubstituteEtag) { return new Response( initial.getStatusLine(), initial.getHeaders().stream().map(h -> h.startsWith("ETag:") ? h.replace("ETag:", "etag:") : h).collect(Collectors.toList())) { @Override public void printContent(PrintStream printStream) throws IOException { initial.printContent(printStream); } @Override public Integer getLength() { return initial.getLength(); } }; } return initial; } } }