Skip to content

Commit ad92aaf

Browse files
committed
feat(modules): add OpenFGA module
Add OpenFGA testcontainer module Signed-off-by: Petr Fedchenkov <[email protected]>
1 parent ef65bd1 commit ad92aaf

File tree

5 files changed

+700
-5
lines changed

5 files changed

+700
-5
lines changed

modules/openfga/README.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.. autoclass:: testcontainers.openfga.OpenFGAContainer
2+
.. title:: testcontainers.openfga.OpenFGAContainer
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
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 typing import Optional, List
15+
16+
import requests
17+
from openfga_sdk import ClientConfiguration
18+
from openfga_sdk.credentials import Credentials, CredentialConfiguration
19+
from openfga_sdk.sync import OpenFgaClient
20+
from testcontainers.core.container import DockerContainer
21+
from testcontainers.core.waiting_utils import wait_container_is_ready
22+
23+
_DEFAULT_RUN_COMMAND = "run"
24+
25+
26+
class OpenFGAContainer(DockerContainer):
27+
"""
28+
OpenFGAContainer container.
29+
30+
Example:
31+
32+
.. doctest::
33+
34+
>>> from testcontainers.openfga import OpenFGAContainer
35+
36+
>>> with OpenFGAContainer("openfga/openfga:v1.8.4") as openfga:
37+
... client = openfga.get_client()
38+
... client.list_stores()
39+
{'continuation_token': '', 'stores': []}
40+
"""
41+
42+
# pylint: disable=too-many-arguments
43+
def __init__(
44+
self,
45+
image: str = "openfga/openfga:latest",
46+
preshared_keys: Optional[List[str]] = None,
47+
playground_port: int = 3000,
48+
http_port: int = 8080,
49+
grpc_port: int = 8081,
50+
cmd: str = _DEFAULT_RUN_COMMAND,
51+
) -> None:
52+
super().__init__(image=image)
53+
self.preshared_keys = preshared_keys
54+
self.playground_port = playground_port
55+
self.http_port = http_port
56+
self.grpc_port = grpc_port
57+
self.with_exposed_ports(self.playground_port, self.http_port, self.grpc_port)
58+
self.cmd = cmd
59+
60+
def _configure(self) -> None:
61+
if self.preshared_keys:
62+
self.cmd += " --authn-method=preshared"
63+
self.cmd += f" --authn-preshared-keys=\"{','.join(self.preshared_keys)}\""
64+
self.with_command(self.cmd)
65+
66+
def get_api_url(self) -> str:
67+
host = self.get_container_host_ip()
68+
port = self.get_exposed_port(self.http_port)
69+
return f"http://{host}:{port}"
70+
71+
@wait_container_is_ready(requests.exceptions.ConnectionError, requests.exceptions.ReadTimeout)
72+
def _readiness_probe(self) -> None:
73+
self.exec(["grpc_health_probe", "-addr=0.0.0.0:8081"]) # from chart
74+
75+
def start(self) -> "OpenFGAContainer":
76+
super().start()
77+
self._readiness_probe()
78+
return self
79+
80+
def get_preshared_keys(self) -> Optional[List[str]]:
81+
return self.preshared_keys
82+
83+
def get_client(self) -> OpenFgaClient:
84+
credentials = None
85+
if preshared_keys := self.get_preshared_keys():
86+
credentials = Credentials(
87+
method='api_token',
88+
configuration=CredentialConfiguration(
89+
api_token=preshared_keys[0],
90+
),
91+
)
92+
client_configuration = ClientConfiguration(api_url=self.get_api_url(), credentials=credentials)
93+
return OpenFgaClient(client_configuration)

modules/openfga/tests/test_openfga.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from testcontainers.openfga import OpenFGAContainer
2+
3+
def test_openfga():
4+
with OpenFGAContainer("openfga/openfga:v1.8.4") as openfga:
5+
client = openfga.get_client()
6+
assert client
7+
assert client.list_stores()

0 commit comments

Comments
 (0)