Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mydiracx extension extensions/src/mydiracx #124

Closed
wants to merge 49 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
0ffffc3
mydiracx extension extensions/src/mydiracx
ruslan33 Oct 3, 2023
8f8a7d5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Oct 3, 2023
e363d9e
Dummy mydiracx extension
ruslan33 Jan 24, 2024
bd2df97
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 24, 2024
14fe687
Fix for setuptools
ruslan33 Mar 29, 2024
f483217
Import Dummy DB
ruslan33 Mar 29, 2024
4a33760
test db
ruslan33 Apr 2, 2024
7215060
extension add insert functions in routers
ruslan33 Apr 3, 2024
38e08a8
Bug fix
ruslan33 Apr 3, 2024
a4824c5
Bug fix
ruslan33 Apr 3, 2024
8d4cf9d
Test
ruslan33 Apr 3, 2024
81d18be
Bug fix in sql return
ruslan33 Apr 3, 2024
a489407
Add more APIs
ruslan33 Apr 9, 2024
ab8101c
Fix
ruslan33 Apr 9, 2024
36f7f9f
Add API. Change order of the APIs
ruslan33 Apr 9, 2024
e48343a
Fix
ruslan33 Apr 9, 2024
074026b
Add authorization to the APIs
ruslan33 Apr 9, 2024
c6bf97f
Fix imports
ruslan33 Apr 9, 2024
8a1b9ae
Fix
ruslan33 Apr 9, 2024
9797073
Fix imports
ruslan33 Apr 9, 2024
12c6f02
Fix for auth
ruslan33 Apr 9, 2024
f5f4cf2
Cleanup
ruslan33 Apr 9, 2024
90a4580
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 9, 2024
7ba9ae2
Remove unneccessary imports
ruslan33 Apr 9, 2024
b76a1f6
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 9, 2024
40abac9
Cleanup
ruslan33 Apr 9, 2024
eb52b64
Fix and cleanup
ruslan33 Apr 9, 2024
da1a188
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 9, 2024
8de3c1a
Cleanup
ruslan33 Apr 10, 2024
0d0fa38
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 10, 2024
d424d81
Add functional tests
ruslan33 Apr 10, 2024
01b43f1
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Apr 10, 2024
895a591
Create extensions.yml
ruslan33 Apr 10, 2024
e366569
Update extensions.yml
ruslan33 Apr 10, 2024
fac28e3
Update extensions.yml
ruslan33 Apr 10, 2024
54166c6
Update extensions.yml
ruslan33 Apr 10, 2024
be09d5e
Update extensions.yml
ruslan33 Apr 10, 2024
1e86a6e
Update extensions.yml
ruslan33 Apr 10, 2024
f0232e6
Update extensions.yml
ruslan33 Apr 10, 2024
798b254
Fix
ruslan33 Apr 10, 2024
951b48b
fix for the tests
ruslan33 Apr 10, 2024
31e426d
Update extensions.yml
ruslan33 Apr 10, 2024
8cd3b0a
Update extensions.yml
ruslan33 Apr 10, 2024
93be03d
Update extensions.yml
ruslan33 Apr 10, 2024
799b2a4
Update extensions.yml
ruslan33 Apr 10, 2024
2423e81
Update extensions.yml
ruslan33 Apr 11, 2024
f4a494a
Update extensions.yml
ruslan33 Apr 11, 2024
847b4b1
Update extensions.yml
ruslan33 Apr 11, 2024
3164055
Update extensions.yml
ruslan33 Apr 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions .github/workflows/extensions.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
name: Extensions Basic Tests

on:
push:
branches:
- main
- mydiracx-extension
pull_request:
branches:
- main


defaults:
run:
shell: bash -el {0}

