Skip to content

Commit e1b5cc4

Browse files
author
Shubham
committed
Download Sync server executable from artifacts
Instead of using Docker to run the Sync server, download its executable from GitLab artifacts and run it.
1 parent 3fd1e91 commit e1b5cc4

File tree

3 files changed

+160
-41
lines changed

3 files changed

+160
-41
lines changed

.gitlab-ci.yml

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,15 @@ test-sync:linux:x64:
109109
matrix:
110110
- PYTHON_VERSION: [ '3.7', '3.8', '3.9', '3.10', '3.11', '3.12' ]
111111

112-
test-sync:linux:armv7hf:
113-
extends: .test-sync
114-
tags: [ armv7hf, shell, linux, python3 ]
112+
#test-sync:linux:armv7hf:
113+
# extends: .test-sync
114+
# tags: [ armv7hf, shell, linux, python3 ]
115115

116116
test-sync:linux:aarch64:
117117
extends: .test-sync
118118
tags: [ aarch64, shell, linux, python3 ]
119119

120-
test-sync:mac:x64:
120+
test-sync:mac:arm64:
121121
extends: .test-sync
122122
script:
123123
- python3 -m venv .venv
@@ -126,11 +126,11 @@ test-sync:mac:x64:
126126
- rm -r objectbox # todo this is ugly; let's copy required files in a sub-folder instead?
127127
- pip3 install --force-reinstall dist/*.whl # Artifacts from build-sync
128128
- python -m pytest -s --runsync
129-
tags: [ mac, x64, shell, python3 ]
129+
tags: [ mac, arm64, shell, python3 ]
130130

131-
test-sync:windows:x64:
132-
extends: .test-sync
133-
tags: [ windows, x64, python ]
134-
variables:
135-
PYTHON: "python.exe"
131+
#test-sync:windows:x64:
132+
# extends: .test-sync
133+
# tags: [ windows, x64, python ]
134+
# variables:
135+
# PYTHON: "python.exe"
136136

tests/common.py

Lines changed: 149 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
import subprocess
44
import socket
55
import typing
6+
import platform
7+
import glob
8+
import zipfile
9+
import tarfile
10+
import signal
11+
import urllib.request
612

713
import pytest
814
import objectbox
@@ -48,56 +54,169 @@ def create_test_store(db_path: str = "testdata", clear_db: bool = True) -> objec
4854

4955
@dataclass
5056
class SyncServerConfig:
51-
container_id: str
57+
pid: int
5258
port: int
5359

5460

61+
def _get_sync_server_job_name() -> str:
62+
"""Returns the GitLab CI job name for downloading the sync server based on OS and architecture."""
63+
system = platform.system().lower()
64+
machine = platform.machine().lower()
65+
66+
if system == "darwin":
67+
if machine in ("arm64", "aarch64"):
68+
return "b:mac-arm64-server"
69+
else:
70+
return "b:mac-x64-server"
71+
elif system == "linux":
72+
if machine in ("arm64", "aarch64"):
73+
return "b:linux-aarch64-server"
74+
else:
75+
return "b:linux-x64-server"
76+
else:
77+
raise RuntimeError(f"Unsupported platform: {system} {machine}")
78+
79+
5580
def start_sync_server() -> typing.Union[SyncServerConfig, None]:
56-
""" Starts the ObjectBox Sync Server in a Docker container. """
81+
""" Downloads and starts the ObjectBox Sync Server binary. """
5782
current_dir = os.path.dirname(os.path.realpath(__file__))
58-
user_id = None
59-
if os.name != 'nt':
60-
user_id = os.getuid()
61-
else:
62-
user_id = 0
83+
84+
# Check for required environment variables
85+
ci_server_url = os.environ.get("CI_SERVER_URL")
86+
ci_job_token = os.environ.get("CI_JOB_TOKEN")
87+
88+
if not ci_server_url or not ci_job_token:
89+
test_logger.warning("CI_SERVER_URL or CI_JOB_TOKEN not set, cannot download sync server")
90+
return None
91+
6392
try:
64-
command = ("docker run "
65-
"--rm "
66-
"-d "
67-
f"--volume {current_dir}:/data "
68-
f"--user {user_id} "
69-
"-p 127.0.0.1:9999:9999 "
70-
"objectboxio/sync-server-trial "
71-
"--conf sync_server_config.json")
72-
logger.info("Using command to start Sync Server Docker container:" + command)
73-
stdout = subprocess.run(command.split(), check=True, capture_output=True, text=True).stdout
74-
container_id = stdout.strip()
93+
# GitLab artifact download configuration
94+
project_id = "4"
95+
job_name = _get_sync_server_job_name()
96+
branch = "syncdev"
97+
98+
# URL-encode the job name (colon -> %3A)
99+
job_name_encoded = job_name.replace(":", "%3A")
100+
101+
artifact_url = f"{ci_server_url}/api/v4/projects/{project_id}/jobs/artifacts/{branch}/download?job={job_name_encoded}"
102+
103+
print(f"Downloading sync-server artifact from: {artifact_url}")
104+
105+
# Download the artifact
106+
artifact_path = os.path.join(current_dir, "artifact.zip")
107+
request = urllib.request.Request(artifact_url, headers={"JOB-TOKEN": ci_job_token})
108+
with urllib.request.urlopen(request) as response, open(artifact_path, "wb") as out_file:
109+
out_file.write(response.read())
110+
111+
# Extract the outer artifact zip
112+
with zipfile.ZipFile(artifact_path, "r") as zip_ref:
113+
zip_ref.extractall(current_dir)
114+
115+
# Find and extract the sync-server archive (could be .zip or .tar.gz)
116+
artifacts_dir = os.path.join(current_dir, "artifacts")
117+
118+
# Look for both .zip and .tar.gz files
119+
sync_server_zips = glob.glob(os.path.join(artifacts_dir, "objectbox-sync-server-*.zip"))
120+
sync_server_tarballs = glob.glob(os.path.join(artifacts_dir, "objectbox-sync-server-*.tar.gz"))
121+
122+
if sync_server_zips:
123+
sync_server_archive = sync_server_zips[0]
124+
print(f"Found sync-server zip archive: {sync_server_archive}")
125+
with zipfile.ZipFile(sync_server_archive, "r") as zip_ref:
126+
zip_ref.extractall(current_dir)
127+
elif sync_server_tarballs:
128+
sync_server_archive = sync_server_tarballs[0]
129+
print(f"Found sync-server tar.gz archive: {sync_server_archive}")
130+
with tarfile.open(sync_server_archive, "r:gz") as tar_ref:
131+
tar_ref.extractall(current_dir)
132+
else:
133+
raise RuntimeError("Could not find objectbox-sync-server-*.zip or *.tar.gz in artifacts")
134+
135+
# Verify sync-server executable exists
136+
sync_server_executable = os.path.join(current_dir, "sync-server")
137+
if platform.system().lower() == "windows":
138+
sync_server_executable += ".exe"
139+
140+
if not os.path.exists(sync_server_executable):
141+
raise RuntimeError("sync-server executable not found after extraction")
142+
143+
# Make executable on Unix systems
144+
if os.name != "nt":
145+
os.chmod(sync_server_executable, 0o755)
146+
147+
print("Starting sync-server in background...")
75148

149+
# Run sync-server in background
150+
process = subprocess.Popen(
151+
[
152+
sync_server_executable,
153+
"--model", os.path.join(current_dir, "objectbox-model.json"),
154+
"--unsecured-no-authentication",
155+
"--debug"
156+
],
157+
cwd=current_dir,
158+
stdout=subprocess.DEVNULL,
159+
stderr=subprocess.DEVNULL
160+
)
161+
162+
print(f"Sync server started with PID: {process.pid}")
163+
164+
# Wait for server to be ready
165+
time.sleep(2)
166+
167+
# Check if server is still running
168+
if process.poll() is not None:
169+
raise RuntimeError("Sync server failed to start")
170+
171+
# Wait for port to be available
76172
start_time = time.time()
77173
while (time.time() - start_time) < 10:
78174
try:
79-
with socket.create_connection(("127.0.0.1", 9999)):
175+
with socket.create_connection(("127.0.0.1", 9999), timeout=1):
80176
break
81-
except OSError:
82-
pass
177+
except (OSError, socket.timeout):
178+
time.sleep(0.5)
83179
else:
84180
raise RuntimeError("Timed out waiting for Sync Server to start")
85181

86-
test_logger.info("Started ObjectBox Sync Server in Docker")
87-
return SyncServerConfig(container_id=container_id, port=9999)
182+
print("Sync server is running")
183+
return SyncServerConfig(pid=process.pid, port=9999)
184+
88185
except Exception as e:
89-
test_logger.warning(f"Could not start ObjectBox Sync Server in Docker: {e}")
186+
test_logger.warning(f"Could not start ObjectBox Sync Server: {e}")
90187
return None
91188

92189

93-
def stop_sync_server(container_id: str):
94-
""" Stops the ObjectBox Sync Server Docker container. """
190+
def stop_sync_server(pid: int):
191+
""" Stops the ObjectBox Sync Server process. """
95192
try:
96-
command = f"docker stop {container_id}"
97-
subprocess.run(command.split(), check=True)
98-
test_logger.info("Stopped ObjectBox Sync Server Docker container")
193+
print(f"Stopping sync server (PID: {pid})...")
194+
195+
# Send SIGTERM (or equivalent on Windows)
196+
if os.name == "nt":
197+
subprocess.run(["taskkill", "/F", "/PID", str(pid)], check=False)
198+
else:
199+
os.kill(pid, signal.SIGTERM)
200+
201+
# Wait for process to stop
202+
for i in range(10):
203+
try:
204+
os.kill(pid, 0) # Check if process exists
205+
time.sleep(1)
206+
except OSError:
207+
print(f"Sync server stopped after {i + 1}s")
208+
return
209+
210+
# Force kill if still running
211+
print("Sync server still running after 10s, sending SIGKILL...")
212+
if os.name == "nt":
213+
subprocess.run(["taskkill", "/F", "/PID", str(pid)], check=False)
214+
else:
215+
os.kill(pid, signal.SIGKILL)
216+
217+
print("Stopped ObjectBox Sync Server")
99218
except Exception as e:
100-
test_logger.warning(f"Could not stop ObjectBox Sync Server Docker container: {e}")
219+
test_logger.warning(f"Could not stop ObjectBox Sync Server: {e}")
101220

102221

103222
def assert_equal_prop(actual, expected, default):

tests/conftest.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ def sync_server():
9292
server_config = start_sync_server()
9393
yield server_config
9494
if server_config:
95-
stop_sync_server(server_config.container_id)
95+
stop_sync_server(server_config.pid)
9696

9797

9898
def pytest_addoption(parser):

0 commit comments

Comments
 (0)