Skip to content

Commit f6336c5

Browse files
authored
Feat/add tests (#2813)
* add test for: - gn_meta/repositories - gn_meta/mtd - occtax - occhab - utilstoml - install-gn-module commands * Change fixtures: datasets + stations + user * (fix) remove deprecated and unused modules (utilsgeometry, utilssqlalchemy)
1 parent a192943 commit f6336c5

File tree

18 files changed

+1157
-1348
lines changed

18 files changed

+1157
-1348
lines changed

backend/geonature/core/command/create_gn_module.py

+34-16
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,56 @@
1+
import importlib
12
import os
2-
import sys
3-
import subprocess
43
import site
5-
import importlib
4+
import subprocess
5+
import sys
66
from pathlib import Path
77

88
import click
9+
import geonature.utils.config
910
from click import ClickException
10-
11-
from geonature.utils.env import ROOT_DIR
12-
from geonature.utils.module import iter_modules_dist, get_dist_from_code, module_db_upgrade
13-
1411
from geonature.core.command.main import main
15-
import geonature.utils.config
16-
from geonature.utils.config import config
1712
from geonature.utils.command import (
18-
install_frontend_dependencies,
19-
create_frontend_module_config,
2013
build_frontend,
14+
create_frontend_module_config,
15+
install_frontend_dependencies,
2116
)
17+
from geonature.utils.config import config
18+
from geonature.utils.env import ROOT_DIR
19+
from geonature.utils.module import get_dist_from_code, iter_modules_dist, module_db_upgrade
2220

2321

2422
@main.command()
2523
@click.option(
2624
"-x", "--x-arg", multiple=True, help="Additional arguments consumed by custom env.py scripts"
2725
)
28-
@click.argument("module_path", type=click.Path(exists=True, file_okay=False, path_type=Path))
26+
@click.argument("module_path", type=click.Path(path_type=Path))
2927
@click.argument("module_code", required=False)
3028
@click.option("--build", type=bool, required=False, default=True)
3129
@click.option("--upgrade-db", type=bool, required=False, default=True)
3230
def install_gn_module(x_arg, module_path, module_code, build, upgrade_db):
31+
"""
32+
Command definition to install a GeoNature module
33+
34+
Parameters
35+
----------
36+
x_arg : list
37+
additional arguments
38+
module_path : str
39+
path of the module directory
40+
module_code : str
41+
code of the module, deprecated in future release
42+
build : boolean
43+
is the frontend rebuild
44+
upgrade_db : boolean
45+
migrate the revision associated with the module
46+
47+
Raises
48+
------
49+
ClickException
50+
No module found with the given module code
51+
ClickException
52+
No module code was detected in the code
53+
"""
3354
click.echo("Installation du backend…")
3455
subprocess.run(f"pip install -e '{module_path}'", shell=True, check=True)
3556

@@ -40,7 +61,7 @@ def install_gn_module(x_arg, module_path, module_code, build, upgrade_db):
4061
if module_code:
4162
# load python package
4263
module_dist = get_dist_from_code(module_code)
43-
if not module_dist:
64+
if not module_dist: # FIXME : technically can't go there...
4465
raise ClickException(f"Aucun module ayant pour code {module_code} n’a été trouvé")
4566
else:
4667
for module_dist in iter_modules_dist():
@@ -56,7 +77,6 @@ def install_gn_module(x_arg, module_path, module_code, build, upgrade_db):
5677
raise ClickException(
5778
f"Impossible de détecter le code du module, essayez de le spécifier."
5879
)
59-
6080
# symlink module in exernal module directory
6181
module_frontend_path = (module_path / "frontend").resolve()
6282
module_symlink = ROOT_DIR / "frontend" / "external_modules" / module_code.lower()
@@ -68,7 +88,6 @@ def install_gn_module(x_arg, module_path, module_code, build, upgrade_db):
6888
else:
6989
click.echo(f"Création du lien symbolique {module_symlink}{module_frontend_path}")
7090
os.symlink(module_frontend_path, module_symlink)
71-
7291
if (Path(module_path) / "frontend" / "package-lock.json").is_file():
7392
click.echo("Installation des dépendances frontend…")
7493
install_frontend_dependencies(module_frontend_path)
@@ -80,7 +99,6 @@ def install_gn_module(x_arg, module_path, module_code, build, upgrade_db):
8099
click.echo("Rebuild du frontend …")
81100
build_frontend()
82101
click.secho("Rebuild du frontend terminé.", fg="green")
83-
84102
if upgrade_db:
85103
click.echo("Installation / mise à jour de la base de données…")
86104
if not module_db_upgrade(module_dist, x_arg=x_arg):

backend/geonature/core/gn_commons/validation/routes.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import logging
2+
import uuid
23

34
from werkzeug.exceptions import BadRequest
45

@@ -9,20 +10,31 @@
910
from geonature.core.gn_commons.models import TValidations
1011
from geonature.core.gn_permissions import decorators as permissions
1112
from geonature.utils.env import DB
12-
from geonature.utils.utilssqlalchemy import test_is_uuid
1313

1414

1515
from ..routes import routes
1616

1717
log = logging.getLogger()
1818

1919

20+
def is_uuid(uuid_string):
21+
try:
22+
# Si uuid_string est un code hex valide mais pas un uuid valid,
23+
# UUID() va quand même le convertir en uuid valide. Pour se prémunir
24+
# de ce problème, on check la version original (sans les tirets) avec
25+
# le code hex généré qui doivent être les mêmes.
26+
uid = uuid.UUID(uuid_string)
27+
return uid.hex == uuid_string.replace("-", "")
28+
except ValueError:
29+
return False
30+
31+
2032
@routes.route("/history/<uuid_attached_row>", methods=["GET"])
2133
@permissions.check_cruved_scope("R", module_code="SYNTHESE")
2234
@json_resp
2335
def get_hist(uuid_attached_row):
2436
# Test if uuid_attached_row is uuid
25-
if not test_is_uuid(uuid_attached_row):
37+
if not is_uuid(uuid_attached_row):
2638
raise BadRequest("Value error uuid_attached_row is not valid")
2739
"""
2840
Here we use execute() instead of scalars() because

backend/geonature/core/gn_meta/repositories.py

+76-51
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22

3-
from sqlalchemy import or_, String, Date, and_
3+
from sqlalchemy import or_, String, Date, and_, func
44
from sqlalchemy.inspection import inspect
55
from sqlalchemy.orm import joinedload, contains_eager, aliased
66
from sqlalchemy.orm.exc import NoResultFound
@@ -32,13 +32,16 @@
3232

3333

3434
def cruved_ds_filter(model, role, scope):
35+
# TODO check if not used elsewhere (not found in major module of Geonature)
3536
if scope not in (1, 2, 3):
3637
raise Unauthorized("Not a valid cruved value")
3738
elif scope == 3:
3839
return True
3940
elif scope in (1, 2):
40-
sub_q = DB.select(TDatasets).join(
41-
CorDatasetActor, TDatasets.id_dataset == CorDatasetActor.id_dataset
41+
sub_q = (
42+
DB.select(func.count("*"))
43+
.select_from(TDatasets)
44+
.join(CorDatasetActor, TDatasets.id_dataset == CorDatasetActor.id_dataset)
4245
)
4346

4447
or_filter = [
@@ -49,10 +52,8 @@ def cruved_ds_filter(model, role, scope):
4952
# if organism is None => do not filter on id_organism even if level = 2
5053
if scope == 2 and role.id_organisme is not None:
5154
or_filter.append(CorDatasetActor.id_organism == role.id_organisme)
52-
sub_q = sub_q.filter(and_(or_(*or_filter), model.id_dataset == TDatasets.id_dataset))
53-
return sub_q.exists()
54-
55-
return True
55+
sub_q = sub_q.where(and_(or_(*or_filter), model.id_dataset == TDatasets.id_dataset))
56+
return DB.session.execute(sub_q).scalar_one() > 0
5657

5758

5859
def cruved_af_filter(model, role, scope):
@@ -61,10 +62,14 @@ def cruved_af_filter(model, role, scope):
6162
elif scope == 3:
6263
return True
6364
elif scope in (1, 2):
64-
sub_q = DB.select(TAcquisitionFramework).join(
65-
CorAcquisitionFrameworkActor,
66-
TAcquisitionFramework.id_acquisition_framework
67-
== CorAcquisitionFrameworkActor.id_acquisition_framework,
65+
sub_q = (
66+
DB.select(func.count("*"))
67+
.select_from(TAcquisitionFramework)
68+
.join(
69+
CorAcquisitionFrameworkActor,
70+
TAcquisitionFramework.id_acquisition_framework
71+
== CorAcquisitionFrameworkActor.id_acquisition_framework,
72+
)
6873
)
6974

7075
or_filter = [
@@ -81,33 +86,23 @@ def cruved_af_filter(model, role, scope):
8186
model.id_acquisition_framework == TAcquisitionFramework.id_acquisition_framework,
8287
)
8388
)
84-
return sub_q.exists()
89+
return DB.session.execute(sub_q).scalar_one() > 0
8590

8691

8792
def get_metadata_list(role, scope, args, exclude_cols):
88-
num = args.get("num")
89-
uuid = args.get("uuid")
90-
name = args.get("name")
91-
date = args.get("date")
92-
organisme = args.get("organism")
93-
person = args.get("person")
93+
id_acquisition_framework = args.get("num")
94+
unique_acquisition_framework_id = args.get("uuid")
95+
acquisition_framework_name = args.get("name")
96+
meta_create_date = args.get("date")
97+
id_organism = args.get("organism")
98+
id_role = args.get("person")
9499
selector = args.get("selector")
95100
is_parent = args.get("is_parent")
101+
order_by = args.get("orderby", None)
96102

97-
# @TODO : replace by select
98-
query = DB.session.query(TAcquisitionFramework)
99-
100-
if is_parent is not None:
101-
query = query.where(TAcquisitionFramework.is_parent)
102-
103-
if selector == "af" and set(["organism", "person"]).intersection(args):
104-
query = query.join(
105-
CorAcquisitionFrameworkActor,
106-
TAcquisitionFramework.id_acquisition_framework
107-
== CorAcquisitionFrameworkActor.id_acquisition_framework,
108-
)
109-
# remove cor_af_actor from joined load because already joined
110-
exclude_cols.append("cor_af_actor")
103+
query = DB.select(TAcquisitionFramework).where_if(
104+
is_parent is not None, TAcquisitionFramework.is_parent
105+
)
111106

112107
if selector == "ds":
113108
query = query.join(
@@ -132,44 +127,74 @@ def get_metadata_list(role, scope, args, exclude_cols):
132127
cruved_ds_filter(TDatasets, role, scope),
133128
)
134129
)
135-
if args.get("selector") == "af":
130+
if selector == "af":
131+
if set(["organism", "person"]).intersection(args):
132+
query = query.join(
133+
CorAcquisitionFrameworkActor,
134+
TAcquisitionFramework.id_acquisition_framework
135+
== CorAcquisitionFrameworkActor.id_acquisition_framework,
136+
)
137+
# remove cor_af_actor from joined load because already joined
138+
exclude_cols.append("cor_af_actor")
136139
query = (
137-
query.where(TAcquisitionFramework.id_acquisition_framework == num if num else True)
140+
query.where(
141+
TAcquisitionFramework.id_acquisition_framework == id_acquisition_framework
142+
if id_acquisition_framework
143+
else True
144+
)
138145
.where(
139146
cast(TAcquisitionFramework.unique_acquisition_framework_id, String).ilike(
140-
f"%{uuid.strip()}%"
147+
f"%{unique_acquisition_framework_id.strip()}%"
141148
)
142-
if uuid
149+
if unique_acquisition_framework_id
143150
else True
144151
)
145152
.where(
146-
TAcquisitionFramework.acquisition_framework_name.ilike(f"%{name}%")
147-
if name
153+
TAcquisitionFramework.acquisition_framework_name.ilike(
154+
f"%{acquisition_framework_name}%"
155+
)
156+
if acquisition_framework_name
148157
else True
149158
)
150-
.where(CorAcquisitionFrameworkActor.id_organism == organisme if organisme else True)
151-
.where(CorAcquisitionFrameworkActor.id_role == person if person else True)
159+
.where(
160+
CorAcquisitionFrameworkActor.id_organism == id_organism if id_organism else True
161+
)
162+
.where(CorAcquisitionFrameworkActor.id_role == id_role if id_role else True)
152163
)
153164

154-
elif args.get("selector") == "ds":
165+
elif selector == "ds":
155166
query = (
156-
query.where(TDatasets.id_dataset == num if num else True)
167+
query.where(
168+
TDatasets.id_dataset == id_acquisition_framework
169+
if id_acquisition_framework
170+
else True
171+
)
172+
.where(
173+
cast(TDatasets.unique_dataset_id, String).ilike(
174+
f"%{unique_acquisition_framework_id.strip()}%"
175+
)
176+
if unique_acquisition_framework_id
177+
else True
178+
)
179+
.where(
180+
TAcquisitionFramework.datasets.any(dataset_name=acquisition_framework_name)
181+
if acquisition_framework_name
182+
else True
183+
)
157184
.where(
158-
cast(TDatasets.unique_dataset_id, String).ilike(f"%{uuid.strip()}%")
159-
if uuid
185+
cast(TDatasets.meta_create_date, Date) == meta_create_date
186+
if meta_create_date
160187
else True
161188
)
162-
.where(TAcquisitionFramework.datasets.any(dataset_name=name) if name else True)
163-
.where(cast(TDatasets.meta_create_date, Date) == date if date else True)
164-
.where(CorDatasetActor.id_organism == organisme if organisme else True)
165-
.where(CorDatasetActor.id_role == person if person else True)
189+
.where(CorDatasetActor.id_organism == id_organism if id_organism else True)
190+
.where(CorDatasetActor.id_role == id_role if id_role else True)
166191
)
167192

168-
if args.get("orderby", None):
193+
if order_by:
169194
try:
170-
query = query.order_by(getattr(TAcquisitionFramework, args.get("orderby")).asc())
195+
query = query.order_by(getattr(TAcquisitionFramework, order_by).asc())
171196
except:
172-
query = query.order_by(getattr(TDatasets, args.get("orderby")).asc())
197+
query = query.order_by(getattr(TDatasets, order_by).asc())
173198
finally:
174199
pass
175200
return query

0 commit comments

Comments
 (0)