jobs:
pytest:
name: Unit test - ${{ matrix.package }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- package: "./diracx-db"
dependencies: "./diracx-testing ./diracx-core"
- package: "./diracx-routers"
dependencies: "./diracx-testing ./diracx-core ./diracx-db"
- package: "./diracx-client"
dependencies: "./diracx-testing ./diracx-core"
- package: "./diracx-api"
dependencies: "./diracx-testing ./diracx-core ./diracx-client"
- package: "./diracx-cli"
dependencies: "./diracx-testing ./diracx-core ./diracx-client ./diracx-api"
- package: "./extensions/mydiracx/mydiracx-db"
dependencies: "./diracx-testing ./diracx-core ./diracx-db"
- package: "./extensions/mydiracx/mydiracx-routers"
dependencies: "./diracx-testing ./diracx-core ./diracx-db ./diracx-routers ./extensions/mydiracx/mydiracx-db"

steps:
- name: Checkout code
uses: actions/checkout@v4
- uses: mamba-org/setup-micromamba@v1
with:
# TODO: Use a conda environment file used for the diracx/base container image
environment-name: test-env
create-args: >-
python=3.11
m2crypto
python-gfal2
mypy
pip
init-shell: bash
post-cleanup: 'all'
- name: Set up environment
run: |
pip install pytest-github-actions-annotate-failures
pip install git+https://github.com/DIRACGrid/DIRAC.git@integration
pip install 'git+https://github.com/ruslan33/diracx.git@mydiracx-extension#egg=mydiracx-db&subdirectory=extensions/mydiracx/mydiracx-db'
pip install 'git+https://github.com/ruslan33/diracx.git@mydiracx-extension#egg=mydiracx-routers&subdirectory=extensions/mydiracx/mydiracx-routers'
pip install 'git+https://github.com/ruslan33/diracx.git@mydiracx-extension#egg=mydiracx&subdirectory=extensions/mydiracx'
pip install ${{ matrix.dependencies }} ${{ matrix.package }}[types]
- name: Run mypy
run: |
mypy ${{ matrix.package }}/src
- name: Run pytest
run: |
cd ${{ matrix.package }}
pip install .[testing]
pytest --cov-report=xml:coverage.xml --junitxml=report.xml
- name: Upload coverage report
uses: codecov/[email protected]
10 changes: 10 additions & 0 deletions extensions/docker/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM ghcr.io/diracgrid/diracx/services:dev

#Extension
ARG MAMBA_DOCKERFILE_ACTIVATE=1
ENV DIRACX_EXTENSIONS "mydiracx,diracx"
ENV DIRACX_DB_URL_DUMMYDB "sqlite+aiosqlite:///:memory:"

RUN pip install 'git+https://github.com/ruslan33/diracx.git@mydiracx-extension#egg=mydiracx-db&subdirectory=extensions/mydiracx/mydiracx-db'
RUN pip install 'git+https://github.com/ruslan33/diracx.git@mydiracx-extension#egg=mydiracx-routers&subdirectory=extensions/mydiracx/mydiracx-routers'
RUN pip install 'git+https://github.com/ruslan33/diracx.git@mydiracx-extension#egg=mydiracx&subdirectory=extensions/mydiracx'
54 changes: 54 additions & 0 deletions extensions/mydiracx/mydiracx-db/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
[project]
name = "mydiracx-db"
description = "TODO"
readme = "README.md"
requires-python = ">=3.10"
keywords = []
license = {text = "GPL-3.0-only"}
classifiers = [
"Intended Audience :: Science/Research",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering",
"Topic :: System :: Distributed Computing",
]
dependencies = [
"dirac",
"diracx-core",
"fastapi",
"opensearch-py[async]",
"pydantic",
"sqlalchemy[aiomysql,aiosqlite]",
]
dynamic = ["version"]

[project.optional-dependencies]
testing = [
"diracx-testing",
]

[project.entry-points."diracx.db.sql"]
DummyDB = "mydiracx.db.sql:DummyDB"

[tool.setuptools.packages.find]
where = ["src"]

[build-system]
requires = ["setuptools>=61", "wheel", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
root = "../../.."

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
"-v",
"--cov=diracx.db", "--cov-report=term-missing",
"-pdiracx.testing", "-pdiracx.testing.osdb",
"--import-mode=importlib",
]
asyncio_mode = "auto"
markers = [
"enabled_dependencies: List of dependencies which should be available to the FastAPI test client",
]
5 changes: 5 additions & 0 deletions extensions/mydiracx/mydiracx-db/src/mydiracx/db/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from __future__ import annotations

__all__ = ("sql",)

from . import sql
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from __future__ import annotations

__all__ = ("DummyDB",)

from .dummy.db import DummyDB
Empty file.
64 changes: 64 additions & 0 deletions extensions/mydiracx/mydiracx-db/src/mydiracx/db/sql/dummy/db.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
from __future__ import annotations

from uuid import UUID

from diracx.db.sql.utils import BaseSQLDB, apply_search_filters
from sqlalchemy import func, insert, select

from .schema import Base as DummyDBBase
from .schema import Cars, Owners


class DummyDB(BaseSQLDB):
"""
This DummyDB is just to illustrate some important aspect of writing
DB classes in DiracX.

It is mostly pure SQLAlchemy, with a few convention

Document the secrets
"""

# This needs to be here for the BaseSQLDB to create the engine
metadata = DummyDBBase.metadata

async def summary(self, group_by, search) -> list[dict[str, str | int]]:
columns = [Cars.__table__.columns[x] for x in group_by]

stmt = select(*columns, func.count(Cars.licensePlate).label("count"))
stmt = apply_search_filters(Cars.__table__, stmt, search)
stmt = stmt.group_by(*columns)

# Execute the query
return [
dict(row._mapping)
async for row in (await self.conn.stream(stmt))
if row.count > 0 # type: ignore
]

async def insert_owner(self, name: str) -> int:
stmt = insert(Owners).values(name=name)
result = await self.conn.execute(stmt)
# await self.engine.commit()
return result.lastrowid

async def get_owner(self) -> list[str]:
stmt = select(Owners.name)
result = await self.conn.execute(stmt)
# await self.engine.commit()
return [row[0] for row in result]

async def insert_car(self, license_plate: UUID, model: str, owner_id: int) -> int:
stmt = insert(Cars).values(
licensePlate=license_plate, model=model, ownerID=owner_id
)

result = await self.conn.execute(stmt)
# await self.engine.commit()
return result.lastrowid

async def get_car(self) -> list[str]:
stmt = select(Cars.model)
result = await self.conn.execute(stmt)
# await self.engine.commit()
return [row[0] for row in result]
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# The utils class define some boilerplate types that should be used
# in place of the SQLAlchemy one. Have a look at them
from diracx.db.sql.utils import Column, DateNowColumn
from sqlalchemy import ForeignKey, Integer, String, Uuid
from sqlalchemy.orm import declarative_base

Base = declarative_base()


class Owners(Base):
__tablename__ = "Owners"
ownerID = Column(Integer, primary_key=True, autoincrement=True)
creation_time = DateNowColumn()
name = Column(String(255))


class Cars(Base):
__tablename__ = "Cars"
licensePlate = Column(Uuid(), primary_key=True)
model = Column(String(255))
ownerID = Column(Integer, ForeignKey(Owners.ownerID))
78 changes: 78 additions & 0 deletions extensions/mydiracx/mydiracx-db/tests/test_dummyDB.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
from __future__ import annotations

import asyncio
from uuid import uuid4

import pytest
from diracx.core.exceptions import InvalidQueryError
from diracx.db.sql.utils import SQLDBUnavailable

from mydiracx.db.sql.dummy.db import DummyDB

# Each DB test class must defined a fixture looking like this one
# It allows to get an instance of an in memory DB,


@pytest.fixture
async def dummy_db(tmp_path) -> DummyDB:
dummy_db = DummyDB("sqlite+aiosqlite:///:memory:")
async with dummy_db.engine_context():
async with dummy_db.engine.begin() as conn:
await conn.run_sync(dummy_db.metadata.create_all)
yield dummy_db


async def test_insert_and_summary(dummy_db: DummyDB):
# Each context manager creates a transaction
# So it is important to write test this way
async with dummy_db as dummy_db:
# First we check that the DB is empty
result = await dummy_db.summary(["model"], [])
assert not result

# Now we add some data in the DB
async with dummy_db as dummy_db:
# Add a car owner
owner_id = await dummy_db.insert_owner(name="Magnum")
assert owner_id

# Add cars, belonging to the same guy
result = await asyncio.gather(
*(dummy_db.insert_car(uuid4(), f"model_{i}", owner_id) for i in range(10))
)
assert result

# Check that there are now 10 cars assigned to a single driver
async with dummy_db as dummy_db:
result = await dummy_db.summary(["ownerID"], [])

assert result[0]["count"] == 10

# Test the selection
async with dummy_db as dummy_db:
result = await dummy_db.summary(
["ownerID"], [{"parameter": "model", "operator": "eq", "value": "model_1"}]
)

assert result[0]["count"] == 1

async with dummy_db as dummy_db:
with pytest.raises(InvalidQueryError):
result = await dummy_db.summary(
["ownerID"],
[
{
"parameter": "model",
"operator": "BADSELECTION",
"value": "model_1",
}
],
)


async def test_bad_connection():
dummy_db = DummyDB("mysql+aiomysql://tata:[email protected]:3306/name")
async with dummy_db.engine_context():
with pytest.raises(SQLDBUnavailable):
async with dummy_db:
dummy_db.ping()
72 changes: 72 additions & 0 deletions extensions/mydiracx/mydiracx-routers/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
[project]
name = "mydiracx-routers"
description = "TODO"
readme = "README.md"
requires-python = ">=3.10"
keywords = []
license = {text = "GPL-3.0-only"}
classifiers = [
"Intended Audience :: Science/Research",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Programming Language :: Python :: 3",
"Topic :: Scientific/Engineering",
"Topic :: System :: Distributed Computing",
]
dependencies = [
"aiobotocore",
"authlib",
"botocore",
"cachetools",
"dirac",
"diracx-core",
"diracx-db",
"python-dotenv", # TODO: We might not need this
"python-multipart",
"fastapi",
"httpx",
"pydantic",
"sqlalchemy",
]
dynamic = ["version"]

[project.optional-dependencies]
testing = [
"diracx-testing",
"moto[server]",
"pytest-httpx",
]
types = [
"boto3-stubs",
"types-aiobotocore[essential]",
"types-aiobotocore-s3",
"types-cachetools",
"types-python-dateutil",
"types-PyYAML",
"types-requests",
]

[project.entry-points."diracx.services"]
mymanager = "mydiracx.routers.mymanager:router"

[tool.setuptools.packages.find]
where = ["src"]

[build-system]
requires = ["setuptools>=61", "wheel", "setuptools_scm>=8"]
build-backend = "setuptools.build_meta"

[tool.setuptools_scm]
root = "../../.."

[tool.pytest.ini_options]
testpaths = ["tests"]
addopts = [
"-v",
"--cov=diracx.routers", "--cov-report=term-missing",
"-pdiracx.testing", "-pdiracx.testing.osdb",
"--import-mode=importlib",
]
asyncio_mode = "auto"
markers = [
"enabled_dependencies: List of dependencies which should be available to the FastAPI test client",
]
Loading
Loading