Browse Source

Add JUnit tests for HTTP transport

No Eclipse support for this project is provided, because the
Jetty project does not publish a complete P2 repository.

Change-Id: Ic5fe2e79bb216e36920fd4a70ec15dd6ccfd1468
Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
tags/v0.7.0
Shawn O. Pearce 14 years ago
parent
commit
f5eb0d9366
22 changed files with 3476 additions and 18 deletions
  1. 1
    0
      org.eclipse.jgit.http.test/.gitignore
  2. 108
    0
      org.eclipse.jgit.http.test/pom.xml
  3. 136
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AsIsServiceTest.java
  4. 198
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java
  5. 160
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java
  6. 246
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java
  7. 261
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java
  8. 85
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ErrorServletTest.java
  9. 137
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/FileResolverTest.java
  10. 119
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletInitTest.java
  11. 328
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java
  12. 556
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java
  13. 181
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/AccessEvent.java
  14. 295
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/AppServer.java
  15. 161
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/HttpTestCase.java
  16. 85
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/MockServletConfig.java
  17. 146
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/RecordingLogger.java
  18. 71
    0
      org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/TestRequestLog.java
  19. 11
    1
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
  20. 150
    12
      org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
  21. 31
    5
      org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java
  22. 10
    0
      pom.xml

+ 1
- 0
org.eclipse.jgit.http.test/.gitignore View File

@@ -0,0 +1 @@
/target

+ 108
- 0
org.eclipse.jgit.http.test/pom.xml View File

@@ -0,0 +1,108 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (C) 2009-2010, Google Inc.
Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
and other copyright owners as documented in the project's IP log.

This program and the accompanying materials are made available
under the terms of the Eclipse Distribution License v1.0 which
accompanies this distribution, is reproduced below, and is
available at http://www.eclipse.org/org/documents/edl-v10.php

All rights reserved.

Redistribution and use in source and binary forms, with or
without modification, are permitted provided that the following
conditions are met:

- Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.

- Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.

- Neither the name of the Eclipse Foundation, Inc. nor the
names of its contributors may be used to endorse or promote
products derived from this software without specific prior
written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-->

<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit-parent</artifactId>
<version>0.6.0-SNAPSHOT</version>
</parent>

<artifactId>org.eclipse.jgit.http.test</artifactId>
<name>JGit - HTTP Tests</name>

<description>
Tests for the HTTP transport.
</description>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.junit</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.eclipse.jgit</groupId>
<artifactId>org.eclipse.jgit.http.server</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<testSourceDirectory>tst/</testSourceDirectory>

<testResources>
<testResource>
<directory>tst-rsrc/</directory>
</testResource>
</testResources>
</build>
</project>

+ 136
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/AsIsServiceTest.java View File

@@ -0,0 +1,136 @@
/*
* Copyright (C) 2009-2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import javax.servlet.http.HttpServletRequestWrapper;

import org.eclipse.jetty.server.Request;
import org.eclipse.jgit.http.server.resolver.AsIsFileService;
import org.eclipse.jgit.http.server.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.lib.Repository;

public class AsIsServiceTest extends LocalDiskRepositoryTestCase {
private Repository db;

private AsIsFileService service;

protected void setUp() throws Exception {
super.setUp();

db = createBareRepository();
service = new AsIsFileService();
}

public void testDisabledSingleton() throws ServiceNotAuthorizedException {
service = AsIsFileService.DISABLED;
try {
service.access(new R(null, "1.2.3.4"), db);
fail("Created session for anonymous user: null");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
service.access(new R("bob", "1.2.3.4"), db);
fail("Created session for user: \"bob\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}
}

public void testCreate_Default() throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
service.access(new R(null, "1.2.3.4"), db);
service.access(new R("bob", "1.2.3.4"), db);
}

public void testCreate_Disabled() throws ServiceNotAuthorizedException {
db.getConfig().setBoolean("http", null, "getanyfile", false);

try {
service.access(new R(null, "1.2.3.4"), db);
fail("Created session for anonymous user: null");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
service.access(new R("bob", "1.2.3.4"), db);
fail("Created session for user: \"bob\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}
}

public void testCreate_Enabled() throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
db.getConfig().setBoolean("http", null, "getanyfile", true);
service.access(new R(null, "1.2.3.4"), db);
service.access(new R("bob", "1.2.3.4"), db);
}

private final class R extends HttpServletRequestWrapper {
private final String user;

private final String host;

R(final String user, final String host) {
super(new Request() /* can't pass null, sigh */);
this.user = user;
this.host = host;
}

@Override
public String getRemoteHost() {
return host;
}

@Override
public String getRemoteUser() {
return user;
}
}
}

+ 198
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultReceivePackFactoryTest.java View File

@@ -0,0 +1,198 @@
/*
* Copyright (C) 2009-2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import javax.servlet.http.HttpServletRequestWrapper;

import org.eclipse.jetty.server.Request;
import org.eclipse.jgit.http.server.resolver.DefaultReceivePackFactory;
import org.eclipse.jgit.http.server.resolver.ReceivePackFactory;
import org.eclipse.jgit.http.server.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.ReceivePack;

public class DefaultReceivePackFactoryTest extends LocalDiskRepositoryTestCase {
private Repository db;

private ReceivePackFactory factory;

protected void setUp() throws Exception {
super.setUp();

db = createBareRepository();
factory = new DefaultReceivePackFactory();
}

public void testDisabledSingleton() throws ServiceNotAuthorizedException {
factory = ReceivePackFactory.DISABLED;

try {
factory.create(new R(null, "localhost"), db);
fail("Created session for anonymous user: null");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
factory.create(new R("", "localhost"), db);
fail("Created session for anonymous user: \"\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
factory.create(new R("bob", "localhost"), db);
fail("Created session for user: \"bob\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}
}

public void testCreate_NullUser() throws ServiceNotEnabledException {
try {
factory.create(new R(null, "localhost"), db);
fail("Created session for anonymous user: null");
} catch (ServiceNotAuthorizedException e) {
// expected not authorized
}
}

public void testCreate_EmptyStringUser() throws ServiceNotEnabledException {
try {
factory.create(new R("", "localhost"), db);
fail("Created session for anonymous user: \"\"");
} catch (ServiceNotAuthorizedException e) {
// expected not authorized
}
}

public void testCreate_AuthUser() throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
ReceivePack rp;
rp = factory.create(new R("bob", "1.2.3.4"), db);
assertNotNull("have ReceivePack", rp);
assertSame(db, rp.getRepository());

PersonIdent id = rp.getRefLogIdent();
assertNotNull(id);
assertEquals("bob", id.getName());
assertEquals("bob@1.2.3.4", id.getEmailAddress());

// Should have inherited off the current system, which is mocked
assertEquals(author.getTimeZoneOffset(), id.getTimeZoneOffset());
assertEquals(author.getWhen(), id.getWhen());
}

public void testCreate_Disabled() throws ServiceNotAuthorizedException {
db.getConfig().setBoolean("http", null, "receivepack", false);

try {
factory.create(new R(null, "localhost"), db);
fail("Created session for anonymous user: null");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
factory.create(new R("", "localhost"), db);
fail("Created session for anonymous user: \"\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
factory.create(new R("bob", "localhost"), db);
fail("Created session for user: \"bob\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}
}

public void testCreate_Enabled() throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
db.getConfig().setBoolean("http", null, "receivepack", true);
ReceivePack rp;

rp = factory.create(new R(null, "1.2.3.4"), db);
assertNotNull("have ReceivePack", rp);
assertSame(db, rp.getRepository());

PersonIdent id = rp.getRefLogIdent();
assertNotNull(id);
assertEquals("anonymous", id.getName());
assertEquals("anonymous@1.2.3.4", id.getEmailAddress());

// Should have inherited off the current system, which is mocked
assertEquals(author.getTimeZoneOffset(), id.getTimeZoneOffset());
assertEquals(author.getWhen(), id.getWhen());

rp = factory.create(new R("bob", "1.2.3.4"), db);
assertNotNull("have ReceivePack", rp);
}

private final class R extends HttpServletRequestWrapper {
private final String user;

private final String host;

R(final String user, final String host) {
super(new Request() /* can't pass null, sigh */);
this.user = user;
this.host = host;
}

@Override
public String getRemoteHost() {
return host;
}

@Override
public String getRemoteUser() {
return user;
}
}
}

+ 160
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DefaultUploadPackFactoryTest.java View File

@@ -0,0 +1,160 @@
/*
* Copyright (C) 2009-2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import javax.servlet.http.HttpServletRequestWrapper;

import org.eclipse.jetty.server.Request;
import org.eclipse.jgit.http.server.resolver.DefaultUploadPackFactory;
import org.eclipse.jgit.http.server.resolver.ServiceNotAuthorizedException;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.http.server.resolver.UploadPackFactory;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.transport.UploadPack;

public class DefaultUploadPackFactoryTest extends LocalDiskRepositoryTestCase {
private Repository db;

private UploadPackFactory factory;

protected void setUp() throws Exception {
super.setUp();

db = createBareRepository();
factory = new DefaultUploadPackFactory();
}

public void testDisabledSingleton() throws ServiceNotAuthorizedException {
factory = UploadPackFactory.DISABLED;

try {
factory.create(new R(null, "localhost"), db);
fail("Created session for anonymous user: null");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
factory.create(new R("", "localhost"), db);
fail("Created session for anonymous user: \"\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
factory.create(new R("bob", "localhost"), db);
fail("Created session for user: \"bob\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}
}

public void testCreate_Default() throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
UploadPack up;

up = factory.create(new R(null, "1.2.3.4"), db);
assertNotNull("have UploadPack", up);
assertSame(db, up.getRepository());

up = factory.create(new R("bob", "1.2.3.4"), db);
assertNotNull("have UploadPack", up);
assertSame(db, up.getRepository());
}

public void testCreate_Disabled() throws ServiceNotAuthorizedException {
db.getConfig().setBoolean("http", null, "uploadpack", false);

try {
factory.create(new R(null, "localhost"), db);
fail("Created session for anonymous user: null");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}

try {
factory.create(new R("bob", "localhost"), db);
fail("Created session for user: \"bob\"");
} catch (ServiceNotEnabledException e) {
// expected not authorized
}
}

public void testCreate_Enabled() throws ServiceNotEnabledException,
ServiceNotAuthorizedException {
db.getConfig().setBoolean("http", null, "uploadpack", true);
UploadPack up;

up = factory.create(new R(null, "1.2.3.4"), db);
assertNotNull("have UploadPack", up);
assertSame(db, up.getRepository());

up = factory.create(new R("bob", "1.2.3.4"), db);
assertNotNull("have UploadPack", up);
assertSame(db, up.getRepository());
}

private final class R extends HttpServletRequestWrapper {
private final String user;

private final String host;

R(final String user, final String host) {
super(new Request() /* can't pass null, sigh */);
this.user = user;
this.host = host;
}

