blob: badcb7d7e5948bd1e82a1def261d757880f1c1e8 [file] [log] [blame]
/*
* Copyright (C) 2022 Nail Samatov <sanail@yandex.ru> and others
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0 which is available at
* https://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
package org.eclipse.jgit.lfs.internal;
import static org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.RemoteAddCommand;
import org.eclipse.jgit.attributes.FilterCommandRegistry;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lfs.CleanFilter;
import org.eclipse.jgit.lfs.Protocol;
import org.eclipse.jgit.lfs.SmudgeFilter;
import org.eclipse.jgit.lfs.errors.LfsConfigInvalidException;
import org.eclipse.jgit.lfs.lib.Constants;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.StoredConfig;
import org.eclipse.jgit.transport.URIish;
import org.eclipse.jgit.transport.http.HttpConnection;
import org.eclipse.jgit.util.HttpSupport;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class LfsConnectionFactoryTest extends RepositoryTestCase {
private static final String SMUDGE_NAME = org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+ Constants.ATTR_FILTER_DRIVER_PREFIX
+ org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_SMUDGE;
private static final String CLEAN_NAME = org.eclipse.jgit.lib.Constants.BUILTIN_FILTER_PREFIX
+ Constants.ATTR_FILTER_DRIVER_PREFIX
+ org.eclipse.jgit.lib.Constants.ATTR_FILTER_TYPE_CLEAN;
private final static String LFS_SERVER_URL1 = "https://lfs.server1/test/uri";
private final static String LFS_SERVER_URL2 = "https://lfs.server2/test/uri";
private final static String ORIGIN_URL = "https://git.server/test/uri";
private Git git;
@BeforeClass
public static void installLfs() {
FilterCommandRegistry.register(SMUDGE_NAME, SmudgeFilter.FACTORY);
FilterCommandRegistry.register(CLEAN_NAME, CleanFilter.FACTORY);
}
@AfterClass
public static void removeLfs() {
FilterCommandRegistry.unregister(SMUDGE_NAME);
FilterCommandRegistry.unregister(CLEAN_NAME);
}
@Override
@Before
public void setUp() throws Exception {
super.setUp();
git = new Git(db);
// Just to have a non empty repo
writeTrashFile("Test.txt", "Hello world from the LFS Factory Test");
git.add().addFilepattern("Test.txt").call();
git.commit().setMessage("Initial commit").call();
}
@Test
public void lfsUrlFromRemoteUrlWithDotGit() throws Exception {
addRemoteUrl("https://localhost/repo.git");
checkLfsUrl("https://localhost/repo.git/info/lfs");
}
@Test
public void lfsUrlFromRemoteUrlWithoutDotGit() throws Exception {
addRemoteUrl("https://localhost/repo");
checkLfsUrl("https://localhost/repo.git/info/lfs");
}
@Test
public void lfsUrlFromLocalConfig() throws Exception {
addRemoteUrl("https://localhost/repo");
StoredConfig cfg = ((Repository) db).getConfig();
cfg.setString(ConfigConstants.CONFIG_SECTION_LFS,
null,
ConfigConstants.CONFIG_KEY_URL,
"https://localhost/repo/lfs");
cfg.save();
checkLfsUrl("https://localhost/repo/lfs");
}
@Test
public void lfsUrlFromOriginConfig() throws Exception {
addRemoteUrl("https://localhost/repo");
StoredConfig cfg = ((Repository) db).getConfig();
cfg.setString(ConfigConstants.CONFIG_SECTION_LFS,
org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME,
ConfigConstants.CONFIG_KEY_URL,
"https://localhost/repo/lfs");
cfg.save();
checkLfsUrl("https://localhost/repo/lfs");
}
@Test
public void lfsUrlNotConfigured() throws Exception {
assertThrows(LfsConfigInvalidException.class,
() -> LfsConnectionFactory.getLfsConnection(db,
HttpSupport.METHOD_POST, Protocol.OPERATION_DOWNLOAD));
}
@Test
public void checkGetLfsConnection_lfsurl_lfsconfigFromWorkingDir()
throws Exception {
writeLfsConfig();
checkLfsUrl(LFS_SERVER_URL1);
}
@Test
public void checkGetLfsConnection_lfsurl_lfsconfigFromIndex()
throws Exception {
writeLfsConfig();
git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
deleteTrashFile(Constants.DOT_LFS_CONFIG);
checkLfsUrl(LFS_SERVER_URL1);
}
@Test
public void checkGetLfsConnection_lfsurl_lfsconfigFromHEAD()
throws Exception {
writeLfsConfig();
git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
git.commit().setMessage("Commit LFS Config").call();
/*
* reading .lfsconfig from HEAD seems only testable using a bare repo,
* since otherwise working tree or index are used
*/
File directory = createTempDirectory("testBareRepo");
try (Repository bareRepoDb = Git.cloneRepository()
.setDirectory(directory)
.setURI(db.getDirectory().toURI().toString()).setBare(true)
.call().getRepository()) {
checkLfsUrl(LFS_SERVER_URL1);
}
}
@Test
public void checkGetLfsConnection_remote_lfsconfigFromWorkingDir()
throws Exception {
addRemoteUrl(ORIGIN_URL);
writeLfsConfig(LFS_SERVER_URL1, "lfs", DEFAULT_REMOTE_NAME, "url");
checkLfsUrl(LFS_SERVER_URL1);
}
/**
* Test the config file precedence.
*
* Checking only with the local repository config is sufficient since from
* that point the "normal" precedence is used.
*
* @throws Exception
*/
@Test
public void checkGetLfsConnection_ConfigFilePrecedence_lfsconfigFromWorkingDir()
throws Exception {
writeLfsConfig();
checkLfsUrl(LFS_SERVER_URL1);
StoredConfig config = git.getRepository().getConfig();
config.setString(ConfigConstants.CONFIG_SECTION_LFS, null,
ConfigConstants.CONFIG_KEY_URL, LFS_SERVER_URL2);
config.save();
checkLfsUrl(LFS_SERVER_URL2);
}
@Test
public void checkGetLfsConnection_InvalidLfsConfig_WorkingDir()
throws Exception {
writeInvalidLfsConfig();
LfsConfigInvalidException actualException = assertThrows(
LfsConfigInvalidException.class, () -> {
LfsConnectionFactory.getLfsConnection(db, HttpSupport.METHOD_POST,
Protocol.OPERATION_DOWNLOAD);
});
assertTrue(getStackTrace(actualException)
.contains("Invalid line in config file"));
}
@Test
public void checkGetLfsConnection_InvalidLfsConfig_Index()
throws Exception {
writeInvalidLfsConfig();
git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
deleteTrashFile(Constants.DOT_LFS_CONFIG);
LfsConfigInvalidException actualException = assertThrows(
LfsConfigInvalidException.class, () -> {
LfsConnectionFactory.getLfsConnection(db, HttpSupport.METHOD_POST,
Protocol.OPERATION_DOWNLOAD);
});
assertTrue(getStackTrace(actualException)
.contains("Invalid line in config file"));
}
@Test
public void checkGetLfsConnection_InvalidLfsConfig_HEAD() throws Exception {
writeInvalidLfsConfig();
git.add().addFilepattern(Constants.DOT_LFS_CONFIG).call();
git.commit().setMessage("Commit LFS Config").call();
/*
* reading .lfsconfig from HEAD seems only testable using a bare repo,
* since otherwise working tree or index are used
*/
File directory = createTempDirectory("testBareRepo");
try (Repository bareRepoDb = Git.cloneRepository()
.setDirectory(directory)
.setURI(db.getDirectory().toURI().toString()).setBare(true)
.call().getRepository()) {
LfsConfigInvalidException actualException = assertThrows(
LfsConfigInvalidException.class,
() -> {
LfsConnectionFactory.getLfsConnection(db,
HttpSupport.METHOD_POST,
Protocol.OPERATION_DOWNLOAD);
});
assertTrue(getStackTrace(actualException)
.contains("Invalid line in config file"));
}
}
private void addRemoteUrl(String remotUrl) throws Exception {
RemoteAddCommand add = git.remoteAdd();
add.setUri(new URIish(remotUrl));
add.setName(org.eclipse.jgit.lib.Constants.DEFAULT_REMOTE_NAME);
add.call();
}
/**
* Returns the stack trace of the provided exception as string
*
* @param actualException
* @return The exception stack trace as string
*/
private String getStackTrace(Exception actualException) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
actualException.printStackTrace(pw);
return sw.toString();
}
private void writeLfsConfig() throws IOException {
writeLfsConfig(LFS_SERVER_URL1, "lfs", "url");
}
private void writeLfsConfig(String lfsUrl, String section, String name)
throws IOException {
writeLfsConfig(lfsUrl, section, null, name);
}
/*
* Write simple lfs config with single entry. Do not use FileBasedConfig to
* avoid introducing new dependency (for now).
*/
private void writeLfsConfig(String lfsUrl, String section,
String subsection, String name) throws IOException {
StringBuilder config = new StringBuilder();
config.append("[");
config.append(section);
if (subsection != null) {
config.append(" \"");
config.append(subsection);
config.append("\"");
}
config.append("]\n");
config.append(" ");
config.append(name);
config.append(" = ");
config.append(lfsUrl);
writeTrashFile(Constants.DOT_LFS_CONFIG, config.toString());
}
private void writeInvalidLfsConfig() throws IOException {
writeTrashFile(Constants.DOT_LFS_CONFIG,
"{lfs]\n url = " + LFS_SERVER_URL1);
}
private void checkLfsUrl(String lfsUrl) throws IOException {
HttpConnection lfsServerConn;
lfsServerConn = LfsConnectionFactory.getLfsConnection(db,
HttpSupport.METHOD_POST, Protocol.OPERATION_DOWNLOAD);
assertEquals(lfsUrl + Protocol.OBJECTS_LFS_ENDPOINT,
lfsServerConn.getURL().toString());
}
}