151e2646dSJens Baumgart /* 2*5c5f7c6bSMatthias Sohn * Copyright (C) 2009-2017, Google Inc. and others 351e2646dSJens Baumgart * 4*5c5f7c6bSMatthias Sohn * This program and the accompanying materials are made available under the 5*5c5f7c6bSMatthias Sohn * terms of the Eclipse Distribution License v. 1.0 which is available at 6*5c5f7c6bSMatthias Sohn * https://www.eclipse.org/org/documents/edl-v10.php. 751e2646dSJens Baumgart * 8*5c5f7c6bSMatthias Sohn * SPDX-License-Identifier: BSD-3-Clause 951e2646dSJens Baumgart */ 1051e2646dSJens Baumgart 1151e2646dSJens Baumgart package org.eclipse.jgit.junit.http; 1251e2646dSJens Baumgart 13d9e07a57SRobin Rosenberg import static org.junit.Assert.fail; 14d9e07a57SRobin Rosenberg 1551e2646dSJens Baumgart import java.io.IOException; 1651e2646dSJens Baumgart import java.net.URI; 1751e2646dSJens Baumgart import java.net.URISyntaxException; 1851e2646dSJens Baumgart import java.util.Collection; 1951e2646dSJens Baumgart import java.util.Collections; 2051e2646dSJens Baumgart import java.util.HashSet; 2151e2646dSJens Baumgart import java.util.List; 2251e2646dSJens Baumgart import java.util.Set; 2351e2646dSJens Baumgart 2451e2646dSJens Baumgart import org.eclipse.jetty.servlet.ServletContextHandler; 2551e2646dSJens Baumgart import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase; 2651e2646dSJens Baumgart import org.eclipse.jgit.junit.TestRepository; 2751e2646dSJens Baumgart import org.eclipse.jgit.lib.AnyObjectId; 2851e2646dSJens Baumgart import org.eclipse.jgit.lib.Constants; 2951e2646dSJens Baumgart import org.eclipse.jgit.lib.ObjectId; 3051e2646dSJens Baumgart import org.eclipse.jgit.lib.Repository; 3151e2646dSJens Baumgart import org.eclipse.jgit.revwalk.RevCommit; 3251e2646dSJens Baumgart import org.eclipse.jgit.revwalk.RevObject; 3351e2646dSJens Baumgart import org.eclipse.jgit.transport.RefSpec; 3451e2646dSJens Baumgart import org.eclipse.jgit.transport.RemoteRefUpdate; 3551e2646dSJens Baumgart import org.eclipse.jgit.transport.URIish; 3651e2646dSJens Baumgart 370b131b73SMatthias Sohn /** 380b131b73SMatthias Sohn * Base class for HTTP related transport testing. 390b131b73SMatthias Sohn */ 4051e2646dSJens Baumgart public abstract class HttpTestCase extends LocalDiskRepositoryTestCase { 410b131b73SMatthias Sohn /** Constant <code>master="Constants.R_HEADS + Constants.MASTER"</code> */ 4251e2646dSJens Baumgart protected static final String master = Constants.R_HEADS + Constants.MASTER; 4351e2646dSJens Baumgart 4451e2646dSJens Baumgart /** In-memory application server; subclass must start. */ 4551e2646dSJens Baumgart protected AppServer server; 4651e2646dSJens Baumgart 470b131b73SMatthias Sohn /** {@inheritDoc} */ 487ac182f4SDavid Pursehouse @Override setUp()49d9e07a57SRobin Rosenberg public void setUp() throws Exception { 5051e2646dSJens Baumgart super.setUp(); 51e17bfc96SThomas Wolf server = createServer(); 5251e2646dSJens Baumgart } 5351e2646dSJens Baumgart 540b131b73SMatthias Sohn /** {@inheritDoc} */ 557ac182f4SDavid Pursehouse @Override tearDown()56d9e07a57SRobin Rosenberg public void tearDown() throws Exception { 5751e2646dSJens Baumgart server.tearDown(); 5851e2646dSJens Baumgart super.tearDown(); 5951e2646dSJens Baumgart } 6051e2646dSJens Baumgart 61e17bfc96SThomas Wolf /** 620b131b73SMatthias Sohn * Create the {@link AppServer}.This default implementation creates a server 63e17bfc96SThomas Wolf * without SSLsupport listening for HTTP connections on a dynamically chosen 64e17bfc96SThomas Wolf * port, which can be gotten once the server has been started via its 650b131b73SMatthias Sohn * {@link org.eclipse.jgit.junit.http.AppServer#getPort()} method. 660b131b73SMatthias Sohn * Subclasses may override if they need a more specialized server. 67e17bfc96SThomas Wolf * 680b131b73SMatthias Sohn * @return the {@link org.eclipse.jgit.junit.http.AppServer}. 69e17bfc96SThomas Wolf * @since 4.9 70e17bfc96SThomas Wolf */ createServer()71e17bfc96SThomas Wolf protected AppServer createServer() { 72e17bfc96SThomas Wolf return new AppServer(); 73e17bfc96SThomas Wolf } 74e17bfc96SThomas Wolf 750b131b73SMatthias Sohn /** 760b131b73SMatthias Sohn * Create TestRepository 770b131b73SMatthias Sohn * 780b131b73SMatthias Sohn * @return the TestRepository 790b131b73SMatthias Sohn * @throws IOException 800b131b73SMatthias Sohn */ createTestRepository()81526b6266SRobin Rosenberg protected TestRepository<Repository> createTestRepository() 8251e2646dSJens Baumgart throws IOException { 833b444863SDavid Pursehouse return new TestRepository<>(createBareRepository()); 8451e2646dSJens Baumgart } 8551e2646dSJens Baumgart 860b131b73SMatthias Sohn /** 870b131b73SMatthias Sohn * Convert path to URIish 880b131b73SMatthias Sohn * 890b131b73SMatthias Sohn * @param path 900b131b73SMatthias Sohn * @return the URIish 910b131b73SMatthias Sohn * @throws URISyntaxException 920b131b73SMatthias Sohn */ toURIish(String path)9351e2646dSJens Baumgart protected URIish toURIish(String path) throws URISyntaxException { 9451e2646dSJens Baumgart URI u = server.getURI().resolve(path); 9551e2646dSJens Baumgart return new URIish(u.toString()); 9651e2646dSJens Baumgart } 9751e2646dSJens Baumgart 980b131b73SMatthias Sohn /** 990b131b73SMatthias Sohn * Convert a path relative to the app's context path to a URIish 1000b131b73SMatthias Sohn * 1010b131b73SMatthias Sohn * @param app 1020b131b73SMatthias Sohn * @param name 1030b131b73SMatthias Sohn * @return the warnings (if any) from the last execution 1040b131b73SMatthias Sohn * @throws URISyntaxException 1050b131b73SMatthias Sohn */ toURIish(ServletContextHandler app, String name)10651e2646dSJens Baumgart protected URIish toURIish(ServletContextHandler app, String name) 10751e2646dSJens Baumgart throws URISyntaxException { 10851e2646dSJens Baumgart String p = app.getContextPath(); 10951e2646dSJens Baumgart if (!p.endsWith("/") && !name.startsWith("/")) 11051e2646dSJens Baumgart p += "/"; 11151e2646dSJens Baumgart p += name; 11251e2646dSJens Baumgart return toURIish(p); 11351e2646dSJens Baumgart } 11451e2646dSJens Baumgart 1150b131b73SMatthias Sohn /** 1160b131b73SMatthias Sohn * Get requests. 1170b131b73SMatthias Sohn * 1180b131b73SMatthias Sohn * @return list of events 1190b131b73SMatthias Sohn */ getRequests()12051e2646dSJens Baumgart protected List<AccessEvent> getRequests() { 12151e2646dSJens Baumgart return server.getRequests(); 12251e2646dSJens Baumgart } 12351e2646dSJens Baumgart 1240b131b73SMatthias Sohn /** 1250b131b73SMatthias Sohn * Get requests. 1260b131b73SMatthias Sohn * 1270b131b73SMatthias Sohn * @param base 1280b131b73SMatthias Sohn * @param path 1290b131b73SMatthias Sohn * 1300b131b73SMatthias Sohn * @return list of events 1310b131b73SMatthias Sohn */ getRequests(URIish base, String path)13251e2646dSJens Baumgart protected List<AccessEvent> getRequests(URIish base, String path) { 13351e2646dSJens Baumgart return server.getRequests(base, path); 13451e2646dSJens Baumgart } 13551e2646dSJens Baumgart 1360b131b73SMatthias Sohn /** 1370b131b73SMatthias Sohn * Get requests. 1380b131b73SMatthias Sohn * 1390b131b73SMatthias Sohn * @param path 1400b131b73SMatthias Sohn * 1410b131b73SMatthias Sohn * @return list of events 1420b131b73SMatthias Sohn */ getRequests(String path)14351e2646dSJens Baumgart protected List<AccessEvent> getRequests(String path) { 14451e2646dSJens Baumgart return server.getRequests(path); 14551e2646dSJens Baumgart } 14651e2646dSJens Baumgart 1470b131b73SMatthias Sohn /** 1480b131b73SMatthias Sohn * Run fsck 1490b131b73SMatthias Sohn * 1500b131b73SMatthias Sohn * @param db 1510b131b73SMatthias Sohn * @param tips 1520b131b73SMatthias Sohn * @throws Exception 1530b131b73SMatthias Sohn */ fsck(Repository db, RevObject... tips)15451e2646dSJens Baumgart protected static void fsck(Repository db, RevObject... tips) 15551e2646dSJens Baumgart throws Exception { 156b4656572SDavid Pursehouse try (TestRepository<? extends Repository> tr = 157b4656572SDavid Pursehouse new TestRepository<>(db)) { 158b4d33382SMatthias Sohn tr.fsck(tips); 15951e2646dSJens Baumgart } 160b4656572SDavid Pursehouse } 16151e2646dSJens Baumgart 1620b131b73SMatthias Sohn /** 1630b131b73SMatthias Sohn * Mirror refs 1640b131b73SMatthias Sohn * 1650b131b73SMatthias Sohn * @param refs 1660b131b73SMatthias Sohn * @return set of RefSpecs 1670b131b73SMatthias Sohn */ mirror(String... refs)16851e2646dSJens Baumgart protected static Set<RefSpec> mirror(String... refs) { 1693b444863SDavid Pursehouse HashSet<RefSpec> r = new HashSet<>(); 17051e2646dSJens Baumgart for (String name : refs) { 17151e2646dSJens Baumgart RefSpec rs = new RefSpec(name); 17251e2646dSJens Baumgart rs = rs.setDestination(name); 17351e2646dSJens Baumgart rs = rs.setForceUpdate(true); 17451e2646dSJens Baumgart r.add(rs); 17551e2646dSJens Baumgart } 17651e2646dSJens Baumgart return r; 17751e2646dSJens Baumgart } 17851e2646dSJens Baumgart 1790b131b73SMatthias Sohn /** 1800b131b73SMatthias Sohn * Push a commit 1810b131b73SMatthias Sohn * 1820b131b73SMatthias Sohn * @param from 1830b131b73SMatthias Sohn * @param q 1840b131b73SMatthias Sohn * @return collection of RefUpdates 1850b131b73SMatthias Sohn * @throws IOException 1860b131b73SMatthias Sohn */ push(TestRepository from, RevCommit q)18751e2646dSJens Baumgart protected static Collection<RemoteRefUpdate> push(TestRepository from, 18851e2646dSJens Baumgart RevCommit q) throws IOException { 18951e2646dSJens Baumgart final Repository db = from.getRepository(); 19051e2646dSJens Baumgart final String srcExpr = q.name(); 19151e2646dSJens Baumgart final String dstName = master; 19251e2646dSJens Baumgart final boolean forceUpdate = true; 19351e2646dSJens Baumgart final String localName = null; 19451e2646dSJens Baumgart final ObjectId oldId = null; 19551e2646dSJens Baumgart 19651e2646dSJens Baumgart RemoteRefUpdate u = new RemoteRefUpdate(db, srcExpr, dstName, 19751e2646dSJens Baumgart forceUpdate, localName, oldId); 19851e2646dSJens Baumgart return Collections.singleton(u); 19951e2646dSJens Baumgart } 20051e2646dSJens Baumgart 2010b131b73SMatthias Sohn /** 2020b131b73SMatthias Sohn * Create loose object path 2030b131b73SMatthias Sohn * 2040b131b73SMatthias Sohn * @param base 2050b131b73SMatthias Sohn * @param id 2060b131b73SMatthias Sohn * @return path of the loose object 2070b131b73SMatthias Sohn */ loose(URIish base, AnyObjectId id)20851e2646dSJens Baumgart public static String loose(URIish base, AnyObjectId id) { 20951e2646dSJens Baumgart final String objectName = id.name(); 21051e2646dSJens Baumgart final String d = objectName.substring(0, 2); 21151e2646dSJens Baumgart final String f = objectName.substring(2); 21251e2646dSJens Baumgart return join(base, "objects/" + d + "/" + f); 21351e2646dSJens Baumgart } 21451e2646dSJens Baumgart 2150b131b73SMatthias Sohn /** 2160b131b73SMatthias Sohn * Join a base URIish and a path 2170b131b73SMatthias Sohn * 2180b131b73SMatthias Sohn * @param base 2190b131b73SMatthias Sohn * @param path 2200b131b73SMatthias Sohn * a relative path 2210b131b73SMatthias Sohn * @return the joined path 2220b131b73SMatthias Sohn */ join(URIish base, String path)22351e2646dSJens Baumgart public static String join(URIish base, String path) { 22451e2646dSJens Baumgart if (path.startsWith("/")) 22551e2646dSJens Baumgart fail("Cannot join absolute path " + path + " to URIish " + base); 22651e2646dSJens Baumgart 22751e2646dSJens Baumgart String dir = base.getPath(); 22851e2646dSJens Baumgart if (!dir.endsWith("/")) 22951e2646dSJens Baumgart dir += "/"; 23051e2646dSJens Baumgart return dir + path; 23151e2646dSJens Baumgart } 232e17bfc96SThomas Wolf 2330b131b73SMatthias Sohn /** 2340b131b73SMatthias Sohn * Rewrite a url 2350b131b73SMatthias Sohn * 2360b131b73SMatthias Sohn * @param url 2370b131b73SMatthias Sohn * @param newProtocol 2380b131b73SMatthias Sohn * @param newPort 2390b131b73SMatthias Sohn * @return the rewritten url 2400b131b73SMatthias Sohn */ rewriteUrl(String url, String newProtocol, int newPort)241e17bfc96SThomas Wolf protected static String rewriteUrl(String url, String newProtocol, 242e17bfc96SThomas Wolf int newPort) { 243e17bfc96SThomas Wolf String newUrl = url; 244e17bfc96SThomas Wolf if (newProtocol != null && !newProtocol.isEmpty()) { 245e17bfc96SThomas Wolf int schemeEnd = newUrl.indexOf("://"); 246e17bfc96SThomas Wolf if (schemeEnd >= 0) { 247e17bfc96SThomas Wolf newUrl = newProtocol + newUrl.substring(schemeEnd); 248e17bfc96SThomas Wolf } 249e17bfc96SThomas Wolf } 250e17bfc96SThomas Wolf if (newPort > 0) { 251e17bfc96SThomas Wolf newUrl = newUrl.replaceFirst(":\\d+/", ":" + newPort + "/"); 252e17bfc96SThomas Wolf } else { 253e17bfc96SThomas Wolf // Remove the port, if any 254e17bfc96SThomas Wolf newUrl = newUrl.replaceFirst(":\\d+/", "/"); 255e17bfc96SThomas Wolf } 256e17bfc96SThomas Wolf return newUrl; 257e17bfc96SThomas Wolf } 258e17bfc96SThomas Wolf 2590b131b73SMatthias Sohn /** 2600b131b73SMatthias Sohn * Extend a path 2610b131b73SMatthias Sohn * 2620b131b73SMatthias Sohn * @param uri 2630b131b73SMatthias Sohn * @param pathComponents 2640b131b73SMatthias Sohn * @return the extended URIish 2650b131b73SMatthias Sohn * @throws URISyntaxException 2660b131b73SMatthias Sohn */ extendPath(URIish uri, String pathComponents)267e17bfc96SThomas Wolf protected static URIish extendPath(URIish uri, String pathComponents) 268e17bfc96SThomas Wolf throws URISyntaxException { 269e17bfc96SThomas Wolf String raw = uri.toString(); 270e17bfc96SThomas Wolf String newComponents = pathComponents; 271e17bfc96SThomas Wolf if (!newComponents.startsWith("/")) { 272e17bfc96SThomas Wolf newComponents = '/' + newComponents; 273e17bfc96SThomas Wolf } 274e17bfc96SThomas Wolf if (!newComponents.endsWith("/")) { 275e17bfc96SThomas Wolf newComponents += '/'; 276e17bfc96SThomas Wolf } 277e17bfc96SThomas Wolf int i = raw.lastIndexOf('/'); 278e17bfc96SThomas Wolf raw = raw.substring(0, i) + newComponents + raw.substring(i + 1); 279e17bfc96SThomas Wolf return new URIish(raw); 280e17bfc96SThomas Wolf } 28151e2646dSJens Baumgart } 282