Skip to content

Commit 82e049f

Browse files
committed
Add a docker registry integration test with real registry
1 parent 364a189 commit 82e049f

File tree

6 files changed

+67
-66
lines changed

6 files changed

+67
-66
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ jobs:
6565
- unit
6666
- venv
6767
- contentproviders
68+
- registry
6869
# Playwright test
6970
- ui
7071
include:
@@ -73,22 +74,9 @@ jobs:
7374
python_version: "3.9"
7475
repo_type: venv
7576

76-
services:
77-
# So that we can test this in PRs/branches
78-
local-registry:
79-
image: registry:2
80-
ports:
81-
- 5000:5000
82-
8377
steps:
8478
- uses: actions/checkout@v4
8579

86-
- name: Set up Docker Buildx
87-
uses: docker/setup-buildx-action@v3
88-
with:
89-
# Allows pushing to registry on localhost:5000
90-
driver-opts: network=host
91-
9280
- uses: actions/setup-python@v5
9381
with:
9482
python-version: "${{ matrix.python_version }}"

repo2docker/app.py

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
RBuildPack,
3838
)
3939
from .engine import BuildError, ContainerEngineException, ImageLoadError
40-
from .utils import ByteSpecification, R2dState, chdir, get_platform
40+
from .utils import ByteSpecification, R2dState, chdir, get_platform, get_free_port
4141

4242

4343
class Repo2Docker(Application):
@@ -660,7 +660,7 @@ def start_container(self):
660660
container_port = int(container_port_proto.split("/", 1)[0])
661661
else:
662662
# no port specified, pick a random one
663-
container_port = host_port = str(self._get_free_port())
663+
container_port = host_port = str(get_free_port())
664664
self.ports = {f"{container_port}/tcp": host_port}
665665
self.port = host_port
666666
# To use the option --NotebookApp.custom_display_url
@@ -744,17 +744,6 @@ def wait_for_container(self, container):
744744
if exit_code:
745745
sys.exit(exit_code)
746746

747-
def _get_free_port(self):
748-
"""
749-
Hacky method to get a free random port on local host
750-
"""
751-
import socket
752-
753-
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
754-
s.bind(("", 0))
755-
port = s.getsockname()[1]
756-
s.close()
757-
return port
758747

759748
def find_image(self):
760749
# if this is a dry run it is Ok for dockerd to be unreachable so we

repo2docker/utils.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import socket
23
import platform
34
import re
45
import subprocess
@@ -545,3 +546,14 @@ def get_platform():
545546
else:
546547
warnings.warn(f"Unexpected platform '{m}', defaulting to linux/amd64")
547548
return "linux/amd64"
549+
550+
551+
def get_free_port():
552+
"""
553+
Hacky method to get a free random port on local host
554+
"""
555+
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
556+
s.bind(("", 0))
557+
port = s.getsockname()[1]
558+
s.close()
559+
return port

tests/registry/Dockerfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Smallest possible dockerfile, used only for building images to be tested
2+
FROM scratch

tests/registry/test_registry.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from pathlib import Path
2+
import subprocess
3+
import pytest
4+
from repo2docker.__main__ import make_r2d
5+
from repo2docker.utils import get_free_port
6+
import time
7+
import requests
8+
import secrets
9+
10+
HERE = Path(__file__).parent
11+
12+
@pytest.fixture
13+
def registry():
14+
port = get_free_port()
15+
cmd = [
16+
"docker", "run", "-it", "-p", f"{port}:5000", "registry:3.0.0-rc.3"
17+
]
18+
proc = subprocess.Popen(cmd)
19+
health_url = f'http://localhost:{port}/v2'
20+
# Wait for the registry to actually come up
21+
for i in range(10):
22+
try:
23+
resp = requests.get(health_url)
24+
if resp.status_code in (401, 200):
25+
break
26+
except requests.ConnectionError:
27+
# The service is not up yet
28+
pass
29+
time.sleep(i)
30+
else:
31+
raise TimeoutError("Test registry did not come up in time")
32+
33+
try:
34+
yield f"localhost:{port}"
35+
finally:
36+
proc.terminate()
37+
proc.wait()
38+
39+
40+
def test_registry(registry):
41+
image_name = f"{registry}/{secrets.token_hex(8)}:latest"
42+
r2d = make_r2d([
43+
"--image", image_name,
44+
"--push", "--no-run", str(HERE)
45+
])
46+
47+
r2d.start()
48+
49+
proc = subprocess.run(["docker", "manifest", "inspect", "--insecure", image_name])
50+
assert proc.returncode == 0

tests/unit/test_docker.py

Lines changed: 0 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -22,43 +22,3 @@ def test_git_credential_env():
2222
.strip()
2323
)
2424
assert out == credential_env
25-
26-
27-
class MockDockerEngine(DockerEngine):
28-
def __init__(self, *args, **kwargs):
29-
self._apiclient = Mock()
30-
31-
32-
def test_docker_push_no_credentials():
33-
engine = MockDockerEngine()
34-
35-
engine.push("image")
36-
37-
assert len(engine._apiclient.method_calls) == 1
38-
engine._apiclient.push.assert_called_once_with("image", stream=True)
39-
40-
41-
def test_docker_push_dict_credentials():
42-
engine = MockDockerEngine()
43-
engine.registry_credentials = {"username": "abc", "password": "def"}
44-
45-
engine.push("image")
46-
47-
assert len(engine._apiclient.method_calls) == 2
48-
engine._apiclient.login.assert_called_once_with(username="abc", password="def")
49-
engine._apiclient.push.assert_called_once_with("image", stream=True)
50-
51-
52-
def test_docker_push_env_credentials():
53-
engine = MockDockerEngine()
54-
with patch.dict(
55-
"os.environ",
56-
{
57-
"CONTAINER_ENGINE_REGISTRY_CREDENTIALS": '{"username": "abc", "password": "def"}'
58-
},
59-
):
60-
engine.push("image")
61-
62-
assert len(engine._apiclient.method_calls) == 2
63-
engine._apiclient.login.assert_called_once_with(username="abc", password="def")
64-
engine._apiclient.push.assert_called_once_with("image", stream=True)

0 commit comments

Comments
 (0)