@Override
public String getRemoteHost() {
return host;
}

@Override
public String getRemoteUser() {
return user;
}
}
}

+ 246
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientDumbServerTest.java View File

@@ -0,0 +1,246 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT;
import static org.eclipse.jgit.util.HttpSupport.HDR_PRAGMA;
import static org.eclipse.jgit.util.HttpSupport.HDR_USER_AGENT;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.util.List;
import java.util.Map;

import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.http.test.util.AccessEvent;
import org.eclipse.jgit.http.test.util.HttpTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.FetchConnection;
import org.eclipse.jgit.transport.HttpTransport;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.TransportHttp;
import org.eclipse.jgit.transport.URIish;

public class DumbClientDumbServerTest extends HttpTestCase {
private Repository remoteRepository;

private URIish remoteURI;

private RevBlob A_txt;

private RevCommit A, B;

protected void setUp() throws Exception {
super.setUp();

final TestRepository src = createTestRepository();
final File srcGit = src.getRepository().getDirectory();
final URI base = srcGit.getParentFile().toURI();

ServletContextHandler app = server.addContext("/git");
app.setResourceBase(base.toString());
app.addServlet(DefaultServlet.class, "/");

server.setUp();

remoteRepository = src.getRepository();
remoteURI = toURIish(app, srcGit.getName());

A_txt = src.blob("A");
A = src.commit().add("A_txt", A_txt).create();
B = src.commit().parent(A).add("A_txt", "C").add("B", "B").create();
src.update(master, B);
}

public void testListRemote() throws IOException {
Repository dst = createBareRepository();

assertEquals("http", remoteURI.getScheme());

Map<String, Ref> map;
Transport t = Transport.open(dst, remoteURI);
try {
// I didn't make up these public interface names, I just
// approved them for inclusion into the code base. Sorry.
// --spearce
//
assertTrue("isa TransportHttp", t instanceof TransportHttp);
assertTrue("isa HttpTransport", t instanceof HttpTransport);

FetchConnection c = t.openFetch();
try {
map = c.getRefsMap();
} finally {
c.close();
}
} finally {
t.close();
}

assertNotNull("have map of refs", map);
assertEquals(2, map.size());

assertNotNull("has " + master, map.get(master));
assertEquals(B, map.get(master).getObjectId());

assertNotNull("has " + Constants.HEAD, map.get(Constants.HEAD));
assertEquals(B, map.get(Constants.HEAD).getObjectId());

List<AccessEvent> requests = getRequests();
assertEquals(2, requests.size());
assertEquals(0, getRequests(remoteURI, "git-upload-pack").size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(remoteURI, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-upload-pack", info.getParameter("service"));
assertEquals("no-cache", info.getRequestHeader(HDR_PRAGMA));
assertNotNull("has user-agent", info.getRequestHeader(HDR_USER_AGENT));
assertTrue("is jgit agent", info.getRequestHeader(HDR_USER_AGENT)
.startsWith("JGit/"));
assertEquals("application/x-git-upload-pack-advertisement, */*", info
.getRequestHeader(HDR_ACCEPT));
assertEquals(200, info.getStatus());

AccessEvent head = requests.get(1);
assertEquals("GET", head.getMethod());
assertEquals(join(remoteURI, "HEAD"), head.getPath());
assertEquals(0, head.getParameters().size());
assertEquals("no-cache", head.getRequestHeader(HDR_PRAGMA));
assertNotNull("has user-agent", head.getRequestHeader(HDR_USER_AGENT));
assertTrue("is jgit agent", head.getRequestHeader(HDR_USER_AGENT)
.startsWith("JGit/"));
assertEquals(200, head.getStatus());
}

public void testInitialClone_Loose() throws Exception {
Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, remoteURI);
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}

assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId());
fsck(dst, B);

List<AccessEvent> loose = getRequests(loose(remoteURI, A_txt));
assertEquals(1, loose.size());
assertEquals("GET", loose.get(0).getMethod());
assertEquals(0, loose.get(0).getParameters().size());
assertEquals(200, loose.get(0).getStatus());
}

public void testInitialClone_Packed() throws Exception {
new TestRepository(remoteRepository).packAndPrune();

Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, remoteURI);
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}

assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId());
fsck(dst, B);

List<AccessEvent> req;
AccessEvent event;

req = getRequests(loose(remoteURI, B));
assertEquals(1, req.size());
event = req.get(0);
assertEquals("GET", event.getMethod());
assertEquals(0, event.getParameters().size());
assertEquals(404, event.getStatus());

req = getRequests(join(remoteURI, "objects/info/packs"));
assertEquals(1, req.size());
event = req.get(0);
assertEquals("GET", event.getMethod());
assertEquals(0, event.getParameters().size());
assertEquals("no-cache", event.getRequestHeader(HDR_PRAGMA));
assertNotNull("has user-agent", event.getRequestHeader(HDR_USER_AGENT));
assertTrue("is jgit agent", event.getRequestHeader(HDR_USER_AGENT)
.startsWith("JGit/"));
assertEquals(200, event.getStatus());
}

public void testPushNotSupported() throws Exception {
final TestRepository src = createTestRepository();
final RevCommit Q = src.commit().create();
final Repository db = src.getRepository();

Transport t = Transport.open(db, remoteURI);
try {
try {
t.push(NullProgressMonitor.INSTANCE, push(src, Q));
fail("push incorrectly completed against a dumb server");
} catch (NotSupportedException nse) {
String exp = "remote does not support smart HTTP push";
assertEquals(exp, nse.getMessage());
}
} finally {
t.close();
}
}
}

+ 261
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/DumbClientSmartServerTest.java View File

@@ -0,0 +1,261 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import static org.eclipse.jgit.util.HttpSupport.HDR_ACCEPT;
import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE;
import static org.eclipse.jgit.util.HttpSupport.HDR_PRAGMA;
import static org.eclipse.jgit.util.HttpSupport.HDR_USER_AGENT;

import java.io.IOException;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jgit.errors.NotSupportedException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.http.server.GitServlet;
import org.eclipse.jgit.http.server.resolver.RepositoryResolver;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.http.test.util.AccessEvent;
import org.eclipse.jgit.http.test.util.HttpTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.FetchConnection;
import org.eclipse.jgit.transport.HttpTransport;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.TransportHttp;
import org.eclipse.jgit.transport.URIish;

public class DumbClientSmartServerTest extends HttpTestCase {
private Repository remoteRepository;

private URIish remoteURI;

private RevBlob A_txt;

private RevCommit A, B;

protected void setUp() throws Exception {
super.setUp();

final TestRepository src = createTestRepository();
final String srcName = src.getRepository().getDirectory().getName();

ServletContextHandler app = server.addContext("/git");
GitServlet gs = new GitServlet();
gs.setRepositoryResolver(new RepositoryResolver() {
public Repository open(HttpServletRequest req, String name)
throws RepositoryNotFoundException,
ServiceNotEnabledException {
if (!name.equals(srcName))
throw new RepositoryNotFoundException(name);

final Repository db = src.getRepository();
db.incrementOpen();
return db;
}
});
app.addServlet(new ServletHolder(gs), "/*");

server.setUp();

remoteRepository = src.getRepository();
remoteURI = toURIish(app, srcName);

A_txt = src.blob("A");
A = src.commit().add("A_txt", A_txt).create();
B = src.commit().parent(A).add("A_txt", "C").add("B", "B").create();
src.update(master, B);
}

public void testListRemote() throws IOException {
Repository dst = createBareRepository();

assertEquals("http", remoteURI.getScheme());

Map<String, Ref> map;
Transport t = Transport.open(dst, remoteURI);
((TransportHttp) t).setUseSmartHttp(false);
try {
// I didn't make up these public interface names, I just
// approved them for inclusion into the code base. Sorry.
// --spearce
//
assertTrue("isa TransportHttp", t instanceof TransportHttp);
assertTrue("isa HttpTransport", t instanceof HttpTransport);

FetchConnection c = t.openFetch();
try {
map = c.getRefsMap();
} finally {
c.close();
}
} finally {
t.close();
}

assertNotNull("have map of refs", map);
assertEquals(2, map.size());

assertNotNull("has " + master, map.get(master));
assertEquals(B, map.get(master).getObjectId());

assertNotNull("has " + Constants.HEAD, map.get(Constants.HEAD));
assertEquals(B, map.get(Constants.HEAD).getObjectId());

List<AccessEvent> requests = getRequests();
assertEquals(2, requests.size());
assertEquals(0, getRequests(remoteURI, "git-upload-pack").size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(remoteURI, "info/refs"), info.getPath());
assertEquals(0, info.getParameters().size());
assertNull("no service parameter", info.getParameter("service"));
assertEquals("no-cache", info.getRequestHeader(HDR_PRAGMA));
assertNotNull("has user-agent", info.getRequestHeader(HDR_USER_AGENT));
assertTrue("is jgit agent", info.getRequestHeader(HDR_USER_AGENT)
.startsWith("JGit/"));
assertEquals("*/*", info.getRequestHeader(HDR_ACCEPT));
assertEquals(200, info.getStatus());
assertEquals("text/plain;charset=UTF-8", info
.getResponseHeader(HDR_CONTENT_TYPE));

AccessEvent head = requests.get(1);
assertEquals("GET", head.getMethod());
assertEquals(join(remoteURI, "HEAD"), head.getPath());
assertEquals(0, head.getParameters().size());
assertEquals(200, head.getStatus());
assertEquals("text/plain", head.getResponseHeader(HDR_CONTENT_TYPE));
}

public void testInitialClone_Small() throws Exception {
Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, remoteURI);
((TransportHttp) t).setUseSmartHttp(false);
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}

assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId());
fsck(dst, B);

List<AccessEvent> loose = getRequests(loose(remoteURI, A_txt));
assertEquals(1, loose.size());
assertEquals("GET", loose.get(0).getMethod());
assertEquals(0, loose.get(0).getParameters().size());
assertEquals(200, loose.get(0).getStatus());
assertEquals("application/x-git-loose-object", loose.get(0)
.getResponseHeader(HDR_CONTENT_TYPE));
}

public void testInitialClone_Packed() throws Exception {
new TestRepository(remoteRepository).packAndPrune();

Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, remoteURI);
((TransportHttp) t).setUseSmartHttp(false);
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}

assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId());
fsck(dst, B);

List<AccessEvent> req;

req = getRequests(loose(remoteURI, B));
assertEquals(1, req.size());
assertEquals("GET", req.get(0).getMethod());
assertEquals(0, req.get(0).getParameters().size());
assertEquals(404, req.get(0).getStatus());

req = getRequests(join(remoteURI, "objects/info/packs"));
assertEquals(1, req.size());
assertEquals("GET", req.get(0).getMethod());
assertEquals(0, req.get(0).getParameters().size());
assertEquals(200, req.get(0).getStatus());
assertEquals("text/plain;charset=UTF-8", req.get(0).getResponseHeader(
HDR_CONTENT_TYPE));
}

public void testPushNotSupported() throws Exception {
final TestRepository src = createTestRepository();
final RevCommit Q = src.commit().create();
final Repository db = src.getRepository();

Transport t = Transport.open(db, remoteURI);
((TransportHttp) t).setUseSmartHttp(false);
try {
try {
t.push(NullProgressMonitor.INSTANCE, push(src, Q));
fail("push incorrectly completed against a smart server");
} catch (NotSupportedException nse) {
String exp = "smart HTTP push disabled";
assertEquals(exp, nse.getMessage());
}
} finally {
t.close();
}
}
}

+ 85
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/ErrorServletTest.java View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2009-2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import java.net.HttpURLConnection;
import java.net.URI;

import junit.framework.TestCase;

import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jgit.http.server.glue.ErrorServlet;
import org.eclipse.jgit.http.test.util.AppServer;

public class ErrorServletTest extends TestCase {
private AppServer server;

protected void setUp() throws Exception {
super.setUp();

server = new AppServer();

ServletContextHandler ctx = server.addContext("/");
ctx.addServlet(new ServletHolder(new ErrorServlet(404)), "/404");
ctx.addServlet(new ServletHolder(new ErrorServlet(500)), "/500");

server.setUp();
}

protected void tearDown() throws Exception {
if (server != null) {
server.tearDown();
}
super.tearDown();
}

public void testHandler() throws Exception {
final URI uri = server.getURI();
assertEquals(404, ((HttpURLConnection) uri.resolve("/404").toURL()
.openConnection()).getResponseCode());
assertEquals(500, ((HttpURLConnection) uri.resolve("/500").toURL()
.openConnection()).getResponseCode());
}
}

+ 137
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/FileResolverTest.java View File

@@ -0,0 +1,137 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import java.io.File;
import java.io.IOException;

import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.http.server.resolver.FileResolver;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.lib.Repository;

public class FileResolverTest extends LocalDiskRepositoryTestCase {
public void testUnreasonableNames() throws ServiceNotEnabledException {
assertUnreasonable("");
assertUnreasonable("a\\b");
assertUnreasonable("../b");
assertUnreasonable("a/../b");
assertUnreasonable("a/./b");
assertUnreasonable("a//b");

if (new File("/foo").isAbsolute())
assertUnreasonable("/foo");

if (new File("//server/share").isAbsolute())
assertUnreasonable("//server/share");

if (new File("C:/windows").isAbsolute())
assertUnreasonable("C:/windows");
}

private void assertUnreasonable(String name)
throws ServiceNotEnabledException {
FileResolver r = new FileResolver(new File("."), false);
try {
r.open(null, name);
fail("Opened unreasonable name \"" + name + "\"");
} catch (RepositoryNotFoundException e) {
assertEquals("repository not found: " + name, e.getMessage());
assertNull("has no cause", e.getCause());
}
}

public void testExportOk() throws IOException {
final Repository a = createBareRepository();
final String name = a.getDirectory().getName();
final File base = a.getDirectory().getParentFile();
final File export = new File(a.getDirectory(), "git-daemon-export-ok");
FileResolver resolver;

assertFalse("no git-daemon-export-ok", export.exists());
resolver = new FileResolver(base, false /* require flag */);
try {
resolver.open(null, name);
fail("opened non-exported repository");
} catch (ServiceNotEnabledException e) {
assertEquals("Service not enabled", e.getMessage());
}

resolver = new FileResolver(base, true /* export all */);
try {
resolver.open(null, name).close();
} catch (ServiceNotEnabledException e) {
fail("did not honor export-all flag");
}

export.createNewFile();
assertTrue("has git-daemon-export-ok", export.exists());
resolver = new FileResolver(base, false /* require flag */);
try {
resolver.open(null, name).close();
} catch (ServiceNotEnabledException e) {
fail("did not honor git-daemon-export-ok");
}
}

public void testNotAGitRepository() throws IOException,
ServiceNotEnabledException {
final Repository a = createBareRepository();
final String name = a.getDirectory().getName() + "-not-a-git";
final File base = a.getDirectory().getParentFile();
FileResolver resolver = new FileResolver(base, false);

try {
resolver.open(null, name);
} catch (RepositoryNotFoundException e) {
assertEquals("repository not found: " + name, e.getMessage());

Throwable why = e.getCause();
assertNotNull("has cause", why);
assertEquals("repository not found: "
+ new File(base, name).getAbsolutePath(), why.getMessage());
}
}
}

+ 119
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/GitServletInitTest.java View File

@@ -0,0 +1,119 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import java.util.List;

import javax.servlet.ServletException;

import junit.framework.TestCase;

import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jgit.http.server.GitServlet;
import org.eclipse.jgit.http.test.util.AppServer;
import org.eclipse.jgit.http.test.util.MockServletConfig;
import org.eclipse.jgit.http.test.util.RecordingLogger;

public class GitServletInitTest extends TestCase {
private AppServer server;

protected void tearDown() throws Exception {
if (server != null) {
server.tearDown();
server = null;
}
super.tearDown();
}

public void testDefaultConstructor_NoBasePath() throws Exception {
GitServlet s = new GitServlet();
try {
s.init(new MockServletConfig());
fail("Init did not crash due to missing parameter");
} catch (ServletException e) {
assertTrue(e.getMessage().contains("base-path"));
}
}

public void testDefaultConstructor_WithBasePath() throws Exception {
MockServletConfig c = new MockServletConfig();
c.setInitParameter("base-path", ".");
c.setInitParameter("export-all", "false");

GitServlet s = new GitServlet();
s.init(c);
s.destroy();
}

public void testInitUnderContainer_NoBasePath() throws Exception {
server = new AppServer();

ServletContextHandler app = server.addContext("/");
ServletHolder s = app.addServlet(GitServlet.class, "/git");
s.setInitOrder(1);

server.setUp();

List<RecordingLogger.Warning> events = RecordingLogger.getWarnings();
assertFalse("Servlet started without base-path", events.isEmpty());

Throwable why = events.get(0).getCause();
assertTrue("Caught ServletException", why instanceof ServletException);
assertTrue("Wanted base-path", why.getMessage().contains("base-path"));
}

public void testInitUnderContainer_WithBasePath() throws Exception {
server = new AppServer();

ServletContextHandler app = server.addContext("/");
ServletHolder s = app.addServlet(GitServlet.class, "/git");
s.setInitOrder(1);
s.setInitParameter("base-path", ".");
s.setInitParameter("export-all", "true");

server.setUp();
assertTrue("no warnings", RecordingLogger.getWarnings().isEmpty());
}
}

+ 328
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/HttpClientTests.java View File

