Skip to content

Commit 08cb887

Browse files
authored
Merge pull request #48 from neo4j/gds-integration-test
gds integration test
2 parents 4bf485f + 7146a4c commit 08cb887

File tree

7 files changed

+123
-20
lines changed

7 files changed

+123
-20
lines changed

.github/workflows/code-style.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
branches: [ "main" ]
88
pull_request:
99
paths:
10-
- "python-wrapper/src/neo4j_viz/**" # python code + its resources
10+
- "python-wrapper/**" # python code + its resources
1111
branches: [ "main" ]
1212

1313
# Allows you to run this workflow manually from the Actions tab
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: Run GDS integration tests
2+
3+
# Controls when the workflow will run
4+
on:
5+
# Triggers the workflow on push or pull request events but only for the "main" branch
6+
push:
7+
branches: [ "main" ]
8+
# Skip on this check PR to reduce number of AuraDS instances created
9+
10+
# Allows you to run this workflow manually from the Actions tab
11+
workflow_dispatch:
12+
13+
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
14+
jobs:
15+
tests:
16+
# The type of runner that the job will run on
17+
runs-on: ${{ matrix.os}}
18+
strategy:
19+
fail-fast: false
20+
matrix:
21+
os: [ubuntu-latest]
22+
defaults:
23+
run:
24+
working-directory: python-wrapper
25+
26+
# Steps represent a sequence of tasks that will be executed as part of the job
27+
steps:
28+
- uses: actions/checkout@v4
29+
30+
- uses: actions/setup-python@v5
31+
with:
32+
python-version: "3.12"
33+
cache: 'pip'
34+
cache-dependency-path: pyproject.toml
35+
- run: pip install ".[dev]"
36+
- run: pip install ".[pandas]"
37+
- run: pip install ".[gds]"
38+
39+
- name: Run tests
40+
env:
41+
AURA_API_CLIENT_ID: 4V1HYCYEeoU4dSxThKnBeLvE2U4hSphx
42+
AURA_API_CLIENT_SECRET: ${{ secrets.AURA_API_CLIENT_SECRET }}
43+
AURA_API_TENANT_ID: eee7ec28-6b1a-5286-8e3a-3362cc1c4c78
44+
run: pytest tests/ --include-neo4j-and-gds -Werror

.github/workflows/unit-tests.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ on:
77
branches: [ "main" ]
88
pull_request:
99
paths:
10-
- "python-wrapper/src/neo4j_viz/**" # python code + its resources
10+
- "python-wrapper/**" # python code + its resources
1111
- "python-wrapper/pyproject.toml" # dependencies
1212
branches: [ "main" ]
1313

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Environments
22
.env
3+
*.env
34
.venv
45
env/
56
venv/

python-wrapper/tests/conftest.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
from typing import Any
1+
import os
2+
from typing import Any, Generator
23

34
import pytest
45

@@ -17,3 +18,27 @@ def pytest_collection_modifyitems(config: Any, items: Any) -> None:
1718
for item in items:
1819
if "requires_neo4j_and_gds" in item.keywords:
1920
item.add_marker(skip)
21+
22+
23+
@pytest.fixture(scope="package")
24+
def gds() -> Generator[Any, None, None]:
25+
from gds_helper import aura_api, connect_to_plugin_gds, create_aurads_instance
26+
from graphdatascience import GraphDataScience
27+
28+
NEO4J_URI = os.environ.get("NEO4J_URI")
29+
30+
if NEO4J_URI:
31+
gds = connect_to_plugin_gds(NEO4J_URI)
32+
yield gds
33+
gds.close()
34+
else:
35+
api = aura_api()
36+
id, dbms_connection_info = create_aurads_instance(api)
37+
yield GraphDataScience(
38+
endpoint=dbms_connection_info.uri,
39+
auth=(dbms_connection_info.username, dbms_connection_info.password),
40+
aura_ds=True,
41+
database="neo4j",
42+
)
43+
44+
api.delete_instance(id)

