Skip to content

Commit e260f03

Browse files
committed
integration tests for minio rules
1 parent fb9bb5e commit e260f03

File tree

13 files changed

+357
-0
lines changed

13 files changed

+357
-0
lines changed

.bazelignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
e2e/

e2e/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.minio.sys/
2+
mc/share/

e2e/BUILD.archive

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
exports_files(["file.txt"])

e2e/BUILD.bazel

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
load("@rules_python//python:defs.bzl", "py_binary", "py_library")
2+
3+
py_binary(
4+
name = "cloud_archive_test",
5+
srcs = ["cloud_archive_test.py"],
6+
data = [
7+
":mc_config",
8+
"@mc_binary//file",
9+
],
10+
deps = [
11+
":minio_server_lib",
12+
"@rules_python//python/runfiles",
13+
],
14+
)
15+
16+
filegroup(
17+
name = "testdata",
18+
srcs = glob(["testdata/**"]),
19+
)
20+
21+
filegroup(
22+
name = "mc_config",
23+
srcs = glob(["mc/**"]),
24+
)
25+
26+
py_library(
27+
name = "minio_server_lib",
28+
srcs = ["minio_server.py"],
29+
data = [
30+
":testdata",
31+
"@minio_binary//file"
32+
],
33+
deps = [
34+
"@rules_python//python/runfiles",
35+
],
36+
)
37+
38+
py_binary(
39+
name = "minio_server",
40+
srcs = ["minio_server.py"],
41+
deps = [":minio_server_lib"],
42+
)

