46 | * Default password is 12345 47 | * 48 | * @param password - git password 49 | * @return instance of the git server container 50 | */ 51 | public GitServerContainer withGitPassword(String password) { 52 | withEnv(GIT_PASSWORD_KEY, password); 53 | return this; 54 | } 55 | 56 | 57 | /** 58 | * Override the default git repository name. 59 | *
60 | * Default name is "testRepo" 61 | * 62 | * @param gitRepoName - name of the git repository that is created by default 63 | * @return instance of the git server container 64 | */ 65 | public GitServerContainer withGitRepo(String gitRepoName) { 66 | this.gitRepoName = gitRepoName; 67 | return this; 68 | } 69 | 70 | /** 71 | * Enabled SSH public key authentication. 72 | * 73 | * @return instance of the git server container 74 | */ 75 | public GitServerContainer withSshKeyAuth() { 76 | try { 77 | sshClientIdentity = new SshIdentity( 78 | this.getClass().getClassLoader().getResourceAsStream("id_client").readAllBytes(), 79 | this.getClass().getClassLoader().getResourceAsStream("id_client.pub").readAllBytes(), 80 | new byte[0]); 81 | 82 | withClasspathResourceMapping("id_client.pub", "/home/git/.ssh/authorized_keys", BindMode.READ_ONLY); 83 | withClasspathResourceMapping("sshd_config", "/etc/ssh/sshd_config", BindMode.READ_ONLY); 84 | 85 | 86 | } catch (IOException e) { 87 | throw new RuntimeException(e); 88 | } 89 | return this; 90 | } 91 | 92 | /** 93 | * Copy an existing git repository to the container. 94 | *
95 | * The git repository is copied to the container and the git repository is initialized as bare repository. 96 | * 97 | * @param pathtoExistingRepo - path to the existing git repository. The path is relative to the project root. 98 | * @return instance of the git server container 99 | */ 100 | public GitServerContainer withCopyExistingGitRepoToContainer(String pathtoExistingRepo) { 101 | this.pathToExistingRepo = pathtoExistingRepo; 102 | return this; 103 | } 104 | 105 | /** 106 | * Return the SSH URI for git repo. 107 | * 108 | * @return SSH URI 109 | */ 110 | public URI getGitRepoURIAsSSH() { 111 | 112 | return URI.create("ssh://git@" + getHost() + ":" + getMappedPort(22) + "/srv/git/" + gitRepoName + ".git"); 113 | } 114 | 115 | @Override 116 | protected void containerIsStarted(InspectContainerResponse containerInfo) { 117 | super.containerIsStarted(containerInfo); 118 | configureGitRepository(); 119 | collectHostKeyInformation(); 120 | fixFilePermissions(); 121 | } 122 | 123 | /** 124 | * Wrong file permissions cause authentication to fail. 125 | */ 126 | private void fixFilePermissions() { 127 | try { 128 | execInContainer("chmod", "600", "/home/git/.ssh/authorized_keys"); 129 | } catch (IOException | InterruptedException e) { 130 | throw new RuntimeException("Could not fix file permissions on /home/git/.ssh/authorized_keys", e); 131 | } 132 | } 133 | 134 | private void collectHostKeyInformation() { 135 | try { 136 | ExecResult result = execInContainer("cat", "/etc/ssh/ssh_host_ecdsa_key.pub"); 137 | String[] catResult = result.getStdout().split(" "); 138 | hostKey = new SshHostKey(getHost(), Base64.getDecoder().decode(catResult[1])); 139 | } catch (IOException | InterruptedException e) { 140 | throw new RuntimeException("Could not collect host key information", e); 141 | } 142 | } 143 | 144 | private void configureGitRepository() { 145 | try { 146 | String gitRepoPath = String.format("/srv/git/%s.git", gitRepoName); 147 | if (pathToExistingRepo != null) { 148 | copyFileToContainer(MountableFile.forHostPath(pathToExistingRepo + "/.git"), gitRepoPath); 149 | execInContainer("git", "config", "--bool", "core.bare", "true", gitRepoPath); 150 | execInContainer("chown", "-R", "git:git", "/srv"); 151 | } else { 152 | execInContainer("mkdir", "-p", gitRepoPath); 153 | execInContainer("git", "init", "--bare", gitRepoPath); 154 | execInContainer("chown", "-R", "git:git", "/srv"); 155 | } 156 | } catch (IOException | InterruptedException e) { 157 | throw new RuntimeException("Configure Git repository failed",e); 158 | } 159 | } 160 | 161 | /** 162 | * Return the Git Password that was set with the method {@code withGitPassword}. 163 | *
164 | * If no password was set, the default "12345" is returned. 165 | * 166 | * @return the git password 167 | */ 168 | public String getGitPassword() { 169 | var password = getEnvMap().get(GIT_PASSWORD_KEY); 170 | return password != null ? password : "12345"; 171 | } 172 | 173 | /** 174 | * Return the identity information for public key authentication. 175 | *
176 | * If {@code withSshKeyAuth} was not called, then it returns null.
177 | *
178 | * @return identity information for a public key authentication
179 | */
180 | public SshIdentity getSshClientIdentity() {
181 | return sshClientIdentity;
182 | }
183 |
184 | /**
185 | * Return the public host key information.
186 | *
187 | * @return public host key
188 | */
189 | public SshHostKey getHostKey() {
190 | return hostKey;
191 | }
192 |
193 | }
194 |
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/main/java/com/github/sparsick/testcontainers/gitserver/plain/SshHostKey.java:
--------------------------------------------------------------------------------
1 | package com.github.sparsick.testcontainers.gitserver.plain;
2 |
3 | import java.util.Objects;
4 |
5 |
6 | /**
7 | * Value object for SSH Host key information.
8 | */
9 | public class SshHostKey {
10 |
11 | private String hostname;
12 | private byte[] key;
13 |
14 | /**
15 | * SSH Host Key information
16 | * @param hostname host
17 | * @param key keystring
18 | */
19 | public SshHostKey(String hostname, byte[] key) {
20 | this.key = key;
21 | this.hostname = hostname;
22 | }
23 |
24 | /**
25 | * Public key of the host key.
26 | *
27 | * @return key string
28 | */
29 | public byte[] getKey() {
30 | return key;
31 | }
32 |
33 | /**
34 | * Name of the host
35 | *
36 | * @return name of the host
37 | */
38 | public String getHostname() {
39 | return hostname;
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/main/java/com/github/sparsick/testcontainers/gitserver/plain/SshIdentity.java:
--------------------------------------------------------------------------------
1 | package com.github.sparsick.testcontainers.gitserver.plain;
2 |
3 | /**
4 | * Value object for identity information for a public key authentication.
5 | */
6 | public class SshIdentity {
7 | private byte[] privateKey;
8 | private byte[] publicKey;
9 | private byte[] passphrase;
10 |
11 | /**
12 | * Identity information for a public key authentication.
13 | *
14 | * @param privateKey SSH private key
15 | * @param publicKey SSH public key
16 | * @param passphrase password for private key
17 | */
18 | public SshIdentity(byte[] privateKey, byte[] publicKey, byte[] passphrase) {
19 | this.privateKey = privateKey;
20 | this.publicKey = publicKey;
21 | this.passphrase = passphrase;
22 | }
23 |
24 | /**
25 | * SSH private key
26 | *
27 | * @return SSH private key
28 | */
29 | public byte[] getPrivateKey() {
30 | return privateKey;
31 | }
32 |
33 | /**
34 | * SSH public key
35 | *
36 | * @return SSH public key
37 | */
38 | public byte[] getPublicKey() {
39 | return publicKey;
40 | }
41 |
42 | /**
43 | * Password for the SSH private key
44 | *
45 | * @return Password for the SSH private key
46 | */
47 | public byte[] getPassphrase() {
48 | return passphrase;
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/main/resources/http-config/nginx.conf:
--------------------------------------------------------------------------------
1 | worker_processes 1;
2 |
3 | error_log /var/log/nginx/error.log;
4 | pid /run/nginx.pid;
5 | user root;
6 |
7 | events {
8 | worker_connections 1024;
9 | }
10 |
11 | http {
12 | server {
13 | listen *:80;
14 |
15 | root /www/empty/;
16 | index index.html;
17 |
18 | server_name $hostname;
19 | access_log /var/log/nginx/access.log;
20 |
21 | #error_page 404 /404.html;
22 |
23 | #auth_basic "Restricted";
24 | #auth_basic_user_file /etc/nginx/.htpasswd;
25 |
26 | location ~ /git(/.*) {
27 | # Set chunks to unlimited, as the bodies can be huge
28 | client_max_body_size 0;
29 |
30 | fastcgi_param SCRIPT_FILENAME /usr/libexec/git-core/git-http-backend;
31 | include fastcgi_params;
32 | fastcgi_param GIT_HTTP_EXPORT_ALL "";
33 | fastcgi_param GIT_PROJECT_ROOT /srv/git;
34 | fastcgi_param PATH_INFO $1;
35 |
36 | # Forward REMOTE_USER as we want to know when we are authenticated
37 | fastcgi_param REMOTE_USER $remote_user;
38 | fastcgi_pass unix:/run/fcgi.sock;
39 | }
40 | }
41 | }
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/main/resources/id_client:
--------------------------------------------------------------------------------
1 | -----BEGIN EC PRIVATE KEY-----
2 | MHcCAQEEIAv2zdBPnakBt4UCoTDRMLDKOrm0JiPc9CwRFqvcha5coAoGCCqGSM49
3 | AwEHoUQDQgAEKArvTWElvX1Erm/essBeGKQzsGrHPJjGJprwEOqV/MKjUPZ1jxl3
4 | iZL9m/PqZrKc94PGgpalIFdxOcdrgwTLMg==
5 | -----END EC PRIVATE KEY-----
6 |
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/main/resources/id_client.pub:
--------------------------------------------------------------------------------
1 | ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCgK701hJb19RK5v3rLAXhikM7BqxzyYxiaa8BDqlfzCo1D2dY8Zd4mS/Zvz6maynPeDxoKWpSBXcTnHa4MEyzI= sparsick@Thinkpad-T14
2 |
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/main/resources/sshd_config:
--------------------------------------------------------------------------------
1 | # $OpenBSD: sshd_config,v 1.104 2021/07/02 05:11:21 dtucker Exp $
2 |
3 | # This is the sshd server system-wide configuration file. See
4 | # sshd_config(5) for more information.
5 |
6 | # This sshd was compiled with PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
7 |
8 | # The strategy used for options in the default sshd_config shipped with
9 | # OpenSSH is to specify options with their default value where
10 | # possible, but leave them commented. Uncommented options override the
11 | # default value.
12 |
13 | #Port 22
14 | #AddressFamily any
15 | #ListenAddress 0.0.0.0
16 | #ListenAddress ::
17 |
18 | #HostKey /etc/ssh/ssh_host_rsa_key
19 | #HostKey /etc/ssh/ssh_host_ecdsa_key
20 | #HostKey /etc/ssh/ssh_host_ed25519_key
21 |
22 | # Ciphers and keying
23 | #RekeyLimit default none
24 |
25 | # Logging
26 | #SyslogFacility AUTH
27 | #LogLevel DEBUG
28 |
29 | # Authentication:
30 |
31 | #LoginGraceTime 2m
32 | #PermitRootLogin prohibit-password
33 | #StrictModes yes
34 | #MaxAuthTries 6
35 | #MaxSessions 10
36 |
37 | #PubkeyAuthentication yes
38 | #PubkeyAcceptedAlgorithms ssh-rsa
39 |
40 | # The default is to check both .ssh/authorized_keys and .ssh/authorized_keys2
41 | # but this is overridden so installations will only check .ssh/authorized_keys
42 | AuthorizedKeysFile .ssh/authorized_keys
43 |
44 | #AuthorizedPrincipalsFile none
45 |
46 | #AuthorizedKeysCommand none
47 | #AuthorizedKeysCommandUser nobody
48 |
49 | # For this to work you will also need host keys in /etc/ssh/ssh_known_hosts
50 | #HostbasedAuthentication no
51 | # Change to yes if you don't trust ~/.ssh/known_hosts for
52 | # HostbasedAuthentication
53 | #IgnoreUserKnownHosts no
54 | # Don't read the user's ~/.rhosts and ~/.shosts files
55 | #IgnoreRhosts yes
56 |
57 | # To disable tunneled clear text passwords, change to no here!
58 | #PasswordAuthentication yes
59 | #PermitEmptyPasswords no
60 |
61 | # Change to no to disable s/key passwords
62 | #KbdInteractiveAuthentication yes
63 |
64 | # Kerberos options
65 | #KerberosAuthentication no
66 | #KerberosOrLocalPasswd yes
67 | #KerberosTicketCleanup yes
68 | #KerberosGetAFSToken no
69 |
70 | # GSSAPI options
71 | #GSSAPIAuthentication no
72 | #GSSAPICleanupCredentials yes
73 |
74 | # Set this to 'yes' to enable PAM authentication, account processing,
75 | # and session processing. If this is enabled, PAM authentication will
76 | # be allowed through the KbdInteractiveAuthentication and
77 | # PasswordAuthentication. Depending on your PAM configuration,
78 | # PAM authentication via KbdInteractiveAuthentication may bypass
79 | # the setting of "PermitRootLogin without-password".
80 | # If you just want the PAM account and session checks to run without
81 | # PAM authentication, then enable this but set PasswordAuthentication
82 | # and KbdInteractiveAuthentication to 'no'.
83 | #UsePAM no
84 |
85 | #AllowAgentForwarding yes
86 | # Feel free to re-enable these if your use case requires them.
87 | AllowTcpForwarding no
88 | GatewayPorts no
89 | X11Forwarding no
90 | #X11DisplayOffset 10
91 | #X11UseLocalhost yes
92 | #PermitTTY yes
93 | #PrintMotd yes
94 | #PrintLastLog yes
95 | #TCPKeepAlive yes
96 | #PermitUserEnvironment no
97 | #Compression delayed
98 | #ClientAliveInterval 0
99 | #ClientAliveCountMax 3
100 | #UseDNS no
101 | #PidFile /run/sshd.pid
102 | #MaxStartups 10:30:100
103 | #PermitTunnel no
104 | #ChrootDirectory none
105 | #VersionAddendum none
106 |
107 | # no default banner path
108 | #Banner none
109 |
110 | # override default of no subsystems
111 | Subsystem sftp /usr/lib/ssh/sftp-server
112 |
113 | # Example of overriding settings on a per-user basis
114 | #Match User anoncvs
115 | # X11Forwarding no
116 | # AllowTcpForwarding no
117 | # PermitTTY no
118 | # ForceCommand cvs server
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/test/java/com/github/sparsick/testcontainers/gitserver/http/GitHttpServerContainerTest.java:
--------------------------------------------------------------------------------
1 | package com.github.sparsick.testcontainers.gitserver.http;
2 |
3 | import com.github.sparsick.testcontainers.gitserver.GitServerVersions;
4 | import org.assertj.core.api.ThrowableAssert;
5 | import org.eclipse.jgit.api.Git;
6 | import org.eclipse.jgit.api.errors.GitAPIException;
7 | import org.eclipse.jgit.api.errors.TransportException;
8 | import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider;
9 | import org.junit.jupiter.api.Test;
10 | import org.junit.jupiter.api.io.CleanupMode;
11 | import org.junit.jupiter.api.io.TempDir;
12 | import org.junit.jupiter.params.ParameterizedTest;
13 | import org.junit.jupiter.params.provider.EnumSource;
14 | import org.testcontainers.utility.DockerImageName;
15 |
16 | import java.io.File;
17 | import java.io.IOException;
18 |
19 | import static org.assertj.core.api.Assertions.assertThat;
20 | import static org.assertj.core.api.Assertions.catchThrowableOfType;
21 |
22 |
23 | public class GitHttpServerContainerTest {
24 |
25 | private static final DockerImageName LATEST_GIT_SERVER_VERSION = GitServerVersions.V2_49.getDockerImageName();
26 |
27 | @TempDir(cleanup = CleanupMode.NEVER)
28 | private File tempDir;
29 |
30 | @ParameterizedTest
31 | @EnumSource(GitServerVersions.class)
32 | void cloneWithoutAuthentication(GitServerVersions gitServerVersions) throws GitAPIException, IOException {
33 | GitHttpServerContainer containerUnderTest = new GitHttpServerContainer(gitServerVersions.getDockerImageName());
34 | containerUnderTest.start();
35 |
36 | Git git = Git.cloneRepository()
37 | .setURI(containerUnderTest.getGitRepoURIAsHttp().toString())
38 | .setDirectory(tempDir)
39 | .call();
40 |
41 | assertThat(new File(tempDir, ".git")).exists();
42 | assertGitPull(git);
43 | }
44 |
45 | @ParameterizedTest
46 | @EnumSource(GitServerVersions.class)
47 | void cloneWithAuthenticationFailedWithoutCredential(GitServerVersions gitServerVersions) {
48 | GitHttpServerContainer containerUnderTest = new GitHttpServerContainer(gitServerVersions.getDockerImageName(), new BasicAuthenticationCredentials("testuser", "testPassword"));
49 | containerUnderTest.start();
50 |
51 |
52 | ThrowableAssert.ThrowingCallable tryingClone = () -> Git.cloneRepository()
53 | .setURI(containerUnderTest.getGitRepoURIAsHttp().toString())
54 | .setDirectory(tempDir)
55 | .call();
56 | TransportException expectedException = catchThrowableOfType(tryingClone, TransportException.class);
57 | assertThat(expectedException).isNotNull();
58 | assertThat(expectedException).hasMessageContaining("Authentication is required");
59 | }
60 |
61 | @ParameterizedTest
62 | @EnumSource(GitServerVersions.class)
63 | void cloneWithAuthentication(GitServerVersions gitServerVersions) throws GitAPIException, IOException {
64 | GitHttpServerContainer containerUnderTest = new GitHttpServerContainer(gitServerVersions.getDockerImageName(),new BasicAuthenticationCredentials("testuser", "testPassword"));
65 | containerUnderTest.start();
66 |
67 | UsernamePasswordCredentialsProvider credentialsProvider = new UsernamePasswordCredentialsProvider(containerUnderTest.getBasicAuthCredentials().getUsername(), containerUnderTest.getBasicAuthCredentials().getPassword());
68 | Git git = Git.cloneRepository()
69 | .setURI(containerUnderTest.getGitRepoURIAsHttp().toString())
70 | .setDirectory(tempDir)
71 | .setCredentialsProvider(credentialsProvider)
72 | .call();
73 |
74 | assertThat(new File(tempDir, ".git")).exists();
75 | assertGitPull(git, credentialsProvider);
76 | }
77 |
78 | @Test
79 | void enableHttpProxySetting() throws GitAPIException, IOException {
80 | GitHttpServerContainer containerUnderTest = new GitHttpServerContainer(LATEST_GIT_SERVER_VERSION).withHttpProxySetting(new HttpProxySetting("http://proxy.example.com", "https://proxy.example.com", ""));
81 | containerUnderTest.start();
82 |
83 | assertThat(containerUnderTest.hasHttpProxy()).isTrue();
84 |
85 |
86 | }
87 |
88 | private void assertGitPull(Git git, UsernamePasswordCredentialsProvider credentialsProvider) throws IOException, GitAPIException {
89 | new File(tempDir, "test.txt").createNewFile();
90 | git.add().addFilepattern(".").call();
91 | git.commit().setMessage("test").call();
92 |
93 | if (credentialsProvider == null) {
94 | git.push().call();
95 | } else {
96 | git.push().setCredentialsProvider(credentialsProvider).call();
97 | }
98 | }
99 |
100 | private void assertGitPull(Git git) throws IOException, GitAPIException {
101 | assertGitPull(git, null);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/test/java/com/github/sparsick/testcontainers/gitserver/plain/GitServerContainerJUnit5IntegrationTest.java:
--------------------------------------------------------------------------------
1 | package com.github.sparsick.testcontainers.gitserver.plain;
2 |
3 | import com.jcraft.jsch.Session;
4 | import org.eclipse.jgit.api.Git;
5 | import org.eclipse.jgit.transport.SshTransport;
6 | import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory;
7 | import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig;
8 | import org.junit.jupiter.api.Test;
9 | import org.junit.jupiter.api.io.CleanupMode;
10 | import org.junit.jupiter.api.io.TempDir;
11 | import org.testcontainers.junit.jupiter.Container;
12 | import org.testcontainers.junit.jupiter.Testcontainers;
13 | import org.testcontainers.utility.DockerImageName;
14 |
15 | import java.io.File;
16 | import java.net.URI;
17 |
18 | import static org.assertj.core.api.Assertions.assertThat;
19 | import static org.assertj.core.api.Assertions.assertThatNoException;
20 |
21 | @Testcontainers
22 | public class GitServerContainerJUnit5IntegrationTest {
23 |
24 | @Container
25 | private GitServerContainer containerUnderTest = new GitServerContainer(DockerImageName.parse("rockstorm/git-server"));
26 |
27 | @TempDir(cleanup = CleanupMode.NEVER)
28 | private File tempDir;
29 |
30 |
31 | @Test
32 | void cloneGitRepo() {
33 | URI gitRepoURI = containerUnderTest.getGitRepoURIAsSSH();
34 |
35 | assertThatNoException().isThrownBy(() ->
36 | Git.cloneRepository()
37 | .setURI(gitRepoURI.toString())
38 | .setDirectory(tempDir)
39 | .setBranch("main")
40 | .setTransportConfigCallback(transport -> {
41 | var sshTransport = (SshTransport) transport;
42 | sshTransport.setSshSessionFactory(new JschConfigSessionFactory() {
43 | @Override
44 | protected void configure(OpenSshConfig.Host hc, Session session) {
45 | session.setPassword(containerUnderTest.getGitPassword());
46 | session.setConfig("StrictHostKeyChecking", "no");
47 | }
48 | });
49 | })
50 | .call()
51 | );
52 | assertThat(new File(tempDir, ".git")).exists();
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/testcontainers-gitserver/src/test/java/com/github/sparsick/testcontainers/gitserver/plain/GitServerContainerTest.java:
--------------------------------------------------------------------------------
1 | package com.github.sparsick.testcontainers.gitserver.plain;
2 |
3 | import com.github.sparsick.testcontainers.gitserver.GitServerVersions;
4 | import com.jcraft.jsch.HostKey;
5 | import com.jcraft.jsch.JSch;
6 | import com.jcraft.jsch.JSchException;
7 | import com.jcraft.jsch.Session;
8 | import org.eclipse.jgit.api.Git;
9 | import org.eclipse.jgit.api.TransportConfigCallback;
10 | import org.eclipse.jgit.api.errors.GitAPIException;
11 | import org.eclipse.jgit.transport.SshTransport;
12 | import org.eclipse.jgit.transport.Transport;
13 | import org.eclipse.jgit.transport.ssh.jsch.JschConfigSessionFactory;
14 | import org.eclipse.jgit.transport.ssh.jsch.OpenSshConfig;
15 | import org.eclipse.jgit.util.FS;
16 | import org.jetbrains.annotations.NotNull;
17 | import org.junit.jupiter.api.Test;
18 | import org.junit.jupiter.api.io.CleanupMode;
19 | import org.junit.jupiter.api.io.TempDir;
20 | import org.junit.jupiter.params.ParameterizedTest;
21 | import org.junit.jupiter.params.provider.Arguments;
22 | import org.junit.jupiter.params.provider.EnumSource;
23 | import org.junit.jupiter.params.provider.MethodSource;
24 | import org.testcontainers.shaded.org.apache.commons.io.FileUtils;
25 | import org.testcontainers.utility.DockerImageName;
26 |
27 | import java.io.File;
28 | import java.io.IOException;
29 | import java.net.URI;
30 | import java.util.Arrays;
31 | import java.util.List;
32 | import java.util.Map;
33 | import java.util.stream.Stream;
34 | import java.util.stream.StreamSupport;
35 |
36 | import static org.assertj.core.api.Assertions.assertThatNoException;
37 | import static org.assertj.core.api.Assertions.assertThatThrownBy;
38 | import static org.assertj.core.api.Assertions.assertThat;
39 |
40 | public class GitServerContainerTest {
41 |
42 | private static final DockerImageName LATEST_GIT_SERVER_VERSION = GitServerVersions.V2_47.getDockerImageName();
43 | @TempDir(cleanup = CleanupMode.NEVER)
44 | private File tempDir;
45 |
46 |
47 | static Stream