python-wrapper/tests/gds_helper.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import os
2+
3+
from graphdatascience import GraphDataScience
4+
from graphdatascience.session import DbmsConnectionInfo, SessionMemory
5+
from graphdatascience.session.aura_api import AuraApi
6+
from graphdatascience.session.aura_api_responses import InstanceCreateDetails
7+
8+
9+
def connect_to_plugin_gds(uri: str) -> GraphDataScience:
10+
NEO4J_AUTH = ("neo4j", "password")
11+
if os.environ.get("NEO4J_USER"):
12+
NEO4J_AUTH = (os.environ.get("NEO4J_USER", "DUMMY"), os.environ.get("NEO4J_PASSWORD", "neo4j"))
13+
14+
return GraphDataScience(endpoint=uri, auth=NEO4J_AUTH, database="neo4j")
15+
16+
17+
def aura_api() -> AuraApi:
18+
return AuraApi(
19+
client_id=os.environ["AURA_API_CLIENT_ID"],
20+
client_secret=os.environ["AURA_API_CLIENT_SECRET"],
21+
tenant_id=os.environ.get("AURA_API_TENANT_ID"),
22+
)
23+
24+
25+
def create_aurads_instance(api: AuraApi) -> tuple[str, DbmsConnectionInfo]:
26+
# Switch to Sessions once they can be created without a DB
27+
instance_details: InstanceCreateDetails = api.create_instance(
28+
name="ci-neo4j-viz-session",
29+
memory=SessionMemory.m_8GB.value,
30+
cloud_provider="gcp",
31+
region="europe-west1",
32+
)
33+
34+
wait_result = api.wait_for_instance_running(instance_id=instance_details.id)
35+
if wait_result.error:
36+
raise Exception(f"Error while waiting for instance to be running: {wait_result.error}")
37+
38+
wait_result.connection_url
39+
40+
return instance_details.id, DbmsConnectionInfo(
41+
uri=wait_result.connection_url,
42+
username="neo4j",
43+
password=instance_details.password,
44+
)

python-wrapper/tests/test_gds.py

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,22 @@
1-
import os
21
import sys
2+
from typing import Any
33

44
import pandas as pd
55
import pytest
66
from pytest_mock import MockerFixture
77

88
from neo4j_viz import Node
99

10-
NEO4J_URI = os.environ.get("NEO4J_URI", "bolt://localhost:7687")
11-
12-
NEO4J_AUTH = ("neo4j", "password")
13-
if os.environ.get("NEO4J_USER"):
14-
NEO4J_AUTH = (
15-
os.environ.get("NEO4J_USER", "DUMMY"),
16-
os.environ.get("NEO4J_PASSWORD", "neo4j"),
17-
)
18-
1910

2011
@pytest.mark.skipif(sys.version_info >= (3, 13), reason="requires python 3.12 or lower")
2112
@pytest.mark.requires_neo4j_and_gds
22-
def test_from_gds_integration() -> None:
23-
from graphdatascience import GraphDataScience
24-
13+
def test_from_gds_integration(gds: Any) -> None:
2514
from neo4j_viz.gds import from_gds
2615

2716
nodes = pd.DataFrame(
2817
{
2918
"nodeId": [0, 1, 2],
30-
"labels": ["A", "C", ["A", "B"]],
19+
"labels": [["A"], ["C"], ["A", "B"]],
3120
"score": [1337, 42, 3.14],
3221
"component": [1, 4, 2],
3322
}
@@ -40,10 +29,10 @@ def test_from_gds_integration() -> None:
4029
}
4130
)
4231

43-
gds = GraphDataScience(NEO4J_URI, auth=NEO4J_AUTH)
44-
4532
with gds.graph.construct("flo", nodes, rels) as G:
46-
VG = from_gds(gds, G, size_property="score", additional_node_properties=["component"])
33+
VG = from_gds(
34+
gds, G, size_property="score", additional_node_properties=["component"], node_radius_min_max=(3.14, 1337)
35+
)
4736

4837
assert len(VG.nodes) == 3
4938
assert sorted(VG.nodes, key=lambda x: x.id) == [

0 commit comments

Comments
 (0)