@@ -0,0 +1,328 @@
/*
* Copyright (C) 2009-2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import java.io.File;
import java.net.URI;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.eclipse.jetty.servlet.DefaultServlet;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jgit.errors.NoRemoteRepositoryException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.http.server.GitServlet;
import org.eclipse.jgit.http.server.resolver.RepositoryResolver;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.http.test.util.AccessEvent;
import org.eclipse.jgit.http.test.util.HttpTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.FetchConnection;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.URIish;

public class HttpClientTests extends HttpTestCase {
private TestRepository remoteRepository;

private URIish dumbAuthNoneURI;

private URIish dumbAuthBasicURI;

private URIish smartAuthNoneURI;

private URIish smartAuthBasicURI;

protected void setUp() throws Exception {
super.setUp();

remoteRepository = createTestRepository();
remoteRepository.update(master, remoteRepository.commit().create());

ServletContextHandler dNone = dumb("/dnone");
ServletContextHandler dBasic = server.authBasic(dumb("/dbasic"));

ServletContextHandler sNone = smart("/snone");
ServletContextHandler sBasic = server.authBasic(smart("/sbasic"));

server.setUp();

final String srcName = nameOf(remoteRepository);
dumbAuthNoneURI = toURIish(dNone, srcName);
dumbAuthBasicURI = toURIish(dBasic, srcName);

smartAuthNoneURI = toURIish(sNone, srcName);
smartAuthBasicURI = toURIish(sBasic, srcName);
}

private ServletContextHandler dumb(final String path) {
final File srcGit = remoteRepository.getRepository().getDirectory();
final URI base = srcGit.getParentFile().toURI();

ServletContextHandler ctx = server.addContext(path);
ctx.setResourceBase(base.toString());
ctx.addServlet(DefaultServlet.class, "/");
return ctx;
}

private ServletContextHandler smart(final String path) {
GitServlet gs = new GitServlet();
gs.setRepositoryResolver(new RepositoryResolver() {
public Repository open(HttpServletRequest req, String name)
throws RepositoryNotFoundException,
ServiceNotEnabledException {
if (!name.equals(nameOf(remoteRepository)))
throw new RepositoryNotFoundException(name);

final Repository db = remoteRepository.getRepository();
db.incrementOpen();
return db;
}
});

ServletContextHandler ctx = server.addContext(path);
ctx.addServlet(new ServletHolder(gs), "/*");
return ctx;
}

private static String nameOf(final TestRepository db) {
return db.getRepository().getDirectory().getName();
}

public void testRepositoryNotFound_Dumb() throws Exception {
URIish uri = toURIish("/dumb.none/not-found");
Repository dst = createBareRepository();
Transport t = Transport.open(dst, uri);
try {
try {
t.openFetch();
fail("connection opened to not found repository");
} catch (NoRemoteRepositoryException err) {
String exp = uri + ": " + uri
+ "/info/refs?service=git-upload-pack not found";
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

public void testRepositoryNotFound_Smart() throws Exception {
URIish uri = toURIish("/smart.none/not-found");
Repository dst = createBareRepository();
Transport t = Transport.open(dst, uri);
try {
try {
t.openFetch();
fail("connection opened to not found repository");
} catch (NoRemoteRepositoryException err) {
String exp = uri + ": " + uri
+ "/info/refs?service=git-upload-pack not found";
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

public void testListRemote_Dumb_DetachedHEAD() throws Exception {
Repository src = remoteRepository.getRepository();
RefUpdate u = src.updateRef(Constants.HEAD, true);
RevCommit Q = remoteRepository.commit().message("Q").create();
u.setNewObjectId(Q);
assertEquals(RefUpdate.Result.FORCED, u.forceUpdate());

Repository dst = createBareRepository();
Ref head;
Transport t = Transport.open(dst, dumbAuthNoneURI);
try {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
}
assertNotNull("has " + Constants.HEAD, head);
assertEquals(Q, head.getObjectId());
}

public void testListRemote_Dumb_NoHEAD() throws Exception {
Repository src = remoteRepository.getRepository();
File headref = new File(src.getDirectory(), Constants.HEAD);
assertTrue("HEAD used to be present", headref.delete());
assertFalse("HEAD is gone", headref.exists());

Repository dst = createBareRepository();
Ref head;
Transport t = Transport.open(dst, dumbAuthNoneURI);
try {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
}
assertNull("has no " + Constants.HEAD, head);
}

public void testListRemote_Smart_DetachedHEAD() throws Exception {
Repository src = remoteRepository.getRepository();
RefUpdate u = src.updateRef(Constants.HEAD, true);
RevCommit Q = remoteRepository.commit().message("Q").create();
u.setNewObjectId(Q);
assertEquals(RefUpdate.Result.FORCED, u.forceUpdate());

Repository dst = createBareRepository();
Ref head;
Transport t = Transport.open(dst, smartAuthNoneURI);
try {
FetchConnection c = t.openFetch();
try {
head = c.getRef(Constants.HEAD);
} finally {
c.close();
}
} finally {
t.close();
}
assertNotNull("has " + Constants.HEAD, head);
assertEquals(Q, head.getObjectId());
}

public void testListRemote_Smart_WithQueryParameters() throws Exception {
URIish myURI = toURIish("/snone/do?r=1&p=test.git");
Repository dst = createBareRepository();
Transport t = Transport.open(dst, myURI);
try {
try {
t.openFetch();
fail("test did not fail to find repository as expected");
} catch (NoRemoteRepositoryException err) {
// expected
}
} finally {
t.close();
}

List<AccessEvent> requests = getRequests();
assertEquals(1, requests.size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals("/snone/do", info.getPath());
assertEquals(3, info.getParameters().size());
assertEquals("1", info.getParameter("r"));
assertEquals("test.git/info/refs", info.getParameter("p"));
assertEquals("git-upload-pack", info.getParameter("service"));
assertEquals(404, info.getStatus());
}

public void testListRemote_Dumb_NeedsAuth() throws Exception {
Repository dst = createBareRepository();
Transport t = Transport.open(dst, dumbAuthBasicURI);
try {
try {
t.openFetch();
fail("connection opened even info/refs needs auth basic");
} catch (TransportException err) {
String status = "401 Unauthorized";
String exp = dumbAuthBasicURI + ": " + status;
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

public void testListRemote_Smart_UploadPackNeedsAuth() throws Exception {
Repository dst = createBareRepository();
Transport t = Transport.open(dst, smartAuthBasicURI);
try {
try {
t.openFetch();
fail("connection opened even though service disabled");
} catch (TransportException err) {
String status = "401 Unauthorized";
String exp = smartAuthBasicURI + ": " + status;
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}

public void testListRemote_Smart_UploadPackDisabled() throws Exception {
Repository src = remoteRepository.getRepository();
src.getConfig().setBoolean("http", null, "uploadpack", false);
src.getConfig().save();

Repository dst = createBareRepository();
Transport t = Transport.open(dst, smartAuthNoneURI);
try {
try {
t.openFetch();
fail("connection opened even though service disabled");
} catch (TransportException err) {
String exp = smartAuthNoneURI
+ ": git-upload-pack not permitted";
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}
}
}

+ 556
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/SmartClientSmartServerTest.java View File

@@ -0,0 +1,556 @@
/*
* Copyright (C) 2009-2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test;

import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_ENCODING;
import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_LENGTH;
import static org.eclipse.jgit.util.HttpSupport.HDR_CONTENT_TYPE;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.errors.TransportException;
import org.eclipse.jgit.http.server.GitServlet;
import org.eclipse.jgit.http.server.resolver.RepositoryResolver;
import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
import org.eclipse.jgit.http.test.util.AccessEvent;
import org.eclipse.jgit.http.test.util.HttpTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.junit.TestRng;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.ReflogReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryConfig;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.transport.FetchConnection;
import org.eclipse.jgit.transport.HttpTransport;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.Transport;
import org.eclipse.jgit.transport.TransportHttp;
import org.eclipse.jgit.transport.URIish;

public class SmartClientSmartServerTest extends HttpTestCase {
private static final String HDR_TRANSFER_ENCODING = "Transfer-Encoding";

private Repository remoteRepository;

private URIish remoteURI;

private URIish brokenURI;

private RevBlob A_txt;

private RevCommit A, B;

protected void setUp() throws Exception {
super.setUp();

final TestRepository src = createTestRepository();
final String srcName = src.getRepository().getDirectory().getName();

ServletContextHandler app = server.addContext("/git");
GitServlet gs = new GitServlet();
gs.setRepositoryResolver(new RepositoryResolver() {
public Repository open(HttpServletRequest req, String name)
throws RepositoryNotFoundException,
ServiceNotEnabledException {
if (!name.equals(srcName))
throw new RepositoryNotFoundException(name);

final Repository db = src.getRepository();
db.incrementOpen();
return db;
}
});
app.addServlet(new ServletHolder(gs), "/*");

ServletContextHandler broken = server.addContext("/bad");
broken.addFilter(new FilterHolder(new Filter() {
public void doFilter(ServletRequest request,
ServletResponse response, FilterChain chain)
throws IOException, ServletException {
final HttpServletResponse r = (HttpServletResponse) response;
r.setContentType("text/plain");
r.setCharacterEncoding("UTF-8");
PrintWriter w = r.getWriter();
w.print("OK");
w.close();
}

public void init(FilterConfig filterConfig) throws ServletException {
//
}

public void destroy() {
//
}
}), "/" + srcName + "/git-upload-pack", FilterMapping.DEFAULT);
broken.addServlet(new ServletHolder(gs), "/*");

server.setUp();

remoteRepository = src.getRepository();
remoteURI = toURIish(app, srcName);
brokenURI = toURIish(broken, srcName);

A_txt = src.blob("A");
A = src.commit().add("A_txt", A_txt).create();
B = src.commit().parent(A).add("A_txt", "C").add("B", "B").create();
src.update(master, B);

src.update("refs/garbage/a/very/long/ref/name/to/compress", B);
}

public void testListRemote() throws IOException {
Repository dst = createBareRepository();

assertEquals("http", remoteURI.getScheme());

Map<String, Ref> map;
Transport t = Transport.open(dst, remoteURI);
try {
// I didn't make up these public interface names, I just
// approved them for inclusion into the code base. Sorry.
// --spearce
//
assertTrue("isa TransportHttp", t instanceof TransportHttp);
assertTrue("isa HttpTransport", t instanceof HttpTransport);

FetchConnection c = t.openFetch();
try {
map = c.getRefsMap();
} finally {
c.close();
}
} finally {
t.close();
}

assertNotNull("have map of refs", map);
assertEquals(3, map.size());

assertNotNull("has " + master, map.get(master));
assertEquals(B, map.get(master).getObjectId());

assertNotNull("has " + Constants.HEAD, map.get(Constants.HEAD));
assertEquals(B, map.get(Constants.HEAD).getObjectId());

List<AccessEvent> requests = getRequests();
assertEquals(1, requests.size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(remoteURI, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-upload-pack", info.getParameter("service"));
assertEquals(200, info.getStatus());
assertEquals("application/x-git-upload-pack-advertisement", info
.getResponseHeader(HDR_CONTENT_TYPE));
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));
}

public void testInitialClone_Small() throws Exception {
Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, remoteURI);
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}

assertTrue(dst.hasObject(A_txt));
assertEquals(B, dst.getRef(master).getObjectId());
fsck(dst, B);

List<AccessEvent> requests = getRequests();
assertEquals(2, requests.size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(remoteURI, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-upload-pack", info.getParameter("service"));
assertEquals(200, info.getStatus());
assertEquals("application/x-git-upload-pack-advertisement", info
.getResponseHeader(HDR_CONTENT_TYPE));
assertEquals("gzip", info.getResponseHeader(HDR_CONTENT_ENCODING));

AccessEvent service = requests.get(1);
assertEquals("POST", service.getMethod());
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
assertEquals(0, service.getParameters().size());
assertNotNull("has content-length", service
.getRequestHeader(HDR_CONTENT_LENGTH));
assertNull("not chunked", service
.getRequestHeader(HDR_TRANSFER_ENCODING));
assertNull("no compression (too small)", service
.getRequestHeader(HDR_CONTENT_ENCODING));

assertEquals(200, service.getStatus());
assertEquals("application/x-git-upload-pack-result", service
.getResponseHeader(HDR_CONTENT_TYPE));
assertNull("no compression (never compressed)", service
.getResponseHeader(HDR_CONTENT_ENCODING));
}

public void testFetchUpdateExisting() throws Exception {
// Bootstrap by doing the clone.
//
TestRepository dst = createTestRepository();
Transport t = Transport.open(dst.getRepository(), remoteURI);
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}
assertEquals(B, dst.getRepository().getRef(master).getObjectId());
List<AccessEvent> cloneRequests = getRequests();

// Force enough into the local client that enumeration will
// need multiple packets, but not too many to overflow and
// not pick up the ACK_COMMON message.
//
TestRepository.BranchBuilder b = dst.branch(master);
for (int i = 0; i < 32 - 1; i++)
b.commit().tick(3600 /* 1 hour */).message("c" + i).create();

