Skip to content

Commit c25e2a6

Browse files
committed
feat(n8n): add n8n workflow automation container module
Closes #901
1 parent b12ae13 commit c25e2a6

File tree

4 files changed

+98
-0
lines changed

4 files changed

+98
-0
lines changed

modules/n8n/README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.. autoclass:: testcontainers.n8n.N8nContainer
2+
.. title:: testcontainers.n8n.N8nContainer
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#
2+
# Licensed under the Apache License, Version 2.0 (the "License"); you may
3+
# not use this file except in compliance with the License. You may obtain
4+
# a copy of the License at
5+
#
6+
# http://www.apache.org/licenses/LICENSE-2.0
7+
#
8+
# Unless required by applicable law or agreed to in writing, software
9+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
10+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
11+
# License for the specific language governing permissions and limitations
12+
# under the License.
13+
14+
from http.client import HTTPException
15+
from typing import Optional
16+
from urllib.error import URLError
17+
from urllib.request import urlopen
18+
19+
from testcontainers.core.container import DockerContainer
20+
from testcontainers.core.waiting_utils import wait_container_is_ready
21+
22+
23+
class N8nContainer(DockerContainer):
24+
"""
25+
n8n workflow automation container.
26+
27+
Example:
28+
29+
.. doctest::
30+
31+
>>> from testcontainers.n8n import N8nContainer
32+
33+
>>> with N8nContainer() as n8n:
34+
... url = n8n.get_url()
35+
... assert url.startswith("http")
36+
"""
37+
38+
def __init__(
39+
self,
40+
image: str = "docker.n8n.io/n8nio/n8n:latest",
41+
port: int = 5678,
42+
encryption_key: Optional[str] = None,
43+
**kwargs,
44+
) -> None:
45+
super().__init__(image, **kwargs)
46+
self.port = port
47+
self.encryption_key = encryption_key
48+
self.with_exposed_ports(self.port)
49+
50+
def _configure(self) -> None:
51+
self.with_env("N8N_PORT", str(self.port))
52+
self.with_env("N8N_DIAGNOSTICS_ENABLED", "false")
53+
if self.encryption_key:
54+
self.with_env("N8N_ENCRYPTION_KEY", self.encryption_key)
55+
56+
def get_url(self) -> str:
57+
host = self.get_container_host_ip()
58+
port = self.get_exposed_port(self.port)
59+
return f"http://{host}:{port}"
60+
61+
def get_webhook_url(self) -> str:
62+
return f"{self.get_url()}/webhook-test"
63+
64+
@wait_container_is_ready(HTTPException, URLError, ConnectionError)
65+
def _healthcheck(self) -> None:
66+
url = f"{self.get_url()}/healthz"
67+
with urlopen(url, timeout=5) as res:
68+
if res.status > 299:
69+
raise HTTPException()
70+
71+
def start(self) -> "N8nContainer":
72+
super().start()
73+
self._healthcheck()
74+
return self

modules/n8n/tests/test_n8n.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import json
2+
from urllib.request import urlopen
3+
4+
from testcontainers.n8n import N8nContainer
5+
6+
7+
def test_docker_run_n8n():
8+
with N8nContainer("docker.n8n.io/n8nio/n8n:latest") as n8n:
9+
url = n8n.get_url()
10+
with urlopen(f"{url}/healthz") as response:
11+
assert response.status == 200
12+
data = json.loads(response.read().decode())
13+
assert data["status"] == "ok"
14+
15+
16+
def test_n8n_get_webhook_url():
17+
with N8nContainer() as n8n:
18+
webhook_url = n8n.get_webhook_url()
19+
assert "/webhook-test" in webhook_url

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ mongodb = ["pymongo>=4"]
8484
mqtt = []
8585
mssql = ["sqlalchemy>=2", "pymssql>=2"]
8686
mysql = ["sqlalchemy>=2", "pymysql[rsa]>=1"]
87+
n8n = []
8788
nats = ["nats-py>=2"]
8889
neo4j = ["neo4j>=6"]
8990
nginx = []
@@ -201,6 +202,7 @@ packages = [
201202
"modules/mqtt/testcontainers",
202203
"modules/mssql/testcontainers",
203204
"modules/mysql/testcontainers",
205+
"modules/n8n/testcontainers",
204206
"modules/nats/testcontainers",
205207
"modules/neo4j/testcontainers",
206208
"modules/nginx/testcontainers",
@@ -250,6 +252,7 @@ dev-mode-dirs = [
250252
"modules/mqtt",
251253
"modules/mssql",
252254
"modules/mysql",
255+
"modules/n8n",
253256
"modules/nats",
254257
"modules/neo4j",
255258
"modules/nginx",

0 commit comments

Comments
 (0)