robotframework-testcontainers 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from TestcontainersLibrary.library import TestcontainersLibrary # noqa
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from robot.api.deco import library, keyword
|
|
4
|
+
from robot.api import logger
|
|
5
|
+
from testcontainers.core.container import DockerContainer
|
|
6
|
+
from testcontainers.core.wait_strategies import LogMessageWaitStrategy, HttpWaitStrategy
|
|
7
|
+
from testcontainers.generic.server import ServerContainer
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@library(listener="SELF")
|
|
11
|
+
class TestcontainersLibrary:
|
|
12
|
+
def __init__(self):
|
|
13
|
+
self._containers: list[DockerContainer] = []
|
|
14
|
+
|
|
15
|
+
@keyword
|
|
16
|
+
def create_docker_container(
|
|
17
|
+
self,
|
|
18
|
+
image: str,
|
|
19
|
+
command: str | None = None,
|
|
20
|
+
env: dict[str, str] | None = None,
|
|
21
|
+
name: str | None = None,
|
|
22
|
+
ports: list[int] | None = None,
|
|
23
|
+
volumes: list[tuple[Path, str, str]] | None = None,
|
|
24
|
+
start: bool = True,
|
|
25
|
+
) -> DockerContainer:
|
|
26
|
+
container = DockerContainer(
|
|
27
|
+
image=image,
|
|
28
|
+
command=command,
|
|
29
|
+
env=env,
|
|
30
|
+
name=name,
|
|
31
|
+
ports=ports,
|
|
32
|
+
volumes=self._resolve_volume_paths(volumes) if volumes else None,
|
|
33
|
+
)
|
|
34
|
+
if start:
|
|
35
|
+
self.start_container(container)
|
|
36
|
+
return container
|
|
37
|
+
|
|
38
|
+
def _resolve_volume_paths(
|
|
39
|
+
self, volumes: list[tuple[Path, str, str]]
|
|
40
|
+
) -> list[tuple[str, str, str]]:
|
|
41
|
+
return [(v[0].resolve().as_posix(), v[1], v[2]) for v in volumes]
|
|
42
|
+
|
|
43
|
+
@keyword
|
|
44
|
+
def create_server_container(
|
|
45
|
+
self, port: int, image: str, start: bool = True
|
|
46
|
+
) -> ServerContainer:
|
|
47
|
+
container = ServerContainer(port=port, image=image)
|
|
48
|
+
if start:
|
|
49
|
+
self.start_container(container)
|
|
50
|
+
return container
|
|
51
|
+
|
|
52
|
+
@keyword
|
|
53
|
+
def create_community_container(
|
|
54
|
+
self, module: str, container_class: str, start: bool = True, **kwargs
|
|
55
|
+
) -> DockerContainer:
|
|
56
|
+
_module = importlib.import_module(module)
|
|
57
|
+
clazz = getattr(_module, container_class)
|
|
58
|
+
container = clazz(**kwargs)
|
|
59
|
+
if start:
|
|
60
|
+
self.start_container(container)
|
|
61
|
+
return container
|
|
62
|
+
|
|
63
|
+
@keyword
|
|
64
|
+
def bind_ports(
|
|
65
|
+
self, container: DockerContainer, container_port: int, host_port: int
|
|
66
|
+
) -> DockerContainer:
|
|
67
|
+
container.with_bind_ports(container_port, host_port)
|
|
68
|
+
return container
|
|
69
|
+
|
|
70
|
+
@keyword
|
|
71
|
+
def start_container(self, container: DockerContainer) -> DockerContainer:
|
|
72
|
+
try:
|
|
73
|
+
container.start()
|
|
74
|
+
self._containers.append(container)
|
|
75
|
+
return container
|
|
76
|
+
except Exception:
|
|
77
|
+
container.stop()
|
|
78
|
+
raise
|
|
79
|
+
|
|
80
|
+
@keyword
|
|
81
|
+
def wait_for_log_message(
|
|
82
|
+
self, container: DockerContainer, message: str, times: int = 1
|
|
83
|
+
) -> None:
|
|
84
|
+
LogMessageWaitStrategy(message, times).wait_until_ready(container)
|
|
85
|
+
|
|
86
|
+
@keyword
|
|
87
|
+
def wait_for_http_endpoint(
|
|
88
|
+
self, container: DockerContainer, port: int, path: str
|
|
89
|
+
) -> None:
|
|
90
|
+
HttpWaitStrategy(port, path).wait_until_ready(container)
|
|
91
|
+
|
|
92
|
+
@keyword
|
|
93
|
+
def stop_container(self, container: DockerContainer) -> None:
|
|
94
|
+
self._containers.remove(container)
|
|
95
|
+
container.stop()
|
|
96
|
+
|
|
97
|
+
def _end_test(self, name, attrs) -> None:
|
|
98
|
+
for container in self._containers.copy():
|
|
99
|
+
cname = container.get_wrapped_container().name
|
|
100
|
+
logger.console(
|
|
101
|
+
f"\n\tTestcontainersLibrary: stopping container {cname} in end_test hook."
|
|
102
|
+
)
|
|
103
|
+
self.stop_container(container)
|
|
104
|
+
|
|
105
|
+
def _end_suite(self, name, attrs) -> None:
|
|
106
|
+
for container in self._containers.copy():
|
|
107
|
+
cname = container.get_wrapped_container().name
|
|
108
|
+
logger.console(
|
|
109
|
+
f"\n\tTestcontainersLibrary: stopping container {cname} in end_suite hook."
|
|
110
|
+
)
|
|
111
|
+
self.stop_container(container)
|
|
File without changes
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: robotframework-testcontainers
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Robot Framework keywords for Testcontainers.
|
|
5
|
+
Author: Andreas Finkler
|
|
6
|
+
Author-email: Andreas Finkler <andi.finkler@gmail.com>
|
|
7
|
+
Requires-Dist: robotframework>=7.3.2
|
|
8
|
+
Requires-Dist: testcontainers[generic]>=4.13.2
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Description-Content-Type: text/markdown
|
|
11
|
+
|
|
12
|
+
# robotframework-testcontainers
|
|
13
|
+
|
|
14
|
+
Robot Framework keywords for [testcontainers](https://github.com/testcontainers/testcontainers-python).
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
- using `pip`:
|
|
19
|
+
|
|
20
|
+
```shell
|
|
21
|
+
pip install robotframework-testcontainers
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
- using `uv`:
|
|
25
|
+
|
|
26
|
+
```shell
|
|
27
|
+
uv add robotframework-testcontainers
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
- using `poetry`:
|
|
31
|
+
|
|
32
|
+
```shell
|
|
33
|
+
poetry add robotframework-testcontainers
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Usage
|
|
37
|
+
|
|
38
|
+
Starting a container can be done with a single keyword:
|
|
39
|
+
|
|
40
|
+
```robot
|
|
41
|
+
*** Settings ***
|
|
42
|
+
Library TestcontainersLibrary
|
|
43
|
+
|
|
44
|
+
*** Test Cases ***
|
|
45
|
+
Basic Usage Example
|
|
46
|
+
Create Docker Container image=hello-world
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`TestcontainersLibrary` keeps track of all created containers.
|
|
50
|
+
It will take care of stopping all created containers at the end of the test,
|
|
51
|
+
by making use of the `end_test`/`end_suite` listener methods.
|
|
52
|
+
|
|
53
|
+
If you require more control, you can also manually start and stop
|
|
54
|
+
the container. Additionally, you can use different wait strategies
|
|
55
|
+
to wait for the container to be ready:
|
|
56
|
+
|
|
57
|
+
```robot
|
|
58
|
+
*** Settings ***
|
|
59
|
+
Library TestcontainersLibrary
|
|
60
|
+
|
|
61
|
+
*** Test Cases ***
|
|
62
|
+
Advanced Usage with more control
|
|
63
|
+
${container}= Create Docker Container image=traefik/whoami start=False ports=[80]
|
|
64
|
+
Start Container ${container}
|
|
65
|
+
Wait For Http Endpoint ${container} port=80 path=/api
|
|
66
|
+
Stop Container ${container}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
You can also use any of the community maintained containers.
|
|
70
|
+
Be aware that you have to make sure to install the required dependencies
|
|
71
|
+
yourself.
|
|
72
|
+
For example: starting a CockroachDB container requires installing `testcontainers[cockroachdb]`.
|
|
73
|
+
Use the `Create Community Container` keyword and specify which class to import from which module.
|
|
74
|
+
Any additional arguments can be passed in as keyword arguments.
|
|
75
|
+
|
|
76
|
+
```robot
|
|
77
|
+
*** Settings ***
|
|
78
|
+
Library TestcontainersLibrary
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
*** Test Cases ***
|
|
82
|
+
Starting an CockroachDb Container
|
|
83
|
+
${password}= Evaluate str(uuid.uuid4())
|
|
84
|
+
${container}= Create Community Container
|
|
85
|
+
... module=testcontainers.cockroachdb
|
|
86
|
+
... container_class=CockroachDBContainer
|
|
87
|
+
... username=demoUser
|
|
88
|
+
... password=${password}
|
|
89
|
+
Log ${container.get_connection_url()}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
You can read the acceptance tests in `test/acceptance/` for more concrete usage examples.
|
|
93
|
+
|
|
94
|
+
## License
|
|
95
|
+
|
|
96
|
+
This project is licensed under the [MIT License](LICENSE).
|
|
97
|
+
|
|
98
|
+
### Third-Party Licenses
|
|
99
|
+
|
|
100
|
+
This library depends on the
|
|
101
|
+
[`testcontainers-python`](https://github.com/testcontainers/testcontainers-python)
|
|
102
|
+
package, which is licensed under the
|
|
103
|
+
[Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
|
|
104
|
+
|
|
105
|
+
No parts of `testcontainers-python` are copied or modified in this project.
|
|
106
|
+
It is used only as a dependency.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
TestcontainersLibrary/__init__.py,sha256=LvjJIomJqxD4X77ehVkIrZJv1SwbLtVrgWku6xuDrs4,72
|
|
2
|
+
TestcontainersLibrary/library.py,sha256=jkN27qcR3fVxo9d6trFfAfKWD0mlYOhVM4eKHYYXctM,3699
|
|
3
|
+
TestcontainersLibrary/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
4
|
+
robotframework_testcontainers-0.1.0.dist-info/WHEEL,sha256=M6du7VZflc4UPsGphmOXHANdgk8zessdJG0DBUuoA-U,78
|
|
5
|
+
robotframework_testcontainers-0.1.0.dist-info/METADATA,sha256=Ca9qG0_Hts9w_M6Tz54RQ1bnWscC1RvPY3mGtsNuCyg,3016
|
|
6
|
+
robotframework_testcontainers-0.1.0.dist-info/RECORD,,
|