// Create a new commit on the remote.
//
b = new TestRepository(remoteRepository).branch(master);
RevCommit Z = b.commit().message("Z").create();

// Now incrementally update.
//
t = Transport.open(dst.getRepository(), remoteURI);
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
} finally {
t.close();
}
assertEquals(Z, dst.getRepository().getRef(master).getObjectId());

List<AccessEvent> requests = getRequests();
requests.removeAll(cloneRequests);
assertEquals(3, requests.size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(remoteURI, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-upload-pack", info.getParameter("service"));
assertEquals(200, info.getStatus());
assertEquals("application/x-git-upload-pack-advertisement", info
.getResponseHeader(HDR_CONTENT_TYPE));

// We should have needed two requests to perform the fetch
// due to the high number of local unknown commits.
//
AccessEvent service = requests.get(1);
assertEquals("POST", service.getMethod());
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
assertEquals(0, service.getParameters().size());
assertNotNull("has content-length", service
.getRequestHeader(HDR_CONTENT_LENGTH));
assertNull("not chunked", service
.getRequestHeader(HDR_TRANSFER_ENCODING));

assertEquals(200, service.getStatus());
assertEquals("application/x-git-upload-pack-result", service
.getResponseHeader(HDR_CONTENT_TYPE));

service = requests.get(2);
assertEquals("POST", service.getMethod());
assertEquals(join(remoteURI, "git-upload-pack"), service.getPath());
assertEquals(0, service.getParameters().size());
assertNotNull("has content-length", service
.getRequestHeader(HDR_CONTENT_LENGTH));
assertNull("not chunked", service
.getRequestHeader(HDR_TRANSFER_ENCODING));

assertEquals(200, service.getStatus());
assertEquals("application/x-git-upload-pack-result", service
.getResponseHeader(HDR_CONTENT_TYPE));
}

public void testInitialClone_BrokenServer() throws Exception {
Repository dst = createBareRepository();
assertFalse(dst.hasObject(A_txt));

Transport t = Transport.open(dst, brokenURI);
try {
try {
t.fetch(NullProgressMonitor.INSTANCE, mirror(master));
fail("fetch completed despite upload-pack being broken");
} catch (TransportException err) {
String exp = brokenURI + ": expected"
+ " Content-Type application/x-git-upload-pack-result;"
+ " received Content-Type text/plain;charset=UTF-8";
assertEquals(exp, err.getMessage());
}
} finally {
t.close();
}

List<AccessEvent> requests = getRequests();
assertEquals(2, requests.size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(brokenURI, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-upload-pack", info.getParameter("service"));
assertEquals(200, info.getStatus());
assertEquals("application/x-git-upload-pack-advertisement", info
.getResponseHeader(HDR_CONTENT_TYPE));

AccessEvent service = requests.get(1);
assertEquals("POST", service.getMethod());
assertEquals(join(brokenURI, "git-upload-pack"), service.getPath());
assertEquals(0, service.getParameters().size());
assertEquals(200, service.getStatus());
assertEquals("text/plain;charset=UTF-8", service
.getResponseHeader(HDR_CONTENT_TYPE));
}

public void testPush_NotAuthorized() throws Exception {
final TestRepository src = createTestRepository();
final RevBlob Q_txt = src.blob("new text");
final RevCommit Q = src.commit().add("Q", Q_txt).create();
final Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch";
Transport t;

// push anonymous shouldn't be allowed.
//
t = Transport.open(db, remoteURI);
try {
final String srcExpr = Q.name();
final boolean forceUpdate = false;
final String localName = null;
final ObjectId oldId = null;

RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
srcExpr, dstName, forceUpdate, localName, oldId);
try {
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
fail("anonymous push incorrectly accepted without error");
} catch (TransportException e) {
final String status = "401 Unauthorized";
final String exp = remoteURI.toString() + ": " + status;
assertEquals(exp, e.getMessage());
}
} finally {
t.close();
}

List<AccessEvent> requests = getRequests();
assertEquals(1, requests.size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(remoteURI, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-receive-pack", info.getParameter("service"));
assertEquals(401, info.getStatus());
}

public void testPush_CreateBranch() throws Exception {
final TestRepository src = createTestRepository();
final RevBlob Q_txt = src.blob("new text");
final RevCommit Q = src.commit().add("Q", Q_txt).create();
final Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch";
Transport t;

enableReceivePack();

t = Transport.open(db, remoteURI);
try {
final String srcExpr = Q.name();
final boolean forceUpdate = false;
final String localName = null;
final ObjectId oldId = null;

RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
srcExpr, dstName, forceUpdate, localName, oldId);
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
} finally {
t.close();
}

assertTrue(remoteRepository.hasObject(Q_txt));
assertNotNull("has " + dstName, remoteRepository.getRef(dstName));
assertEquals(Q, remoteRepository.getRef(dstName).getObjectId());
fsck(remoteRepository, Q);

final ReflogReader log = remoteRepository.getReflogReader(dstName);
assertNotNull("has log for " + dstName);

final ReflogReader.Entry last = log.getLastEntry();
assertNotNull("has last entry", last);
assertEquals(ObjectId.zeroId(), last.getOldId());
assertEquals(Q, last.getNewId());
assertEquals("anonymous", last.getWho().getName());

// Assumption: The host name we use to contact the server should
// be the server's own host name, because it should be the loopback
// network interface.
//
final String clientHost = remoteURI.getHost();
assertEquals("anonymous@" + clientHost, last.getWho().getEmailAddress());
assertEquals("push: created", last.getComment());

List<AccessEvent> requests = getRequests();
assertEquals(2, requests.size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(remoteURI, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-receive-pack", info.getParameter("service"));
assertEquals(200, info.getStatus());
assertEquals("application/x-git-receive-pack-advertisement", info
.getResponseHeader(HDR_CONTENT_TYPE));

AccessEvent service = requests.get(1);
assertEquals("POST", service.getMethod());
assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
assertEquals(0, service.getParameters().size());
assertNotNull("has content-length", service
.getRequestHeader(HDR_CONTENT_LENGTH));
assertNull("not chunked", service
.getRequestHeader(HDR_TRANSFER_ENCODING));

assertEquals(200, service.getStatus());
assertEquals("application/x-git-receive-pack-result", service
.getResponseHeader(HDR_CONTENT_TYPE));
}

public void testPush_ChunkedEncoding() throws Exception {
final TestRepository src = createTestRepository();
final RevBlob Q_bin = src.blob(new TestRng("Q").nextBytes(128 * 1024));
final RevCommit Q = src.commit().add("Q", Q_bin).create();
final Repository db = src.getRepository();
final String dstName = Constants.R_HEADS + "new.branch";
Transport t;

enableReceivePack();

db.getConfig().setInt("core", null, "compression", 0);
db.getConfig().setInt("http", null, "postbuffer", 8 * 1024);
db.getConfig().save();

t = Transport.open(db, remoteURI);
try {
final String srcExpr = Q.name();
final boolean forceUpdate = false;
final String localName = null;
final ObjectId oldId = null;

RemoteRefUpdate u = new RemoteRefUpdate(src.getRepository(),
srcExpr, dstName, forceUpdate, localName, oldId);
t.push(NullProgressMonitor.INSTANCE, Collections.singleton(u));
} finally {
t.close();
}

assertTrue(remoteRepository.hasObject(Q_bin));
assertNotNull("has " + dstName, remoteRepository.getRef(dstName));
assertEquals(Q, remoteRepository.getRef(dstName).getObjectId());
fsck(remoteRepository, Q);

List<AccessEvent> requests = getRequests();
assertEquals(2, requests.size());

AccessEvent info = requests.get(0);
assertEquals("GET", info.getMethod());
assertEquals(join(remoteURI, "info/refs"), info.getPath());
assertEquals(1, info.getParameters().size());
assertEquals("git-receive-pack", info.getParameter("service"));
assertEquals(200, info.getStatus());
assertEquals("application/x-git-receive-pack-advertisement", info
.getResponseHeader(HDR_CONTENT_TYPE));

AccessEvent service = requests.get(1);
assertEquals("POST", service.getMethod());
assertEquals(join(remoteURI, "git-receive-pack"), service.getPath());
assertEquals(0, service.getParameters().size());
assertNull("no content-length", service
.getRequestHeader(HDR_CONTENT_LENGTH));
assertEquals("chunked", service.getRequestHeader(HDR_TRANSFER_ENCODING));

assertEquals(200, service.getStatus());
assertEquals("application/x-git-receive-pack-result", service
.getResponseHeader(HDR_CONTENT_TYPE));
}

private void enableReceivePack() throws IOException {
final RepositoryConfig cfg = remoteRepository.getConfig();
cfg.setBoolean("http", null, "receivepack", true);
cfg.save();
}
}

+ 181
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/AccessEvent.java View File

@@ -0,0 +1,181 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test.util;

import java.util.Collections;
import java.util.Enumeration;
import java.util.Map;
import java.util.TreeMap;

import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.Response;

/** A single request made through {@link AppServer}. */
public class AccessEvent {
private final String method;

private final String uri;

private final Map<String, String> requestHeaders;

private final Map<String, String[]> parameters;

private final int status;

private final Map<String, String> responseHeaders;

AccessEvent(final Request req, final Response rsp) {
method = req.getMethod();
uri = req.getRequestURI();
requestHeaders = cloneHeaders(req);
parameters = clone(req.getParameterMap());

status = rsp.getStatus();
responseHeaders = cloneHeaders(rsp);
}

private static Map<String, String> cloneHeaders(final Request req) {
Map<String, String> r = new TreeMap<String, String>();
Enumeration hn = req.getHeaderNames();
while (hn.hasMoreElements()) {
String key = (String) hn.nextElement();
if (!r.containsKey(key)) {
r.put(key, req.getHeader(key));
}
}
return Collections.unmodifiableMap(r);
}

private static Map<String, String> cloneHeaders(final Response rsp) {
Map<String, String> r = new TreeMap<String, String>();
Enumeration<String> hn = rsp.getHttpFields().getFieldNames();
while (hn.hasMoreElements()) {
String key = hn.nextElement();
if (!r.containsKey(key)) {
Enumeration<String> v = rsp.getHttpFields().getValues(key);
r.put(key, v.nextElement());
}
}
return Collections.unmodifiableMap(r);
}

@SuppressWarnings("unchecked")
private static Map<String, String[]> clone(Map parameterMap) {
return new TreeMap<String, String[]>(parameterMap);
}

/** @return {@code "GET"} or {@code "POST"} */
public String getMethod() {
return method;
}

/** @return path of the file on the server, e.g. {@code /git/HEAD}. */
public String getPath() {
return uri;
}

/**
* @param name
* name of the request header to read.
* @return first value of the request header; null if not sent.
*/
public String getRequestHeader(String name) {
return requestHeaders.get(name);
}

/**
* @param name
* name of the request parameter to read.
* @return first value of the request parameter; null if not sent.
*/
public String getParameter(String name) {
String[] r = parameters.get(name);
return r != null && 1 <= r.length ? r[0] : null;
}

/** @return all parameters in the request. */
public Map<String, String[]> getParameters() {
return parameters;
}

/** @return HTTP status code of the response, e.g. 200, 403, 500. */
public int getStatus() {
return status;
}

/**
* @param name
* name of the response header to read.
* @return first value of the response header; null if not sent.
*/
public String getResponseHeader(String name) {
return responseHeaders.get(name);
}

public String toString() {
StringBuilder b = new StringBuilder();
b.append(method);
b.append(' ');
b.append(uri);
if (!parameters.isEmpty()) {
b.append('?');
boolean first = true;
for (Map.Entry<String, String[]> e : parameters.entrySet()) {
for (String val : e.getValue()) {
if (!first) {
b.append('&');
}
first = false;

b.append(e.getKey());
b.append('=');
b.append(val);
}
}
}
b.append(' ');
b.append(status);
return b.toString();
}
}

+ 295
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/AppServer.java View File

@@ -0,0 +1,295 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test.util;

import java.io.IOException;
import java.net.InetAddress;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;

import junit.framework.Assert;

import org.eclipse.jetty.http.security.Constraint;
import org.eclipse.jetty.http.security.Password;
import org.eclipse.jetty.security.Authenticator;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.ConstraintSecurityHandler;
import org.eclipse.jetty.security.MappedLoginService;
import org.eclipse.jetty.security.authentication.BasicAuthenticator;
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.server.handler.ContextHandlerCollection;
import org.eclipse.jetty.server.handler.RequestLogHandler;
import org.eclipse.jetty.server.nio.SelectChannelConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.util.thread.QueuedThreadPool;
import org.eclipse.jgit.transport.URIish;

/**
* Tiny web application server for unit testing.
* <p>
* Tests should start the server in their {@code setUp()} method and stop the
* server in their {@code tearDown()} method. Only while started the server's
* URL and/or port number can be obtained.
*/
public class AppServer {
/** Realm name for the secure access areas. */
public static final String realm = "Secure Area";

/** Username for secured access areas. */
public static final String username = "agitter";

/** Password for {@link #username} in secured access areas. */
public static final String password = "letmein";

static {
// Install a logger that throws warning messages.
//
final String prop = "org.eclipse.jetty.util.log.class";
System.setProperty(prop, RecordingLogger.class.getName());
}

private final Server server;

private final Connector connector;

private final ContextHandlerCollection contexts;

private final TestRequestLog log;

public AppServer() {
connector = new SelectChannelConnector();
connector.setPort(0);
try {
final InetAddress me = InetAddress.getByName("localhost");
connector.setHost(me.getHostAddress());
} catch (UnknownHostException e) {
throw new RuntimeException("Cannot find localhost", e);
}

// We need a handful of threads in the thread pool, otherwise
// our tests will deadlock when they can't open enough requests.
// In theory we only need 1 concurrent connection at a time, but
// I suspect the JRE isn't doing request pipelining on existing
// connections like we want it to.
//
final QueuedThreadPool pool = new QueuedThreadPool();
pool.setMinThreads(1);
pool.setMaxThreads(4);
pool.setMaxQueued(8);

contexts = new ContextHandlerCollection();

log = new TestRequestLog();

final RequestLogHandler logHandler = new RequestLogHandler();
logHandler.setHandler(contexts);
logHandler.setRequestLog(log);

server = new Server();
server.setConnectors(new Connector[] { connector });
server.setThreadPool(pool);
server.setHandler(logHandler);

server.setStopAtShutdown(false);
server.setGracefulShutdown(0);
}

/**
* Create a new servlet context within the server.
* <p>
* This method should be invoked before the server is started, once for each
* context the caller wants to register.
*
* @param path
* path of the context; use "/" for the root context if binding
* to the root is desired.
* @return the context to add servlets into.
*/
public ServletContextHandler addContext(String path) {
assertNotYetSetUp();
if ("".equals(path))
path = "/";

ServletContextHandler ctx = new ServletContextHandler();
ctx.setContextPath(path);
contexts.addHandler(ctx);

return ctx;
}

public ServletContextHandler authBasic(ServletContextHandler ctx) {
assertNotYetSetUp();
auth(ctx, new BasicAuthenticator());
return ctx;
}

private void auth(ServletContextHandler ctx, Authenticator authType) {
final String role = "can-access";

MappedLoginService users = new MappedLoginService() {
@Override
protected UserIdentity loadUser(String who) {
return null;
}

@Override
protected void loadUsers() throws IOException {
putUser(username, new Password(password), new String[] { role });
}
};

ConstraintMapping cm = new ConstraintMapping();
cm.setConstraint(new Constraint());
cm.getConstraint().setAuthenticate(true);
cm.getConstraint().setDataConstraint(Constraint.DC_NONE);
cm.getConstraint().setRoles(new String[] { role });
cm.setPathSpec("/*");

ConstraintSecurityHandler sec = new ConstraintSecurityHandler();
sec.setStrict(false);
sec.setRealmName(realm);
sec.setAuthenticator(authType);
sec.setLoginService(users);
sec.setConstraintMappings(new ConstraintMapping[] { cm });
sec.setHandler(ctx);

contexts.removeHandler(ctx);
contexts.addHandler(sec);
}

/**
* Start the server on a random local port.
*
* @throws Exception
* the server cannot be started, testing is not possible.
*/
public void setUp() throws Exception {
RecordingLogger.clear();
log.clear();
server.start();
}

/**
* Shutdown the server.
*
* @throws Exception
* the server refuses to halt, or wasn't running.
*/
public void tearDown() throws Exception {
RecordingLogger.clear();
log.clear();
server.stop();
}

/**
* Get the URI to reference this server.
* <p>
* The returned URI includes the proper host name and port number, but does
* not contain a path.
*
* @return URI to reference this server's root context.
*/
public URI getURI() {
assertAlreadySetUp();
String host = connector.getHost();
if (host.contains(":") && !host.startsWith("["))
host = "[" + host + "]";
final String uri = "http://" + host + ":" + getPort();
try {
return new URI(uri);
} catch (URISyntaxException e) {
throw new RuntimeException("Unexpected URI error on " + uri, e);
}
}

/** @return the local port number the server is listening on. */
public int getPort() {
assertAlreadySetUp();
return ((SelectChannelConnector) connector).getLocalPort();
}

/** @return all requests since the server was started. */
public List<AccessEvent> getRequests() {
return new ArrayList<AccessEvent>(log.getEvents());
}

/**
* @param base
* base URI used to access the server.
* @param path
* the path to locate requests for, relative to {@code base}.
* @return all requests which match the given path.
*/
public List<AccessEvent> getRequests(URIish base, String path) {
return getRequests(HttpTestCase.join(base, path));
}

/**
* @param path
* the path to locate requests for.
* @return all requests which match the given path.
*/
public List<AccessEvent> getRequests(String path) {
ArrayList<AccessEvent> r = new ArrayList<AccessEvent>();
for (AccessEvent event : log.getEvents()) {
if (event.getPath().equals(path)) {
r.add(event);
}
}
return r;
}

private void assertNotYetSetUp() {
Assert.assertFalse("server is not running", server.isRunning());
}

private void assertAlreadySetUp() {
Assert.assertTrue("server is running", server.isRunning());
}
}

+ 161
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/HttpTestCase.java View File

@@ -0,0 +1,161 @@
/*
* Copyright (C) 2009-2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test.util;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
import org.eclipse.jgit.junit.TestRepository;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
import org.eclipse.jgit.transport.RefSpec;
import org.eclipse.jgit.transport.RemoteRefUpdate;
import org.eclipse.jgit.transport.URIish;

/** Base class for HTTP related transport testing. */
public abstract class HttpTestCase extends LocalDiskRepositoryTestCase {
protected static final String master = Constants.R_HEADS + Constants.MASTER;

/** In-memory application server; subclass must start. */
protected AppServer server;

protected void setUp() throws Exception {
super.setUp();
server = new AppServer();
}

protected void tearDown() throws Exception {
server.tearDown();
super.tearDown();
}

protected TestRepository createTestRepository() throws Exception {
return new TestRepository(createBareRepository());
}

protected URIish toURIish(String path) throws URISyntaxException {
URI u = server.getURI().resolve(path);
return new URIish(u.toString());
}

protected URIish toURIish(ServletContextHandler app, String name)
throws URISyntaxException {
String p = app.getContextPath();
if (!p.endsWith("/") && !name.startsWith("/"))
p += "/";
p += name;
return toURIish(p);
}

protected List<AccessEvent> getRequests() {
return server.getRequests();
}

protected List<AccessEvent> getRequests(URIish base, String path) {
return server.getRequests(base, path);
}

protected List<AccessEvent> getRequests(String path) {
return server.getRequests(path);
}

protected static void fsck(Repository db, RevObject... tips)
throws Exception {
new TestRepository(db).fsck(tips);
}

protected static Set<RefSpec> mirror(String... refs) {
HashSet<RefSpec> r = new HashSet<RefSpec>();
for (String name : refs) {
RefSpec rs = new RefSpec(name);
rs = rs.setDestination(name);
rs = rs.setForceUpdate(true);
r.add(rs);
}
return r;
}

protected static Collection<RemoteRefUpdate> push(TestRepository from,
RevCommit q) throws IOException {
final Repository db = from.getRepository();
final String srcExpr = q.name();
final String dstName = master;
final boolean forceUpdate = true;
final String localName = null;
final ObjectId oldId = null;

RemoteRefUpdate u = new RemoteRefUpdate(db, srcExpr, dstName,
forceUpdate, localName, oldId);
return Collections.singleton(u);
}

public static String loose(URIish base, AnyObjectId id) {
final String objectName = id.name();
final String d = objectName.substring(0, 2);
final String f = objectName.substring(2);
return join(base, "objects/" + d + "/" + f);
}

public static String join(URIish base, String path) {
if (path.startsWith("/"))
fail("Cannot join absolute path " + path + " to URIish " + base);

String dir = base.getPath();
if (!dir.endsWith("/"))
dir += "/";
return dir + path;
}
}

+ 85
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/MockServletConfig.java View File

@@ -0,0 +1,85 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test.util;

import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;

public class MockServletConfig implements ServletConfig {
private final Map<String, String> parameters = new HashMap<String, String>();

public void setInitParameter(String name, String value) {
parameters.put(name, value);
}

public String getInitParameter(String name) {
return parameters.get(name);
}

public Enumeration getInitParameterNames() {
final Iterator<String> i = parameters.keySet().iterator();
return new Enumeration<String>() {
public boolean hasMoreElements() {
return i.hasNext();
}

public String nextElement() {
return i.next();
}
};
}

public String getServletName() {
return "MOCK_SERVLET";
}

public ServletContext getServletContext() {
return null;
}
}

+ 146
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/RecordingLogger.java View File

@@ -0,0 +1,146 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test.util;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.eclipse.jetty.util.log.Logger;

/** Logs warnings into an array for later inspection. */
public class RecordingLogger implements Logger {
private static List<Warning> warnings = new ArrayList<Warning>();

/** Clear the warnings, automatically done by {@link AppServer#setUp()} */
public static void clear() {
synchronized (warnings) {
warnings.clear();
}
}

/** @return the warnings (if any) from the last execution */
public static List<Warning> getWarnings() {
synchronized (warnings) {
ArrayList<Warning> copy = new ArrayList<Warning>(warnings);
return Collections.unmodifiableList(copy);
}
}

@SuppressWarnings("serial")
public static class Warning extends Exception {
public Warning(String msg) {
super(msg);
}

public Warning(String msg, Throwable cause) {
super(msg, cause);
}
}

private final String name;

public RecordingLogger() {
this("");
}

public RecordingLogger(final String name) {
this.name = name;
}

public Logger getLogger(@SuppressWarnings("hiding") String name) {
return new RecordingLogger(name);
}

public String getName() {
return name;
}

public void warn(String msg, Object arg0, Object arg1) {
synchronized (warnings) {
warnings.add(new Warning(MessageFormat.format(msg, arg0, arg1)));
}
}

public void warn(String msg, Throwable th) {
synchronized (warnings) {
warnings.add(new Warning(msg, th));
}
}

public void warn(String msg) {
synchronized (warnings) {
warnings.add(new Warning(msg));
}
}

public void debug(String msg, Object arg0, Object arg1) {
// Ignore (not relevant to test failures)
}

public void debug(String msg, Throwable th) {
// Ignore (not relevant to test failures)
}

public void debug(String msg) {
// Ignore (not relevant to test failures)
}

public void info(String msg, Object arg0, Object arg1) {
// Ignore (not relevant to test failures)
}

public void info(String msg) {
// Ignore (not relevant to test failures)
}

public boolean isDebugEnabled() {
return false;
}

public void setDebugEnabled(boolean enabled) {
// Ignore (not relevant to test failures)
}
}

+ 71
- 0
org.eclipse.jgit.http.test/tst/org/eclipse/jgit/http/test/util/TestRequestLog.java View File

@@ -0,0 +1,71 @@
/*
* Copyright (C) 2010, Google Inc.
* and other copyright owners as documented in the project's IP log.
*
* This program and the accompanying materials are made available
* under the terms of the Eclipse Distribution License v1.0 which
* accompanies this distribution, is reproduced below, and is
* available at http://www.eclipse.org/org/documents/edl-v10.php
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
* conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* - Neither the name of the Eclipse Foundation, Inc. nor the
* names of its contributors may be used to endorse or promote
* products derived from this software without specific prior
* written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
* CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

package org.eclipse.jgit.http.test.util;

import java.util.ArrayList;
import java.util.List;

import org.eclipse.jetty.server.Request;
import org.eclipse.jetty.server.RequestLog;
import org.eclipse.jetty.server.Response;
import org.eclipse.jetty.util.component.AbstractLifeCycle;

/** Logs request made through {@link AppServer}. */
class TestRequestLog extends AbstractLifeCycle implements RequestLog {
private final List<AccessEvent> events = new ArrayList<AccessEvent>();

/** Reset the log back to its original empty state. */
synchronized void clear() {
events.clear();
}

/** @return all of the events made since the last clear. */
synchronized List<AccessEvent> getEvents() {
return events;
}

public synchronized void log(Request request, Response response) {
events.add(new AccessEvent(request, response));
}
}

+ 11
- 1
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java View File

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2009, Google Inc.
* Copyright (C) 2009-2010, Google Inc.
* Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
* Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>
* and other copyright owners as documented in the project's IP log.
@@ -57,8 +57,10 @@ import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import junit.framework.Assert;
import junit.framework.TestCase;

import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileBasedConfig;
import org.eclipse.jgit.lib.PersonIdent;
@@ -404,6 +406,14 @@ public abstract class LocalDiskRepositoryTestCase extends TestCase {
return new String(body, 0, body.length, "UTF-8");
}

protected static void assertEquals(AnyObjectId exp, AnyObjectId act) {
if (exp != null)
exp = exp.copy();
if (act != null)
act = act.copy();
Assert.assertEquals(exp, act);
}

private static String[] toEnvArray(final Map<String, String> env) {
final String[] envp = new String[env.size()];
int i = 0;

+ 150
- 12
org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java View File

@@ -44,11 +44,15 @@
package org.eclipse.jgit.junit;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import junit.framework.Assert;
import junit.framework.AssertionFailedError;
@@ -60,21 +64,30 @@ import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.dircache.DirCacheEditor.DeletePath;
import org.eclipse.jgit.dircache.DirCacheEditor.DeleteTree;
import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
import org.eclipse.jgit.errors.IncorrectObjectTypeException;
import org.eclipse.jgit.errors.MissingObjectException;
import org.eclipse.jgit.errors.ObjectWritingException;
import org.eclipse.jgit.lib.AnyObjectId;
import org.eclipse.jgit.lib.Commit;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.FileMode;
import org.eclipse.jgit.lib.LockFile;
import org.eclipse.jgit.lib.NullProgressMonitor;
import org.eclipse.jgit.lib.ObjectChecker;
import org.eclipse.jgit.lib.ObjectDatabase;
import org.eclipse.jgit.lib.ObjectDirectory;
import org.eclipse.jgit.lib.ObjectId;
import org.eclipse.jgit.lib.ObjectWriter;
import org.eclipse.jgit.lib.PackFile;
import org.eclipse.jgit.lib.PackWriter;
import org.eclipse.jgit.lib.PersonIdent;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.RefUpdate;
import org.eclipse.jgit.lib.RefWriter;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.Tag;
import org.eclipse.jgit.lib.PackIndex.MutableEntry;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevBlob;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevObject;
@@ -428,26 +441,25 @@ public class TestRepository {
* @throws Exception
*/
public void updateServerInfo() throws Exception {
if (db.getObjectDatabase() instanceof ObjectDirectory) {
final ObjectDatabase odb = db.getObjectDatabase();
if (odb instanceof ObjectDirectory) {
RefWriter rw = new RefWriter(db.getAllRefs().values()) {
@Override
protected void writeFile(final String name, final byte[] bin)
throws IOException {
final File p = new File(db.getDirectory(), name);
final LockFile lck = new LockFile(p);
if (!lck.lock())
throw new ObjectWritingException("Can't write " + p);
try {
lck.write(bin);
} catch (IOException ioe) {
throw new ObjectWritingException("Can't write " + p);
}
if (!lck.commit())
throw new ObjectWritingException("Can't write " + p);
TestRepository.this.writeFile(name, bin);
}
};
rw.writePackedRefs();
rw.writeInfoRefs();

final StringBuilder w = new StringBuilder();
for (PackFile p : ((ObjectDirectory) odb).getPacks()) {
w.append("P ");
w.append(p.getPackFile().getName());
w.append('\n');
}
writeFile("objects/info/packs", Constants.encodeASCII(w.toString()));
}
}

@@ -484,6 +496,132 @@ public class TestRepository {
return new BranchBuilder(ref);
}

/**
* Run consistency checks against the object database.
* <p>
* This method completes silently if the checks pass. A temporary revision
* pool is constructed during the checking.
*
* @param tips
* the tips to start checking from; if not supplied the refs of
* the repository are used instead.
* @throws MissingObjectException
* @throws IncorrectObjectTypeException
* @throws IOException
*/
public void fsck(RevObject... tips) throws MissingObjectException,
IncorrectObjectTypeException, IOException {
ObjectWalk ow = new ObjectWalk(db);
if (tips.length != 0) {
for (RevObject o : tips)
ow.markStart(ow.parseAny(o));
} else {
for (Ref r : db.getAllRefs().values())
ow.markStart(ow.parseAny(r.getObjectId()));
}

ObjectChecker oc = new ObjectChecker();
for (;;) {
final RevCommit o = ow.next();
if (o == null)
break;

final byte[] bin = db.openObject(o).getCachedBytes();
oc.checkCommit(bin);
assertHash(o, bin);
}

for (;;) {
final RevObject o = ow.nextObject();
if (o == null)
break;

final byte[] bin = db.openObject(o).getCachedBytes();
oc.check(o.getType(), bin);
assertHash(o, bin);
}
}

private static void assertHash(RevObject id, byte[] bin) {
MessageDigest md = Constants.newMessageDigest();
md.update(Constants.encodedTypeString(id.getType()));
md.update((byte) ' ');
md.update(Constants.encodeASCII(bin.length));
md.update((byte) 0);
md.update(bin);
Assert.assertEquals(id.copy(), ObjectId.fromRaw(md.digest()));
}

/**
* Pack all reachable objects in the repository into a single pack file.
* <p>
* All loose objects are automatically pruned. Existing packs however are
* not removed.
*
* @throws Exception
*/
public void packAndPrune() throws Exception {
final ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase();
final PackWriter pw = new PackWriter(db, NullProgressMonitor.INSTANCE);

Set<ObjectId> all = new HashSet<ObjectId>();
for (Ref r : db.getAllRefs().values())
all.add(r.getObjectId());
pw.preparePack(all, Collections.<ObjectId> emptySet());

final ObjectId name = pw.computeName();
FileOutputStream out;

final File pack = nameFor(odb, name, ".pack");
out = new FileOutputStream(pack);
try {
pw.writePack(out);
} finally {
out.close();
}
pack.setReadOnly();

final File idx = nameFor(odb, name, ".idx");
out = new FileOutputStream(idx);
try {
pw.writeIndex(out);
} finally {
out.close();
}
idx.setReadOnly();

odb.openPack(pack, idx);
updateServerInfo();
prunePacked(odb);
}

private void prunePacked(ObjectDirectory odb) {
for (PackFile p : odb.getPacks()) {
for (MutableEntry e : p)
odb.fileFor(e.toObjectId()).delete();
}
}

private static File nameFor(ObjectDirectory odb, ObjectId name, String t) {
File packdir = new File(odb.getDirectory(), "pack");
return new File(packdir, "pack-" + name.name() + t);
}

private void writeFile(final String name, final byte[] bin)
throws IOException, ObjectWritingException {
final File p = new File(db.getDirectory(), name);
final LockFile lck = new LockFile(p);
if (!lck.lock())
throw new ObjectWritingException("Can't write " + p);
try {
lck.write(bin);
} catch (IOException ioe) {
throw new ObjectWritingException("Can't write " + p);
}
if (!lck.commit())
throw new ObjectWritingException("Can't write " + p);
}

/** Helper to build a branch with one or more commits */
public class BranchBuilder {
private final String ref;

+ 31
- 5
org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportHttp.java View File

@@ -155,6 +155,8 @@ public class TransportHttp extends HttpTransport implements WalkTransport,

private final ProxySelector proxySelector;

private boolean useSmartHttp = true;

TransportHttp(final Repository local, final URIish uri)
throws NotSupportedException {
super(local, uri);
@@ -171,6 +173,20 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
proxySelector = ProxySelector.getDefault();
}

/**
* Toggle whether or not smart HTTP transport should be used.
* <p>
* This flag exists primarily to support backwards compatibility testing
* within a testing framework, there is no need to modify it in most
* applications.
*
* @param on
* if {@code true} (default), smart HTTP is enabled.
*/
public void setUseSmartHttp(final boolean on) {
useSmartHttp = on;
}

@Override
public FetchConnection openFetch() throws TransportException,
NotSupportedException {
@@ -271,6 +287,10 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
readSmartHeaders(in, service);
return new SmartHttpPushConnection(in);

} else if (!useSmartHttp) {
final String msg = "smart HTTP push disabled";
throw new NotSupportedException(msg);

} else {
final String msg = "remote does not support smart HTTP push";
throw new NotSupportedException(msg);
@@ -303,9 +323,11 @@ public class TransportHttp extends HttpTransport implements WalkTransport,
b.append('/');
b.append(Constants.INFO_REFS);

b.append(b.indexOf("?") < 0 ? '?' : '&');
b.append("service=");
b.append(service);
if (useSmartHttp) {
b.append(b.indexOf("?") < 0 ? '?' : '&');
b.append("service=");
b.append(service);
}

u = new URL(b.toString());
} catch (MalformedURLException e) {
@@ -314,8 +336,12 @@ public class TransportHttp extends HttpTransport implements WalkTransport,

try {
final HttpURLConnection conn = httpOpen(u);
String expType = "application/x-" + service + "-advertisement";
conn.setRequestProperty(HDR_ACCEPT, expType + ", */*");
if (useSmartHttp) {
String expType = "application/x-" + service + "-advertisement";
conn.setRequestProperty(HDR_ACCEPT, expType + ", */*");
} else {
conn.setRequestProperty(HDR_ACCEPT, "*/*");
}
final int status = HttpSupport.response(conn);
switch (status) {
case HttpURLConnection.HTTP_OK:

+ 10
- 0
pom.xml View File

@@ -138,6 +138,8 @@

<servlet-api-CQ>CQ 3565</servlet-api-CQ>
<servlet-api-version>2.5</servlet-api-version>

<jetty-version>7.0.1.v20091125</jetty-version>
</properties>

<build>
@@ -265,6 +267,12 @@
<artifactId>servlet-api</artifactId>
<version>${servlet-api-version}</version>
</dependency>

<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty-version}</version>
</dependency>
</dependencies>
</dependencyManagement>

@@ -298,6 +306,8 @@
<module>org.eclipse.jgit.http.server</module>
<module>org.eclipse.jgit.pgm</module>
<module>org.eclipse.jgit.junit</module>

<module>org.eclipse.jgit.test</module>
<module>org.eclipse.jgit.http.test</module>
</modules>
</project>

Loading…
Cancel
Save