e2e/README.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Integration Test Repository
2+
3+
```shell
4+
bazel run //:minio_server
5+
```
6+
7+
will start a [MinIO](https://docs.min.io) server locally.
8+
By default, it serves from the `testdata/` directory.
9+
There is a single bucket named `bucket`.
10+
11+
You can fetch the [AlStor client](https://docs.min.io/enterprise/aistor-object-store/reference/cli/) with `bazel`,
12+
13+
```shell
14+
bazel build @mc_binary//file
15+
```
16+
17+
This can be used from the command line by including the output on your `PATH`,
18+
19+
```shell
20+
export PATH="$(bazel info execution_root)/external/mc_binary/file:$PATH"
21+
```
22+
23+
The client's config is available in `mc/`.
24+
There is a single alias named `local` with default typical MinIO defaults set.
25+
Again, we'll update our shell for convenience,
26+
27+
```shell
28+
export MC_CONFIG_DIR="$PWD/mc"
29+
```
30+
31+
You should now be able to access the server with `$ mc admin info local`.
32+
You are now able to fetch the data using `bazel` and the `cloud_archive` rules,
33+
34+
**`minio_file`**:
35+
36+
```shell
37+
bazel build @test_file//file
38+
```
39+
40+
**`minio_archive`**:
41+
42+
```shell
43+
bazel build @test_archive//:file.txt
44+
```
45+
46+
## Tests
47+
48+
All of the above is done automatically when running the integration tests,
49+
50+
```shell
51+
bazel run //:cloud_archive_test
52+
```

e2e/WORKSPACE

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
workspace(name = "my_workspace")
2+
3+
load("@bazel_tools//tools/build_defs/repo:local.bzl", "local_repository")
4+
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_file")
5+
6+
local_repository(
7+
name = "cloud_archive",
8+
path = "..",
9+
)
10+
11+
load("@cloud_archive//:cloud_archive.bzl", "minio_archive", "minio_file")
12+
13+
minio_archive(
14+
name = "test_archive",
15+
build_file = "//:BUILD.archive",
16+
file_path = "local/bucket/data.tar.gz",
17+
sha256 = "cb8c43418acb05e11619478fbb9c0a76827841cc2d1f58ce9b4d7b5093d1c01e",
18+
)
19+
20+
minio_archive(
21+
name = "test_archive_p0_patch",
22+
patches = ["@//:patches/p0.patch"],
23+
build_file = "//:BUILD.archive",
24+
file_path = "local/bucket/data.tar.gz",
25+
sha256 = "cb8c43418acb05e11619478fbb9c0a76827841cc2d1f58ce9b4d7b5093d1c01e",
26+
)
27+
28+
minio_archive(
29+
name = "test_archive_p1_patch",
30+
patch_args = ["-p1"],
31+
patches = ["@//:patches/p1.patch"],
32+
build_file = "//:BUILD.archive",
33+
file_path = "local/bucket/data.tar.gz",
34+
sha256 = "cb8c43418acb05e11619478fbb9c0a76827841cc2d1f58ce9b4d7b5093d1c01e",
35+
)
36+
37+
minio_file(
38+
name = "test_file",
39+
file_path = "local/bucket/file.txt",
40+
sha256 = "8e686326c475d56c005bcda41fe457e777894b57b98be9b29603779d3f6d50b6",
41+
)
42+
43+
http_archive(
44+
name = "rules_python",
45+
sha256 = "fa532d635f29c038a64c8062724af700c30cf6b31174dd4fac120bc561a1a560",
46+
strip_prefix = "rules_python-1.5.1",
47+
urls = [
48+
"https://github.com/bazel-contrib/rules_python/releases/download/1.5.1/rules_python-1.5.1.tar.gz",
49+
],
50+
)
51+
52+
load("@rules_python//python:repositories.bzl", "py_repositories")
53+
54+
py_repositories()
55+
56+
http_file(
57+
name = "minio_binary",
58+
urls = [
59+
"https://dl.min.io/server/minio/release/linux-amd64/minio",
60+
],
61+
downloaded_file_path = "minio",
62+
executable = True,
63+
sha256 = "eef6581f6509f43ece007a6f2eb4c5e3ce41498c8956e919a7ac7b4b170fa431",
64+
)
65+
66+
http_file(
67+
name = "mc_binary",
68+
urls = [
69+
"https://dl.min.io/client/mc/release/linux-amd64/mc",
70+
],
71+
downloaded_file_path = "mc",
72+
executable = True,
73+
sha256 = "ea4a453be116071ab1ccbd24eb8755bf0579649f41a7b94ab9e68571bb9f4a1e",
74+
)

e2e/cloud_archive_test.py

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
from __future__ import annotations
2+
3+
import atexit
4+
import os
5+
import pathlib
6+
import shutil
7+
import socket
8+
import subprocess
9+
import tempfile
10+
import time
11+
import unittest
12+
13+
import minio_server
14+
from python.runfiles import Runfiles
15+
16+
MINIO_PORT = 9000
17+
18+
FILE_CONTENT = "go bears"
19+
PATCHED_CONTENT = "Go Bears!"
20+
21+
# Always run in a new output_base to avoid false-negatives from caching.
22+
TEMP_OUTPUT_BASE = tempfile.mkdtemp()
23+
atexit.register(shutil.rmtree, TEMP_OUTPUT_BASE)
24+
25+
26+
def wait_for_port(host: str, port: int, timeout: int = 5) -> bool:
27+
start = time.time()
28+
while time.time() - start < timeout:
29+
try:
30+
with socket.create_connection((host, port), timeout=1):
31+
return True
32+
except OSError: # noqa: PERF203
33+
time.sleep(0.1)
34+
return False
35+
36+
37+
class CloudArchiveTest(unittest.TestCase):
38+
@classmethod
39+
def setUpClass(cls) -> None:
40+
r = Runfiles.Create()
41+
mc_binary = r.Rlocation("mc_binary/file/mc")
42+
mc_config = r.Rlocation("my_workspace/mc/config.json")
43+
44+
cls.env = {
45+
"PATH": f"{os.path.dirname(mc_binary)}:{os.environ['PATH']}",
46+
"MC_CONFIG_DIR": os.path.dirname(mc_config),
47+
}
48+
cls.workspace_dir = os.environ["BUILD_WORKING_DIRECTORY"]
49+
50+
repository_cache = subprocess.check_output(
51+
["bazel", "info", "repository_cache"],
52+
text=True,
53+
cwd=cls.workspace_dir,
54+
).strip()
55+
cls.bazel_args = [
56+
f"--output_base={TEMP_OUTPUT_BASE}",
57+
]
58+
cls.bazel_build_args = [
59+
f"--repository_cache={repository_cache}",
60+
]
61+
62+
execution_root = subprocess.check_output(
63+
["bazel", *cls.bazel_args, "info", "execution_root"],
64+
text=True,
65+
cwd=cls.workspace_dir,
66+
).strip()
67+
cls.output_dir = pathlib.Path(execution_root, "external")
68+
69+
def test_minio(self) -> None:
70+
subtests = [
71+
(
72+
"@test_file//file",
73+
FILE_CONTENT,
74+
self.output_dir / "test_file" / "file" / "downloaded",
75+
),
76+
(
77+
"@test_archive//:file.txt",
78+
FILE_CONTENT,
79+
self.output_dir / "test_archive" / "file.txt",
80+
),
81+
(
82+
"@test_archive_p0_patch//:file.txt",
83+
PATCHED_CONTENT,
84+
self.output_dir / "test_archive_p0_patch" / "file.txt",
85+
),
86+
(
87+
"@test_archive_p1_patch//:file.txt",
88+
PATCHED_CONTENT,
89+
self.output_dir / "test_archive_p1_patch" / "file.txt",
90+
),
91+
]
92+
with minio_server.run(port=MINIO_PORT) as proc:
93+
if not wait_for_port("127.0.0.1", MINIO_PORT):
94+
proc.kill()
95+
print("MinIO server failed to start")
96+
raise SystemExit(1)
97+
98+
for target, expected_content, output_path in subtests:
99+
with self.subTest(target=target):
100+
subprocess.check_call(
101+
["bazel", *self.bazel_args, "build", *self.bazel_build_args, target],
102+
env=self.env,
103+
cwd=self.workspace_dir,
104+
)
105+
assert expected_content in output_path.read_text()
106+
107+
108+
if __name__ == "__main__":
109+
unittest.main()

e2e/mc/config.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "10",
3+
"aliases": {
4+
"local": {
5+
"url": "http://127.0.0.1:9000",
6+
"accessKey": "minioadmin",
7+
"secretKey": "minioadmin",
8+
"api": "s3v4",
9+
"path": "auto"
10+
}
11+
}
12+
}

e2e/minio_server.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from __future__ import annotations
2+
3+
from contextlib import contextmanager
4+
import os
5+
import subprocess
6+
import typing
7+
8+
from python.runfiles import Runfiles
9+
10+
MINIO_ACCESS_KEY = "minioadmin"
11+
MINIO_SECRET_KEY = "minioadmin" # noqa: S105
12+
13+
14+
@contextmanager
15+
def run(*_: typing.Any, port: int = 9000, wait: bool = False) -> typing.Generator:
16+
r = Runfiles.Create()
17+
minio_binary = r.Rlocation("minio_binary/file/minio")
18+
data_directory = os.path.dirname(
19+
os.path.dirname(
20+
os.path.dirname(
21+
r.Rlocation(
22+
"my_workspace/testdata/bucket/file.txt/xl.meta" # The particular file is not important. # noqa: E501
23+
)
24+
)
25+
)
26+
)
27+
28+
env = os.environ.copy()
29+
env["MINIO_ROOT_USER"] = MINIO_ACCESS_KEY
30+
env["MINIO_ROOT_PASSWORD"] = MINIO_SECRET_KEY
31+
32+
proc = subprocess.Popen( # noqa: S603
33+
[minio_binary, "server", f"--address=:{port}", data_directory],
34+
env=env,
35+
)
36+
37+
try:
38+
if wait:
39+
proc.wait()
40+
return
41+
yield proc
42+
finally:
43+
if not wait:
44+
proc.terminate()
45+
proc.wait()
46+
47+
48+
if __name__ == "__main__":
49+
with run(wait=True):
50+
pass

e2e/patches/p0.patch

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
diff --git file.txt file.txt
2+
index 0247de8..18bdb41 100644
3+
--- file.txt
4+
+++ file.txt
5+
@@ -1 +1 @@
6+
-go bears
7+
+Go Bears!

0 commit comments

Comments
 (0)