diff --git a/.docker/Dockerfile b/.docker/Dockerfile index 3dd4b6b0c462d04218e913d683e88a26f1400189..14a4f121954591a255cbb32301f3bad748771f74 100644 --- a/.docker/Dockerfile +++ b/.docker/Dockerfile @@ -9,7 +9,6 @@ RUN apt-get update && \ tox \ -y COPY .docker/wait-for-it.sh /wait-for-it.sh -ARG PYLIB=dev ADD https://gitlab.indiscale.com/api/v4/projects/97/repository/commits/${PYLIB} \ pylib_version.json RUN git clone https://gitlab.indiscale.com/caosdb/src/caosdb-pylib.git && \ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 5d821d4a48561444b959fccc397101b1a2d293ed..b2598bd6341ddc6e982820c16705947b972edcf3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -21,9 +21,9 @@ variables: CI_REGISTRY_IMAGE: $CI_REGISTRY/caosdb/src/caosdb-pyinttest/testenv:$CI_COMMIT_REF_NAME CI_REGISTRY_IMAGE_BASE: $CI_REGISTRY/caosdb/src/caosdb-pyinttest/base:latest - DEPLOY_REF: dev stages: + - info - setup - cert - style @@ -79,10 +79,44 @@ stages: # file-system features. # +.env: &env + - echo "Pipeline triggered by $TRIGGERED_BY_REPO@$TRIGGERED_BY_REF ($TRIGGERED_BY_HASH)" + - echo "CI_REGISTRY_IMAGE_BASE = $CI_REGISTRY_IMAGE_BASE" + - echo "CI_REGISTRY_IMAGE = $CI_REGISTRY_IMAGE" + - echo "CAOSDB_TAG = $CAOSDB_TAG" + - echo "REFTAG = $REFTAG" + - echo "F_BRANCH = $F_BRANCH" + - echo "CI_COMMIT_REF_NAME = $CI_COMMIT_REF_NAME" + - ls -lah /image-cache/ + + - F_BRANCH=${F_BRANCH:-$CI_COMMIT_REF_NAME} + - echo $F_BRANCH + - if [[ "$REFTAG" == "" ]] ; then + if [[ "$F_BRANCH" == "dev" ]] ; then + REFTAG=dev; + fi; + fi + - REFTAG=${REFTAG:-dev_F_${F_BRANCH}} + + - echo $F_BRANCH + + - if [[ "$CAOSDB_TAG" == "" ]]; then + CAOSDB_TAG=${REFTAG}; + fi + - echo $CAOSDB_TAG + +info: + tags: [cached-dind] + image: docker:20.10 + stage: info + needs: [] + script: + - *env + test: tags: [docker] services: - - docker:20.10.3-dind + - docker:20.10-dind variables: # This is a workaround for the gitlab-runner health check mechanism when # using docker-dind service. The runner will otherwise guess the port @@ -90,35 +124,10 @@ test: SERVICE_PORT_2376_TCP_PORT: 2375 stage: test image: $CI_REGISTRY_IMAGE_BASE - needs: ["cert"] + needs: [cert] script: - - echo $F_BRANCH - - echo $CAOSDB_TAG - - echo $CI_COMMIT_REF_NAME - - F_BRANCH=${F_BRANCH:-$CI_COMMIT_REF_NAME} - - echo $F_BRANCH - - echo $CAOSDB_TAG - - echo $CI_COMMIT_REF_NAME - - if echo "$F_BRANCH" | grep -c "^f-.*$"; then - REFTAG="${REFTAG}_F_${F_BRANCH}"; - elif [ "$F_BRANCH" == "main" ]; then - F_BRANCH=main; - else - F_BRANCH=dev; - fi - - echo $F_BRANCH - - echo $CI_COMMIT_REF_NAME - - echo $CI_REGISTRY_IMAGE - + - *env - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY - - if [[ "$CAOSDB_TAG" == "" ]]; then - if echo "$F_BRANCH" | grep -c "^f-" ; then - CAOSDB_TAG=${DEPLOY_REF}_F_${F_BRANCH}; - docker pull $CI_REGISTRY/caosdb/src/caosdb-deploy:$CAOSDB_TAG || CAOSDB_TAG=${DEPLOY_REF} ; - else - CAOSDB_TAG=${DEPLOY_REF}; - fi; - fi - echo $CAOSDB_TAG - cd .docker @@ -126,10 +135,10 @@ test: - MARIADBVERSION=$(grep mariadb docker-compose.yml | awk '{print $2}') - echo "mariadb image:"$MARIADBVERSION - time docker load < /image-cache/caosdb-pyint-testenv-${CI_COMMIT_REF_NAME}.tar || true - - time docker load < /image-cache/caosdb-${F_BRANCH}.tar || true + - time docker load < /image-cache/caosdb-${REFTAG}.tar || time docker load < /image-cache/caosdb-dev.tar || true - time docker load < /image-cache/$MARIADBVERSION.tar || true + - docker pull $CI_REGISTRY/caosdb/src/caosdb-deploy:$CAOSDB_TAG || CAOSDB_TAG=dev - docker pull $CI_REGISTRY_IMAGE - - docker pull $CI_REGISTRY/caosdb/src/caosdb-deploy:$CAOSDB_TAG || CAOSDB_TAG=dev ; # Here, the server and the mysql backend docker are being started - CAOSDB_TAG=$CAOSDB_TAG docker-compose up -d @@ -139,7 +148,12 @@ test: - docker exec -u 0 -t docker_caosdb-server_1 cat /opt/caosdb/git/caosdb_webui_commit > hash_webui - docker exec -u 0 -t docker_caosdb-server_1 cat /opt/caosdb/git/caosdb_server_commit > hash_server - docker exec -u 0 -t docker_caosdb-server_1 cat /opt/caosdb/git/caosdb_mysqlbackend_commit > hash_mysql - + - docker exec -u 0 -t docker_caosdb-server_1 cat /opt/caosdb/git/caosdb_proto_commit > hash_proto + - cat hash_server + - cat hash_proto + - cat hash_mysql + - cat hash_webui + - cat hash_pylib # Run the actual tests. This starts a new docker container within which # the tests run. The return value is stored in .docker/result - /bin/sh ./run.sh @@ -154,8 +168,8 @@ test: # Store mariadb image - if [ ! -f ".gistlab-ci.yml" ]; then - time docker save $MARIADBVERSION > /image-cache/$MARIADBVERSION.tar || true - fi + time docker save $MARIADBVERSION > /image-cache/$MARIADBVERSION.tar || true; + fi; # the pyinttest docker writes the return value of the tests into the # file result @@ -164,7 +178,6 @@ test: dependencies: [cert] timeout: 3h artifacts: - when: on_failure paths: - caosdb_log.txt - mariadb_log.txt @@ -173,7 +186,7 @@ test: build-testenv: tags: [cached-dind] - image: docker:19.03 + image: docker:20.10 stage: setup timeout: 2h only: @@ -212,6 +225,9 @@ cert: tags: [docker] stage: cert image: $CI_REGISTRY_IMAGE + needs: + - job: build-testenv + optional: true artifacts: paths: - .docker/cert/ @@ -219,10 +235,14 @@ cert: script: - cd .docker - CAOSHOSTNAME=caosdb-server ./cert.sh + style: tags: [docker] stage: style image: $CI_REGISTRY_IMAGE + needs: + - job: build-testenv + optional: true script: - autopep8 -r --diff --exit-code . allow_failure: true diff --git a/.gitlab/merge_request_templates/Default.md b/.gitlab/merge_request_templates/Default.md deleted file mode 100644 index 77a95da1cc40c815e4952a1283d345af56e80461..0000000000000000000000000000000000000000 --- a/.gitlab/merge_request_templates/Default.md +++ /dev/null @@ -1,49 +0,0 @@ -# Summary - - Insert a meaningful description for this merge request here. What is the - new/changed behavior? Which bug has been fixed? Are there related Issues? - -# Focus - - Point the reviewer to the core of the code change. Where should they start - reading? What should they focus on (e.g. security, performance, - maintainability, user-friendliness, compliance with the specs, finding more - corner cases, concrete questions)? - -# Test Environment - - How to set up a test environment for manual testing? - -# Check List for the Author - -Please, prepare your MR for a review. Be sure to write a summary and a -focus and create gitlab comments for the reviewer. They should guide the -reviewer through the changes, explain your changes and also point out open -questions. For further good practices have a look at [our review -guidelines](https://gitlab.com/caosdb/caosdb/-/blob/dev/REVIEW_GUIDELINES.md) - -- [ ] All automated tests pass -- [ ] Reference related Issues -- [ ] Up-to-date CHANGELOG.md -- [ ] Annotations in code (Gitlab comments) - - Intent of new code - - Problems with old code - - Why this implementation? - - -# Check List for the Reviewer - - -- [ ] I understand the intent of this MR -- [ ] All automated tests pass -- [ ] Up-to-date CHANGELOG.md -- [ ] The test environment setup works and the intended behavior is - reproducible in the test environment -- [ ] In-code documentation and comments are up-to-date. -- [ ] Check: Are there spezifications? Are they satisfied? - -For further good practices have a look at [our review guidelines](https://gitlab.com/caosdb/caosdb/-/blob/dev/REVIEW_GUIDELINES.md). - - -/assign me -/target_branch dev diff --git a/CHANGELOG.md b/CHANGELOG.md index dd58edd8e7fa711540aa8e20f981c155c3945711..c997d3e3d77a949be42440117a4fcba538de7926 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -36,6 +36,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 [caosdb-server#155](https://gitlab.indiscale.com/caosdb/src/caosdb-server/-/issues/155) have been resolved. * Tests for caosdb-server#154 +* Tests for caosdb-server#217 * Tests for caosdb-pylib#61 ### Changed (for changes in existing functionality) diff --git a/Makefile b/Makefile index 9689f1e3b68d0bd7f501879bcb6c854c0153a88e..d81534bd53fe76e6244a998aa393a6a86f52ac69 100644 --- a/Makefile +++ b/Makefile @@ -47,7 +47,7 @@ help: # Run the tests through autopep8. autopep8: - autopep8 -ri tests + autopep8 -ri . # Meta target to call the other targets. all: autopep8 test diff --git a/pycaosdb.ini.template b/pycaosdb.ini.template index c94af17ae01408f9d7f24473ce36ce738c75331d..7530d6af2e24d564c3d02b88b3f7dd38eb4de073 100644 --- a/pycaosdb.ini.template +++ b/pycaosdb.ini.template @@ -2,28 +2,30 @@ ## This sections must exist in addition to the usual section. [IntegrationTests] -########## Server-side scripting ################## +########## Server-side scripting paths ################## ## These are used by tests of server side scripting. Both paths have ## to point to existing directories in which the CaosDB server has the ## permissions to create and execute scripts. -# location of the scripting bin dir which is used for the test scripts from the -# pyinttest's perspective. +# Location of the scripting bin dir which is used for the test scripts from the +# pyinttest's perspective. Probably the scripting/bin dir in the caosdb-server sources. #test_server_side_scripting.bin_dir.local=/path/to/scripting/bin -# location of the scripting bin dir which is used for the test scripts from the +# Location of the scripting bin dir which is used for the test scripts from the # server's perspective. #test_server_side_scripting.bin_dir.server=/opt/caosdb/git/caosdb-server/scripting/bin -########## Files ################## +########## Files paths ################## ## Used by tests of file handling. Specify the path to an existing ## directory in which file tests are performed, once as seen by the ## host and once as seen by the server. -# location of the files from the pyinttest (i.e. host) perspective +# Location of the files from the pyinttest (i.e. host) perspective. Probably the local extroot +# path plus `/test_insert_files_in_dir/`. #test_files.test_insert_files_in_dir.local=/extroot/test_insert_files_in_dir/ -# location of the files from the caosdb server's perspective +# Location of the files from the caosdb server's perspective. Probably with the same last +# component(s) as the local variant (above). #test_files.test_insert_files_in_dir.server=/opt/caosdb/mnt/extroot/test_insert_files_in_dir/ ########## Authentication tokens ################## diff --git a/tests/test_administration.py b/tests/test_administration.py index 9ecc1360dc537852463c8ab3c2abc945266711e2..6187da465d19db729fbdba9c8e50c51a15ab7b28 100644 --- a/tests/test_administration.py +++ b/tests/test_administration.py @@ -26,7 +26,7 @@ @author: tf """ -from caosdb import administration as admin +from caosdb import administration as admin, Info, get_config from caosdb.connection.connection import configure_connection, get_connection from caosdb.exceptions import (HTTPClientError, HTTPForbiddenError, LoginFailedError, HTTPResourceNotFoundError) @@ -52,17 +52,18 @@ def setup_module(): def teardown_module(): switch_to_admin_user() + admin.set_server_property("AUTH_OPTIONAL", "FALSE") try: admin._delete_user(name=test_user) except Exception as e: print(e) -def setup(): +def setup_function(function): switch_to_admin_user() -def teardown(): +def teardown_function(function): switch_to_admin_user() try: admin._delete_user(name=test_user + "2") @@ -81,6 +82,8 @@ def switch_to_normal_user(): def switch_to_admin_user(): configure_connection() + assert Info().user_info.name == get_config().get("Connection", "username") + assert Info().user_info.roles == ["administration"] def test_get_server_properties(): @@ -99,6 +102,8 @@ def test_set_server_property(): def test_insert_role_success(): + assert Info().user_info.name == get_config().get("Connection", "username") + assert Info().user_info.roles == ["administration"] assert admin._insert_role(name=test_role, description=test_role_desc) @@ -110,6 +115,8 @@ def test_insert_role_failure_permission(): def test_insert_role_failure_name_duplicates(): + assert Info().user_info.name == get_config().get("Connection", "username") + assert Info().user_info.roles == ["administration"] test_insert_role_success() with assert_raises(HTTPClientError) as cm: admin._insert_role(name=test_role, description=test_role_desc) diff --git a/tests/test_affiliation.py b/tests/test_affiliation.py index 70a619c5662fa6afb0e4bf949afae720322ecbd2..6c7bef617396a738cfa34cba6816578d951b60ec 100644 --- a/tests/test_affiliation.py +++ b/tests/test_affiliation.py @@ -27,7 +27,7 @@ """ import os import caosdb as db -from nose.tools import nottest, assert_true, assert_equal, with_setup, assert_is_not_none +from nose.tools import nottest, assert_equal, assert_is_not_none from pytest import raises @@ -48,7 +48,7 @@ prop_name = "TestPropertyParent" file_path = "testfile.dat" -def setup(): +def setup_function(function): d = db.execute_query("FIND ENTITY WITH ID > 99") if len(d) > 0: d.delete() @@ -58,32 +58,29 @@ def setup(): db.Property(name=prop_name, datatype=db.TEXT).insert() -def teardown(): +def teardown_function(function): db.execute_query("FIND Test*").delete() def test_affiliation_there(): par = db.RecordType(name="TestRT1") ch = db.Record(name="TestRec").add_parent(par) - assert_is_not_none(ch.get_parent("TestRT1")) - assert_true(hasattr(ch.get_parent("TestRT1"), "affiliation")) + assert ch.get_parent("TestRT1") is not None + assert hasattr(ch.get_parent("TestRT1"), "affiliation") -@with_setup(setup, teardown) def test_rec_rec_is_parthood(): par = db.Record(name="TestRecordChild").add_parent( name=rec_name).insert().get_parent(rec_name) assert_equal(par.affiliation, "PARTHOOD") -@with_setup(setup, teardown) def test_rec_rt_is_instantiation(): par = db.Record(name="TestRecordChild").add_parent( name=recty_name).insert().get_parent(recty_name) assert_equal(par.affiliation, "INSTANTIATION") -@with_setup(setup, teardown) def test_rec_prop_is_invalid(): with raises(db.TransactionError) as cm: db.Record(name="TestRecordChild").add_parent(name=prop_name).insert() @@ -94,7 +91,6 @@ def test_rec_prop_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_rec_file_is_invalid(): with raises(db.TransactionError) as cm: db.Record(name="TestRecordChild").add_parent(name=file_name).insert() @@ -103,7 +99,6 @@ def test_rec_file_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_rt_rec_is_invalid(): with raises(db.TransactionError) as cm: db.RecordType( @@ -114,14 +109,12 @@ def test_rt_rec_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_rt_rt_is_subtyping(): par = db.RecordType(name="TestRecordTypeChild").add_parent( name=recty_name).insert().get_parent(recty_name) assert_equal(par.affiliation, "SUBTYPING") -@with_setup(setup, teardown) def test_rt_prop_is_invalid(): with raises(db.TransactionError) as cm: db.RecordType( @@ -132,7 +125,6 @@ def test_rt_prop_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_rt_file_is_invalid(): with raises(db.TransactionError) as cm: db.RecordType( @@ -143,7 +135,6 @@ def test_rt_file_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_prop_rec_is_invalid(): with raises(db.TransactionError) as cm: db.Property( @@ -155,7 +146,6 @@ def test_prop_rec_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_prop_rt_is_invalid(): with raises(db.TransactionError) as cm: db.Property( @@ -167,7 +157,6 @@ def test_prop_rt_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_prop_prop_is_subtyping(): par = db.Property( name="TestPropertyChild", @@ -176,7 +165,6 @@ def test_prop_prop_is_subtyping(): assert_equal(par.affiliation, "SUBTYPING") -@with_setup(setup, teardown) def test_prop_file_is_invalid(): with raises(db.TransactionError) as cm: db.Property( @@ -188,7 +176,6 @@ def test_prop_file_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_file_rec_is_parthood(): par = db.File( name="TestFileChild", @@ -198,7 +185,6 @@ def test_file_rec_is_parthood(): assert_equal(par.affiliation, "PARTHOOD") -@with_setup(setup, teardown) def test_file_rt_is_instantiation(): par = db.File( name="TestFileChild", @@ -208,7 +194,6 @@ def test_file_rt_is_instantiation(): assert_equal(par.affiliation, "INSTANTIATION") -@with_setup(setup, teardown) def test_file_prop_is_invalid(): with raises(db.TransactionError) as cm: db.File( @@ -221,7 +206,6 @@ def test_file_prop_is_invalid(): assert ee.msg == "Affiliation is not defined for this child-parent constellation." -@with_setup(setup, teardown) def test_file_file_is_invalid(): with raises(db.TransactionError) as cm: db.File( diff --git a/tests/test_authentication.py b/tests/test_authentication.py index ef0657cbe215743e79ce1e2110a1b172cb980c36..c885523a8ac52b2f2d84a55e92c3351a39edae47 100644 --- a/tests/test_authentication.py +++ b/tests/test_authentication.py @@ -41,7 +41,7 @@ from .test_server_side_scripting import request _USED_OTA_TOKEN = set() -def setup(): +def setup_function(function): db.configure_connection() # deactivate anonymous user @@ -51,8 +51,8 @@ def setup(): d.delete() -def teardown(): - setup() +def teardown_function(function): + setup_function(function) @mark.skipif( diff --git a/tests/test_creation.py b/tests/test_creation.py index a2a431e82c948286afba71841832025241208d24..5f5d3ecac30c8888ac9f788e45a7dd57ffaa347c 100755 --- a/tests/test_creation.py +++ b/tests/test_creation.py @@ -27,17 +27,15 @@ # A. Schlemmer, 08/2014 from caosdb import Container, RecordType, Property, execute_query -from nose.tools import with_setup # @UnresolvedImport -def setup(): +def setup_function(function): try: execute_query("FIND PA_*").delete() except BaseException: pass -@with_setup(setup, setup) def test_PA_Datamodel(): pr10 = Property(name="PA_DataFile", id=-10, datatype="file", description="The property specifying the " diff --git a/tests/test_datatype.py b/tests/test_datatype.py index 3abba3f85369df799ed3611b84ce7d54f8dc17f0..46c52108e9bb1aed097c109ea30f675f6efc20a2 100644 --- a/tests/test_datatype.py +++ b/tests/test_datatype.py @@ -29,14 +29,14 @@ import caosdb as db from pytest import raises -def setup(): +def setup_function(function): try: db.execute_query("FIND Test*").delete() except BaseException: pass -def teardown(): +def teardown_function(function): try: db.execute_query("FIND Test*").delete() except BaseException: diff --git a/tests/test_datatype_inheritance.py b/tests/test_datatype_inheritance.py index 638207181dee055a1fcfffa57386e598a32ab828..119f72869612f636346da098630ff8715d888a44 100644 --- a/tests/test_datatype_inheritance.py +++ b/tests/test_datatype_inheritance.py @@ -25,18 +25,17 @@ from caosdb import Container, Property, RecordType, Record, execute_query import caosdb import caosdb as db from caosdb.connection.connection import get_connection -# @UnresolvedImport -from nose.tools import assert_is_not_none, assert_true, assert_equal, with_setup +from nose.tools import assert_is_not_none, assert_true, assert_equal from caosdb.exceptions import TransactionError from pytest import raises -def setup(): - teardown() +def setup_function(function): + teardown_function(function) -def teardown(): +def teardown_function(function): try: db.execute_query("FIND test_*").delete() except BaseException: @@ -47,7 +46,6 @@ def teardown(): pass -@with_setup(setup, teardown) def test_default_datatype_for_recordtypes(): rt1 = db.RecordType(name="TestRT1").insert() rt2 = db.RecordType(name="TestRT2").add_property(name="TestRT1").insert() @@ -62,7 +60,6 @@ def test_default_datatype_for_recordtypes(): assert_equal(p.datatype, rt1.name) -@with_setup(setup, teardown) def test_datatype_inheritance(): insert = '<Insert><Property id="-1" name="test_property" description="bla" datatype="Text"/><RecordType name="test_rt" description="bla"> <Property id="-1" importance="obligatory" /></RecordType></Insert>' diff --git a/tests/test_deletion.py b/tests/test_deletion.py index fd2236ec2b96d0a0340ebb773fc829066f824941..bf449218765e49f994c69eaebff60c6673c0f867 100755 --- a/tests/test_deletion.py +++ b/tests/test_deletion.py @@ -26,7 +26,7 @@ # Testcase fuer deletion # A. Schlemmer, 08/2014 -from nose.tools import with_setup, assert_false, assert_true, assert_raises, assert_equal, assert_is_not_none # @UnresolvedImport +from nose.tools import with_setup, assert_false, assert_true, assert_raises, assert_equal import caosdb as h @@ -37,18 +37,11 @@ def setup_module(): old.delete() -def setup161(): +def test_delete_referencing_properties(): h.RecordType(name="RT1").insert() h.RecordType(name="RT2").add_property("RT1").insert() h.RecordType(name="RT3").insert() - -def teardown161(): - setup_module() - - -@with_setup(setup161, teardown161) -def test_delete_referencing_properties(): rt3 = h.RecordType(name="RT3").retrieve() rt2 = h.RecordType(name="RT2").retrieve() rt3.add_property( @@ -61,14 +54,13 @@ def test_delete_referencing_properties(): h.execute_query("FIND ENTITY WITH ID > 100").delete() -def setup(): +def setup_function(function): try: h.execute_query("FIND Test*").delete() except Exception as e: print(e) -@with_setup(setup, setup) def test_deletion(): c = h.Container() c.append( @@ -148,7 +140,7 @@ def test_deletion(): cr2.insert() assert_true(cr2.is_valid()) - assert_is_not_none(cr2.id) + assert cr2.id is not None c.extend([cr1, sr, d]) assert_raises(h.TransactionError, c.delete) diff --git a/tests/test_empty_text_value.py b/tests/test_empty_text_value.py index fe705d6deadc7ce57e0a12c3d5492c3ab9b7d87e..64be317878150e735e6d197835381d5a52b22dcc 100644 --- a/tests/test_empty_text_value.py +++ b/tests/test_empty_text_value.py @@ -24,15 +24,15 @@ import pytest import caosdb as db -def setup(): - teardown() +def setup_function(function): + teardown_function(function) rt = db.RecordType("TestRT") rt.insert() p = db.Property("TestProp", datatype=db.TEXT) p.insert() -def teardown(): +def teardown_function(function): try: db.execute_query("FIND Test*").delete() except Exception as e: diff --git a/tests/test_error_stuff.py b/tests/test_error_stuff.py index d6eb85b74bf288e91de02c4d6d95e1f1298b2c0f..ca33fb2f101ad87e701bad92745490699b1e789a 100644 --- a/tests/test_error_stuff.py +++ b/tests/test_error_stuff.py @@ -40,16 +40,16 @@ from caosdb.exceptions import (AmbiguousEntityError, import pytest -def setup(): +def setup_function(function): try: h.execute_query("FIND Test*").delete() except BaseException: pass -def teardown(): +def teardown_function(function): """Delete everything.""" - setup() + setup_function(function) def test_retrieval_no_exception_raised(): diff --git a/tests/test_file.py b/tests/test_file.py index 7b24c9777a39b9d6b6ed66540441b09056c36f37..67d9c1ed05c52dd8a77c6b746a7c1c9fe2c71cb4 100644 --- a/tests/test_file.py +++ b/tests/test_file.py @@ -43,11 +43,11 @@ from caosdb.utils.checkFileSystemConsistency import runCheck def setup_module(): - teardown() + teardown_function(None) -def setup(): - teardown() +def setup_function(function): + teardown_function(function) with open("test.dat", "w") as upload_file: upload_file.write("hello world\n") os.makedirs("testfolder/subfolder") @@ -57,7 +57,7 @@ def setup(): upload_file.write("hello world\n") -def teardown(): +def teardown_function(function): d = execute_query("FIND ENTITY WHICH HAS AN ID >= 100") if len(d) > 0: d.delete() diff --git a/tests/test_importance.py b/tests/test_importance.py index afa63effa4d70b32728777d3304a09c212c318e1..6bcf4a097647c6d8393192361337e0b45a1417b0 100644 --- a/tests/test_importance.py +++ b/tests/test_importance.py @@ -22,7 +22,7 @@ from pytest import raises import caosdb as db -def setup(): +def setup_function(function): teardown_module() diff --git a/tests/test_inheritance.py b/tests/test_inheritance.py index 6b4fd2c293b88d6a3ae241b8302c186b84ac4ebd..bffb128484364906ec2e30342cbc5090c7ca9554 100644 --- a/tests/test_inheritance.py +++ b/tests/test_inheritance.py @@ -30,11 +30,11 @@ import caosdb as db -def setup(): - teardown() +def setup_function(function): + teardown_function(function) -def teardown(): +def teardown_function(function): d = db.execute_query("FIND ENTITY WITH ID > 99") if len(d) > 0: d.delete() diff --git a/tests/test_issues_mysqlbackend.py b/tests/test_issues_mysqlbackend.py index 64de2f2f6e4d92effc9847598e474bd80a06825d..5904deda1ac5a63f40eeb578ba82cd249ebfcec6 100644 --- a/tests/test_issues_mysqlbackend.py +++ b/tests/test_issues_mysqlbackend.py @@ -33,12 +33,12 @@ def setup_module(): print(delete_exc) -def setup(): +def setup_function(function): """No setup required.""" setup_module() -def teardown(): +def teardown_function(function): """Deleting entities again.""" setup_module() diff --git a/tests/test_issues_server.py b/tests/test_issues_server.py index a05a1ca465d6515552213c963d6d3e1211695eb2..e9a93685cfd222000a50b399d44ec32692137e4f 100644 --- a/tests/test_issues_server.py +++ b/tests/test_issues_server.py @@ -1,10 +1,8 @@ # -*- coding: utf-8 -*- -# -# ** header v3.0 # This file is a part of the CaosDB Project. # -# Copyright (c) 2020 IndiScale GmbH <info@indiscale.com> -# Copyright (c) 2020 Daniel Hornung <d.hornung@indiscale.com> +# Copyright (c) 2022 IndiScale GmbH <info@indiscale.com> +# Copyright (c) 2022 Daniel Hornung <d.hornung@indiscale.com> # Copyright (c) 2020 Florian Spreckelsen <f.spreckelsen@indiscale.com> # # This program is free software: you can redistribute it and/or modify @@ -19,8 +17,6 @@ # # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. -# -# ** end header """Tests for issues on gitlab.com, project caosdb-server.""" @@ -41,15 +37,14 @@ def setup_module(): print(delete_exc) -def setup(): +def setup_function(function): """No setup required.""" setup_module() -def teardown(): +def teardown_function(function): """Deleting entities again.""" setup_module() - pass # ########################### Issue tests start here ##################### @@ -463,3 +458,249 @@ def test_issue_183(): value="2015-05-05T20:15").insert() assert cm.value.errors[0].msg == ("Cannot parse value to datetime format " "(yyyy-mm-dd'T'hh:mm:ss[.fffffffff][TimeZone]).") + + +@pytest.mark.xfail(reason="fix https://gitlab.com/caosdb/caosdb-server/-/issues/130") +def test_issue_130(): + """Test select queries where names contain spaces + + https://gitlab.com/caosdb/caosdb-server/-/issues/130 + + However, this bug was actually about quotation marks + """ + db.RecordType(name="TestRT_A").insert() + r1 = db.Record("ReferencedRecord").add_parent("TestRT_A").insert() + p1 = db.Property(name="TestWrapper", datatype="TestRT_A").insert() + p2 = db.Property( + name="TestWrapper With Spaces", + datatype="TestRT_A").insert() + db.RecordType(name="TestRT_B" + ).add_property(name="TestWrapper" + ).add_property("TestWrapper With Spaces" + ).insert() + db.Record().add_parent("TestRT_B" + ).add_property("TestWrapper", value=r1 + ).add_property("TestWrapper With Spaces", + value=r1 + ).insert() + + query = "SELECT TestWrapper FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values(("TestWrapper")) + assert row == [(r1.id,)] + + query = "SELECT TestWrapper FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values(("TestWrapper", "id")) + assert row == [(p1.id,)] + + query = "SELECT 'TestWrapper' FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values(("TestWrapper", "id")) + assert row == [(r1.id,)] # FAILS + + query = "SELECT TestWrapper FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values(("TestWrapper", "name")) + assert row == [("TestWrapper",)] + + query = "SELECT TestWrapper.name FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values(("TestWrapper", "name")) + assert row == [("ReferencedRecord",)] + + query = "SELECT 'TestWrapper.name' FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values(("TestWrapper", "name")) + assert row == [("ReferencedRecord",)] # FAILS + + query = "SELECT 'TestWrapper'.name FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values(("TestWrapper", "name")) + assert row == [("ReferencedRecord",)] # FAILS + + query = "SELECT TestWrapper With Spaces FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values( + ("TestWrapper With Spaces")) + assert row == [(r1.id,)] + + query = "SELECT TestWrapper With Spaces FROM RECORD TestRT_B" + row = db.execute_query(query).get_property_values( + ("TestWrapper With Spaces", "id")) + assert row == [(p2.id,)] + + query = 'SELECT TestWrapper With Spaces FROM RECORD TestRT_B' + row = db.execute_query(query).get_property_values( + ("TestWrapper With Spaces", "name")) + assert row == [("TestWrapper With Spaces",)] + + query = 'SELECT "TestWrapper With Spaces" FROM RECORD TestRT_B' + row = db.execute_query(query).get_property_values( + ("TestWrapper With Spaces", "name")) + assert row == [("ReferencedRecord",)] # FAILS + + query = 'SELECT TestWrapper With Spaces.name FROM RECORD TestRT_B' + row = db.execute_query(query).get_property_values( + ("TestWrapper With Spaces", "name")) + # Works!!! This is about the quotation marks + assert row == [("ReferencedRecord",)] + + query = 'SELECT "TestWrapper With Spaces.name" FROM RECORD TestRT_B' + row = db.execute_query(query).get_property_values( + ("TestWrapper With Spaces", "name")) + assert row == [("ReferencedRecord",)] # FAILS + + query = 'SELECT "TestWrapper With Spaces".name FROM RECORD TestRT_B' + row = db.execute_query(query).get_property_values( + ("TestWrapper With Spaces", "name")) + assert row == [("ReferencedRecord",)] # FAILS + + +def test_issue_132(): + """Query: Parenthesis around subproperties. + + https://gitlab.com/caosdb/caosdb-server/-/issues/132 + """ + db.RecordType("TestRT").insert() + db.RecordType("TestRT_Foo").insert() + db.Property("TestP_Bar", datatype=db.TEXT).insert() + db.Property("TestP_Baz", datatype=db.TEXT).insert() + + rt1 = db.Record().add_parent("TestRT_Foo").add_property( + "TestP_Bar", "val1").add_property( + "TestP_Baz", "the other baz").insert() + rt2 = db.Record().add_parent("TestRT").add_property( + "TestP_Baz", "val2").add_property( + "TestRT_Foo", rt1).insert() + + query = "FIND RECORD TestRT_Foo" + assert db.execute_query(query, unique=True).id == rt1.id + + query = "FIND RECORD TestRT" + assert db.execute_query(query, unique=True).id == rt2.id + + query = "FIND RECORD TestRT WITH TestRT_Foo" + assert db.execute_query(query, unique=True).id == rt2.id + + query = "FIND RECORD TestRT WITH TestRT_Foo.TestP_Bar" + assert db.execute_query(query, unique=True).id == rt2.id + + query = "FIND RECORD TestRT WITH TestRT_Foo.TestP_Bar = val1" + assert db.execute_query(query, unique=True).id == rt2.id + + query = "FIND RECORD TestRT WITH (TestRT_Foo.TestP_Bar = val1)" + assert db.execute_query(query, unique=True).id == rt2.id + + query = "FIND RECORD TestRT WITH ( TestRT_Foo.TestP_Bar = val1 )" + assert db.execute_query(query, unique=True).id == rt2.id + + query = "FIND RECORD TestRT WITH (TestRT_Foo.TestP_Bar = val1) AND TestP_Baz = val2" + assert db.execute_query(query, unique=True).id == rt2.id + + query = "FIND RECORD TestRT WITH (TestRT_Foo WITH (TestP_Bar = val1 AND TestP_Baz = 'the other baz')) AND TestP_Baz = val2" + assert db.execute_query(query, unique=True).id == rt2.id + + query = "FIND RECORD TestRT WITH TestRT_Foo WITH (TestP_Bar = val1 AND TestP_Baz = 'the other baz') AND TestP_Baz = val2" + assert db.execute_query(query, unique=True).id == rt2.id + + # this one has the wront scope of the conjunction. + query = "FIND RECORD TestRT WITH TestRT_Foo.TestP_Bar = val1 AND TestP_Baz = 'the other one'" + assert len(db.execute_query(query)) == 0 + + +def test_issue_217(): + """Server gets list property datatype wrong if description is updated.""" + # @review Florian Spreckelsen 2022-03-15 + + rt = db.RecordType(name="TestRT").insert() + # prop = db.Property(name="LP", datatype=db.LIST("TestRT")).insert() + r = db.Record().add_parent(id=rt.id).add_property(name=rt.name, + datatype=db.LIST( + db.INTEGER), + value=[10001, 10002]) + assert r.get_property(rt.name).datatype == db.LIST(db.INTEGER) + assert r.get_property(rt.name).value == [10001, 10002] + r.insert() + assert r.get_property(rt.name).datatype == db.LIST(db.INTEGER) + assert r.get_property(rt.name).value == [10001, 10002] + r.retrieve() + assert r.get_property(rt.name).datatype == db.LIST(db.INTEGER) + assert r.get_property(rt.name).value == [10001, 10002] + r.retrieve(flags={"cache": "false"}) + assert r.get_property(rt.name).datatype == db.LIST(db.INTEGER) + assert r.get_property(rt.name).value == [10001, 10002] + r.description = "Changed description" + r.update() + assert r.get_property(rt.name).datatype == db.LIST(db.INTEGER) + assert r.get_property(rt.name).value == [10001, 10002] + # This line fails in the bug report with invalid XML. + r.retrieve() + assert r.get_property(rt.name).datatype == db.LIST(db.INTEGER) + assert r.get_property(rt.name).value == [10001, 10002] + + +def test_issue_217_2(): + """Server gets overridden name of property wrong when the description of record is being updated.""" + # @review Florian Spreckelsen 2022-03-15 + + rt = db.RecordType(name="TestRT").insert() + # prop = db.Property(name="LP", datatype=db.LIST("TestRT")).insert() + overridden_name = "TestRT-overridden" + r = db.Record().add_parent(id=rt.id).add_property(name=overridden_name, + id=rt.id) + assert r.get_property(overridden_name) is not None + assert r.get_property(overridden_name).id == rt.id + r.insert() + assert r.get_property(overridden_name) is not None + assert r.get_property(overridden_name).id == rt.id + r.retrieve() + assert r.get_property(overridden_name) is not None + assert r.get_property(overridden_name).id == rt.id + r.retrieve(flags={"cache": "false"}) + assert r.get_property(overridden_name) is not None + assert r.get_property(overridden_name).id == rt.id + r.description = "Changed description" # change description of the record + r.update() + assert r.get_property(overridden_name) is not None + assert r.get_property(overridden_name).id == rt.id + r.retrieve() + assert r.get_property(overridden_name) is not None + assert r.get_property(overridden_name).id == rt.id + + +def test_issue_217_3(): + """Server gets overridden description of property wrong when the description of record is being updated.""" + # @review Florian Spreckelsen 2022-03-15 + + rt = db.RecordType(name="TestRT", description="Desc").insert() + # prop = db.Property(name="LP", datatype=db.LIST("TestRT")).insert() + r = db.Record().add_parent(id=rt.id).add_property(description="Desc-overridden", + id=rt.id) + r.insert() + assert r.get_property(rt.name).id == rt.id + assert r.get_property(rt.name).description == "Desc-overridden" + r.retrieve() + assert r.get_property(rt.name).id == rt.id + assert r.get_property(rt.name).description == "Desc-overridden" + r.retrieve(flags={"cache": "false"}) + assert r.get_property(rt.name).id == rt.id + assert r.get_property(rt.name).description == "Desc-overridden" + r.description = "Changed description" # change description of the record + r.update() + assert r.get_property(rt.name).id == rt.id + assert r.get_property(rt.name).description == "Desc-overridden" + r.retrieve() + assert r.get_property(rt.name).id == rt.id + assert r.get_property(rt.name).description == "Desc-overridden" + + +def test_issue_221(): + """Unknown error during update of property leaving out datatype""" + + rt = db.RecordType("A") + r = db.Record() + r.add_parent(rt) + p = db.Property(name="B", datatype=db.INTEGER) + r.add_property(name="B", value=5) + db.Container().extend([rt, r, p]).insert() + + r2 = db.Record(id=r.id).retrieve() + r2.remove_property("B") + r2.add_property(p, value=7) + r2.update() + assert r2.get_property("B").value == 7 + assert r2.get_property("B").datatype == db.INTEGER + assert r2.get_property("B").id == p.id diff --git a/tests/test_list.py b/tests/test_list.py index 2888552b3f26770986596f28dde6c87eb4b4271d..63ece67b7b454800533a68b2c86d5db51776be68 100644 --- a/tests/test_list.py +++ b/tests/test_list.py @@ -33,16 +33,16 @@ from nose.tools import assert_true, assert_equal from pytest import raises -def setup(): +def setup_function(function): d = db.execute_query("FIND ENTITY WITH ID > 99") if len(d) > 0: d.delete() -def teardown(): +def teardown_function(function): if os.path.isfile("test.dat"): os.remove("test.dat") - setup() + setup_function(function) def test_list_of_files(): diff --git a/tests/test_misc.py b/tests/test_misc.py index 177843a765a83ceb9b4de3f43b1b2caa2e31658d..15ba810887802917725a8eb8e88b6fa66f98c3bf 100644 --- a/tests/test_misc.py +++ b/tests/test_misc.py @@ -31,7 +31,7 @@ from pytest import raises from pytest import mark -def setup(): +def setup_function(function): try: db.execute_query("FIND Test*").delete() except Exception as e: @@ -227,7 +227,7 @@ def test_annotation(): def test_info(): assert admin.get_server_property( - "TRANSACTION_BENCHMARK_ENABLED") == "TRUE", "Please activate the transaction benchmark with the server option TRANSACTION_BENCHMARK_ENABLED=TRUE (Restart of the server needed)" + "TRANSACTION_BENCHMARK_ENABLED").lower() == "true", "Please activate the transaction benchmark with the server option TRANSACTION_BENCHMARK_ENABLED=TRUE (Restart of the server needed)" i = Info() assert (i.messages["Flags"]) is not None assert (i.messages["Counts"]) is not None diff --git a/tests/test_name_properties.py b/tests/test_name_properties.py index 028592b7c0a728587f9939e427eb40ba74b9be43..c389945d5a46bfa8f22511554a751051ebf625fc 100644 --- a/tests/test_name_properties.py +++ b/tests/test_name_properties.py @@ -27,8 +27,8 @@ """ import caosdb as db -from pytest import raises, mark -from nose.tools import nottest, assert_true, assert_raises, assert_equal, with_setup, assert_is_not_none # @UnresolvedImport +from pytest import raises +from nose.tools import assert_true, assert_equal def setup_module(): @@ -36,36 +36,34 @@ def setup_module(): def teardown_module(): - teardown() + teardown_function(None) -def setup(): +def setup_function(function): try: db.execute_query("FIND Test*").delete() except BaseException: pass -def teardown(): +def teardown_function(function): try: db.execute_query("FIND Test*").delete() except BaseException: pass -@with_setup(setup, teardown) def test_property_insertion(): p = db.Property( name="TestShortName", datatype=db.TEXT, value="TestSN").add_parent( name="name").insert() - assert_true(p.is_valid()) + assert p.is_valid() return p -@with_setup(setup, teardown) def test_property_query(): pid = test_property_insertion().id assert_equal(db.execute_query("FIND TestShortName", unique=True).id, pid) @@ -74,29 +72,26 @@ def test_property_query(): assert_equal(len(db.execute_query("FIND TestSN")), 0) -@with_setup(setup, teardown) def test_recordtype_insertion_separately_prop_by_id_direct_name_child(): pid = test_property_insertion().id rt = db.RecordType( name="TestRecordType").add_property( id=pid, value="TestRT").insert() - assert_true(rt.is_valid()) + assert rt.is_valid() return rt -@with_setup(setup, teardown) def test_recordtype_is_stored_correctly(): test_recordtype_insertion_separately_prop_by_id_direct_name_child() rt = db.RecordType(name="TestRecordType").retrieve() - assert_true(rt.is_valid()) + assert rt.is_valid() assert_equal(len(rt.get_properties()), 1) - assert_is_not_none(rt.get_property("TestShortName")) + assert rt.get_property("TestShortName") is not None assert_equal(rt.get_property("TestShortName").value, "TestRT") -@with_setup(setup, teardown) def test_recordtype_insertion_container_prop_by_tempid_direct_name_child(): p = db.Property( name="TestShortName", @@ -109,13 +104,12 @@ def test_recordtype_insertion_container_prop_by_tempid_direct_name_child(): id=-1, value="TestRT") c = db.Container().extend([p, rt]) c.insert() - assert_true(c.is_valid()) - assert_true(p.is_valid()) - assert_true(rt.is_valid()) + assert c.is_valid() + assert p.is_valid() + assert rt.is_valid() return rt -@with_setup(setup, teardown) def test_recordtype_insertion_container_prop_by_name_direct_name_child(): p = db.Property( name="TestShortName", @@ -128,40 +122,37 @@ def test_recordtype_insertion_container_prop_by_name_direct_name_child(): value="TestRT") c = db.Container().extend([p, rt]) c.insert() - assert_true(c.is_valid()) - assert_true(p.is_valid()) - assert_true(rt.is_valid()) + assert c.is_valid() + assert p.is_valid() + assert rt.is_valid() return rt -@with_setup(setup, teardown) def test_recordtype_insertion_separately_prop_by_name_direct_name_child(): test_property_insertion() rt = db.RecordType( name="TestRecordType").add_property( name="TestShortName", value="TestRT").insert() - assert_true(rt.is_valid()) + assert rt.is_valid() return rt -@with_setup(setup, teardown) def test_recordtpye_insertion_with_indirect_child_with_existing_parent(): test_property_insertion() p = db.Property( name="TestExtraShortName").add_parent( name="TestShortName").insert() - assert_true(p.is_valid()) + assert p.is_valid() rt = db.RecordType( name="TestRecordType").add_property( name="TestExtraShortName", value="TestRT").insert() - assert_true(rt.is_valid()) + assert rt.is_valid() return rt -@with_setup(setup, teardown) def test_recordtpye_insertion_with_indirect_child_with_new_parent(): parp = db.Property(name="TestShortName").add_parent(name="name") p = db.Property(name="TestExtraShortName").add_parent(name="TestShortName") @@ -171,40 +162,39 @@ def test_recordtpye_insertion_with_indirect_child_with_new_parent(): value="TestRT") c = db.Container().extend([parp, p, rt]).insert() - assert_true(c.is_valid()) - assert_true(p.is_valid()) - assert_true(parp.is_valid()) - assert_true(rt.is_valid()) + assert c.is_valid() + assert p.is_valid() + assert parp.is_valid() + assert rt.is_valid() return rt -@nottest -def do_unique_query_test(call, queries): - setup() +def assert_same_unique_results(call, queries): + setup_function(None) rtid = call().id for q in queries: assert_equal(db.execute_query(q, unique=True).id, rtid) - teardown() + teardown_function(None) def test_recordtype_query(): - do_unique_query_test( + assert_same_unique_results( test_recordtype_insertion_separately_prop_by_id_direct_name_child, [ "FIND TestRecordType", "FIND TestRT"]) - do_unique_query_test( + assert_same_unique_results( test_recordtype_insertion_separately_prop_by_name_direct_name_child, [ "FIND TestRecordType", "FIND TestRT"]) - do_unique_query_test( + assert_same_unique_results( test_recordtype_insertion_container_prop_by_name_direct_name_child, [ "FIND TestRecordType", "FIND TestRT"]) - do_unique_query_test( + assert_same_unique_results( test_recordtype_insertion_container_prop_by_tempid_direct_name_child, [ "FIND TestRecordType", "FIND TestRT"]) - do_unique_query_test( + assert_same_unique_results( test_recordtpye_insertion_with_indirect_child_with_new_parent, [ "FIND TestRecordType", "FIND TestRT"]) - do_unique_query_test( + assert_same_unique_results( test_recordtpye_insertion_with_indirect_child_with_existing_parent, [ "FIND TestRecordType", "FIND TestRT"]) @@ -224,7 +214,7 @@ def test_query_name_property(): with raises(db.BadQueryError): db.execute_query("FIND John", unique=True) - teardown() + teardown_function(None) # test behavior WITH the name parent db.RecordType("TestPerson").insert() @@ -239,7 +229,6 @@ def test_query_name_property(): unique=True).id == rec.id -@with_setup(setup, teardown) def test_query_property_with_pov(): """ Insert a Record with a property which can be searched using two different names. @@ -285,7 +274,6 @@ def test_query_property_with_pov(): rec.id) -@with_setup(setup, teardown) def test_query_with_reference(): """ Insert a Record with two names. Both work in a reference query. @@ -321,7 +309,6 @@ def test_query_with_reference(): rec.id) -@with_setup(setup, teardown) def test_query_with_back_reference(): """ Insert a Record with two names. Both work in a back-ref query. diff --git a/tests/test_parents.py b/tests/test_parents.py index 19b5894546a48847d8f5146388d413f833df9217..d038350a27cb0a9bb2db79020957dc401e1b1e10 100644 --- a/tests/test_parents.py +++ b/tests/test_parents.py @@ -22,11 +22,11 @@ from pytest import raises, mark import caosdb as db -def setup(): - teardown() +def setup_function(function): + teardown_function(function) -def teardown(): +def teardown_function(function): d = db.execute_query("FIND Test*") if len(d) > 0: d.delete() diff --git a/tests/test_permissions.py b/tests/test_permissions.py index 3fb41c6d2731607ed3ad02e1305e2f2f2b9dab67..f35d49661a551f6ee336d85e4477233905da1515 100644 --- a/tests/test_permissions.py +++ b/tests/test_permissions.py @@ -45,7 +45,9 @@ easy_pw = "1234" def setup_module(): - switch_to_admin_user() + d = db.execute_query("FIND *") + if len(d) > 0: + d.delete() insert_test_user() @@ -62,6 +64,9 @@ def teardown_module(): os.remove("test2.dat") except BaseException: pass + d = db.execute_query("FIND *") + if len(d) > 0: + d.delete() @mark.skip @@ -146,11 +151,11 @@ def revoke_permissions_test_role(): role=test_role, permission_rules=[]) -def teardown(): - setup() +def teardown_function(function): + setup_function(function) -def setup(): +def setup_function(function): switch_to_admin_user() try: db.execute_query("FIND Test*").delete() @@ -486,13 +491,12 @@ def test_update_role(): def test_update_move_file(): - upload_file = open("test.dat", "w") - upload_file.write("hello world\n") - upload_file.close() + with open("test.dat", "w") as upload_file: + upload_file.write("hello world\n") f = db.File( name="TestFile", - path="/permissiontestfiles/test.dat", + path="/testfiles/permissiontestfiles/test.dat", file="test.dat").insert() assert f.is_valid() @@ -500,22 +504,22 @@ def test_update_move_file(): grant_permission(f, "UPDATE:FILE:MOVE") '''SUCCESS''' - f.path = "/otherpermissiontestfiles/test.dat" + f.path = "/testfiles/otherpermissiontestfiles/test.dat" f.update() f2 = db.execute_query("FIND TestFile", unique=True) - assert_equal(f2.path, "/otherpermissiontestfiles/test.dat") + assert_equal(f2.path, "/testfiles/otherpermissiontestfiles/test.dat") deny_permission(f, "UPDATE:FILE:MOVE") '''FAILURE''' - f.path = "/againotherpermissiontestfiles/test.dat" + f.path = "/testfiles/againotherpermissiontestfiles/test.dat" with raises(db.TransactionError) as te: f.update() assert te.value.has_error(db.AuthorizationError) f2 = db.execute_query("FIND TestFile", unique=True) - assert f2.path == "/otherpermissiontestfiles/test.dat" + assert f2.path == "/testfiles/otherpermissiontestfiles/test.dat" def test_update_add_file(): @@ -529,7 +533,7 @@ def test_update_add_file(): grant_permission(f, "RETRIEVE:ENTITY") '''FAILURE''' - f.path = "/permissiontestfiles/newtest.dat" + f.path = "/testfiles/permissiontestfiles/newtest.dat" f.file = upload_file with raises(db.TransactionError) as te: f.update() @@ -542,13 +546,13 @@ def test_update_add_file(): grant_permission(f, "UPDATE:FILE:ADD") f2 = db.execute_query("FIND TestFile", unique=True) - f2.path = "/permissiontestfiles/newtest.dat" + f2.path = "/testfiles/permissiontestfiles/newtest.dat" f2.file = upload_file f2.update() assert f2.is_valid() f2 = db.execute_query("FIND TestFile", unique=True) - assert_equal(f2.path, "/permissiontestfiles/newtest.dat") + assert_equal(f2.path, "/testfiles/permissiontestfiles/newtest.dat") def test_update_change_file(): @@ -563,7 +567,7 @@ def test_update_change_file(): f = db.File( name="TestFile", file=upload_file, - path="permissiontestfiles/test.dat").insert() + path="testfiles/permissiontestfiles/test.dat").insert() assert f.is_valid() grant_permission(f, "RETRIEVE:ENTITY") grant_permission(f, "RETRIEVE:FILE") @@ -925,7 +929,7 @@ def test_download_file(): f = db.File( name="TestFile", file=upload_file, - path="permissiontestfiles/test.dat").insert() + path="testfiles/permissiontestfiles/test.dat").insert() assert f.is_valid() '''FAILURE''' @@ -1110,7 +1114,6 @@ def test_use_as_parent(): datatype=db.TEXT).add_parent( name="TestProperty") - deny_permission(p, "USE:AS_PARENT") '''Failure''' deny_permission(p, "USE:AS_PARENT") with raises(db.TransactionError) as cm: diff --git a/tests/test_properties.py b/tests/test_properties.py index ffedcdbd2bd38a7ee993307f52514da9116daf24..ca6aac4a5de393647f20d6143a775116f6b72bf8 100644 --- a/tests/test_properties.py +++ b/tests/test_properties.py @@ -32,11 +32,11 @@ def setup_module(): d.delete() -def setup(): +def setup_function(function): setup_module() -def teardown(): +def teardown_function(function): setup_module() diff --git a/tests/test_query.py b/tests/test_query.py index 92639f2cc67002360a282089b94690e6304b4561..403aa0ad3acf7712f10701844bfa6b8841c275d2 100644 --- a/tests/test_query.py +++ b/tests/test_query.py @@ -43,16 +43,16 @@ def setup_module(): assert perms == set() -def setup(): +def setup_function(function): try: - db.execute_query("FIND Test*").delete() + db.execute_query("FIND *").delete() except Exception as e: print(e) -def teardown(): +def teardown_function(function): db.configure_connection() - setup() + setup_function(function) try: os.remove("test.dat") except Exception as e: @@ -633,9 +633,8 @@ def store_file(path, name=None, f=None): def test_stored_at_wildcards(): - upload_file = open("test.dat", "w") - upload_file.write("hello world\n") - upload_file.close() + with open("test.dat", "w") as upload_file: + upload_file.write("hello world\n") file1 = store_file("test1.dat", f=upload_file) diff --git a/tests/test_query_template.py b/tests/test_query_template.py index e4c662d6d166e0b64bab6e16733b455ff3de1254..58eccf87b502587c9c7ce0c0424012006167fc03 100644 --- a/tests/test_query_template.py +++ b/tests/test_query_template.py @@ -78,11 +78,11 @@ def teardown_module(): print(e) -def setup(): +def setup_function(function): pass -def teardown(): +def teardown_function(function): db.configure_connection() try: db.execute_query("FIND QUERYTEMPLATE Test*").delete() diff --git a/tests/test_query_version.py b/tests/test_query_version.py index 860bc68514327a8bbfc90777abac4974344b820f..bf6b368ff91101db7e2a4409babdfa6c8fe57c23 100644 --- a/tests/test_query_version.py +++ b/tests/test_query_version.py @@ -25,9 +25,8 @@ import caosdb as db import pytest from caosdb import execute_query as query -db.configure_connection() CONTAINER = db.Container() -NAME_PROPERTY = db.Property("name").retrieve() +NAME_PROPERTY = db.Property("name") TEST_PROP_TEXT = db.Property("TestPropertyText", datatype=db.TEXT) TEST_PROP_DOUBLE = db.Property("TestPropertyDouble", datatype=db.DOUBLE) TEST_PROP_INTEGER = db.Property("TestPropertyInteger", datatype=db.INTEGER) @@ -88,6 +87,8 @@ def teardown_module(): def setup_module(): + db.configure_connection() + NAME_PROPERTY.retrieve() CONTAINER.extend([TEST_RT_1, TEST_REC_1, TEST_PROP_TEXT, TEST_PROP_DOUBLE, TEST_PROP_INTEGER, TEST_PROP_DATETIME, TEST_PROP_DATE, TEST_REF_RT, TEST_REF_1, TEST_REF_2, TEST_REF_3, diff --git a/tests/test_records.py b/tests/test_records.py index 011ebef67568f7b4bd6ff0097e601cef414c5fdb..182375ba2495539025b47cb604f1acaed07adade 100644 --- a/tests/test_records.py +++ b/tests/test_records.py @@ -30,7 +30,7 @@ from caosdb.exceptions import CaosDBException import caosdb -def teardown(): +def teardown_function(function): try: caosdb.execute_query("FIND Test*").delete() except Exception as e: diff --git a/tests/test_recursive_parents.py b/tests/test_recursive_parents.py index 1efd9390d9a01a417f91bca1cce7f0f76c154e4b..76178cee37db9ebeb2d249837bdfde80baa58141 100644 --- a/tests/test_recursive_parents.py +++ b/tests/test_recursive_parents.py @@ -38,12 +38,12 @@ def setup_module(): raise_exception_on_error=False) -def setup(): +def setup_function(function): """No further setup required""" setup_module() -def teardown(): +def teardown_function(function): """Delete again""" setup_module() diff --git a/tests/test_server_side_scripting.py b/tests/test_server_side_scripting.py index 1c032523d1efee8c4c930235f79e8fd81259cc2c..5801f98a7b634c2c391d531be42f3c4878cc1d2c 100644 --- a/tests/test_server_side_scripting.py +++ b/tests/test_server_side_scripting.py @@ -70,11 +70,11 @@ def clean_database(): d.delete() -def setup(): +def setup_function(function): clean_database() -def teardown(): +def teardown_function(function): admin.set_server_property("SERVER_SIDE_SCRIPTING_BIN_DIRS", _ORIGINAL_SERVER_SCRIPTING_BIN_DIR) clean_database() @@ -227,7 +227,8 @@ def test_diagnostics_basic(): print(etree.tostring(xml)) assert response.status == 200 # ok - assert response.getheader("Content-Type") == 'text/xml; charset=UTF-8' + assert "text/xml" in response.getheader("Content-Type").lower() + assert "charset=utf-8" in response.getheader("Content-Type").lower() diagnostics = xml.xpath("/Response/script/stdout")[0].text assert diagnostics is not None @@ -266,7 +267,8 @@ def test_diagnostics_with_file_upload(): response = get_connection().insert( ["scripting"], body=body, headers=headers) assert response.status == 200 # ok - assert response.getheader("Content-Type") == 'text/xml; charset=UTF-8' + assert "text/xml" in response.getheader("Content-Type").lower() + assert "charset=utf-8" in response.getheader("Content-Type").lower() xml = etree.parse(response) print(etree.tostring(xml)) @@ -316,7 +318,8 @@ def test_call_as_anonymous_with_administration_role(): xml = etree.parse(response) assert response.getheader("Set-Cookie") is None # no auth token returned - assert response.getheader("Content-Type") == 'text/xml; charset=UTF-8' + assert "text/xml" in response.getheader("Content-Type").lower() + assert "charset=utf-8" in response.getheader("Content-Type").lower() assert response.status == 200 # ok assert xml.xpath("/Response/script/@code")[0] == "0" @@ -390,7 +393,8 @@ def test_anonymous_script_calling_success(): body=urlencode(form)) assert response.status == 200 # ok assert response.getheader("Set-Cookie") is None # no auth token returned - assert response.getheader("Content-Type") == 'text/xml; charset=UTF-8' + assert "text/xml" in response.getheader("Content-Type").lower() + assert "charset=utf-8" in response.getheader("Content-Type").lower() body = response.read() xml = etree.fromstring(body) diff --git a/tests/test_state.py b/tests/test_state.py index 1bc8a49c823eedd3479e52f9841bd6ac578346a6..0b2c510d5c78609e9f9797336687446a7b20e2d6 100644 --- a/tests/test_state.py +++ b/tests/test_state.py @@ -1,3 +1,25 @@ +# encoding: utf-8 +# +# This file is a part of the CaosDB Project. +# +# Copyright (C) 2020-2022 IndiScale GmbH <info@indiscale.com> +# Copyright (C) 2020-2022 Timm Fitschen <t.fitschen@indiscale.com> +# +# This program is free software: you can redistribute it and/or modify it under +# the terms of the GNU Affero General Public License as published by the Free +# Software Foundation, either version 3 of the License, or (at your option) any +# later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more +# details. +# +# You should have received a copy of the GNU Affero General Public License along +# with this program. If not, see <https://www.gnu.org/licenses/>. +# +# ** end header +# import pytest import caosdb as db from caosdb import administration as admin @@ -49,6 +71,8 @@ def setup_users(): "Grant", "STATE:TRANSITION:Transition4"), db.administration.PermissionRule( "Grant", "STATE:TRANSITION:EditTransition"), + db.administration.PermissionRule( + "Grant", "STATE:TRANSITION:StartReviewTransition"), ]) db.administration._set_permissions( role="team-leader", permission_rules=[ @@ -109,6 +133,7 @@ def setup_module(): "ACL": None}) state_acl = db.ACL() state_acl.grant(role="role1", permission="UPDATE:DESCRIPTION") + state_acl.deny(role="anonymous", permission="RETRIEVE:ENTITY") state_acl = db.State.create_state_acl(state_acl) st1.acl = state_acl.combine(st1.acl) st1.update_acl() @@ -142,16 +167,18 @@ def setup_module(): "State1").insert() -def teardown(): +def teardown_function(function): switch_to_admin_user() + # deactivate anonymous user + db.administration.set_server_property("AUTH_OPTIONAL", "FALSE") d = db.execute_query("FIND TestRT") if len(d) > 0: d.delete(flags={"forceFinalState": "true"}) -def setup(): +def setup_function(function): admin.set_server_property("EXT_ENTITY_STATE", "ENABLED") - teardown() + teardown_function(function) db.RecordType("TestRT").insert() @@ -478,10 +505,16 @@ def test_transfer_state_acl(): rec.state = db.State(model="Model1", name="State1") insert_rec = rec.insert(flags={"ACL": None}) - state_acl = db.ACL().combine(db.get_global_acl()) + state_acl = db.ACL() state_acl.grant(role="role1", permission="UPDATE:DESCRIPTION") + state_acl.deny(role="anonymous", permission="RETRIEVE:ENTITY") + state_acl = state_acl.combine(db.get_global_acl()) # the acl has been transfered from the state record + assert insert_rec.acl.get_permissions_for_role("role1") == { + "UPDATE:DESCRIPTION"} + assert "RETRIEVE:ENTITY" not in insert_rec.acl.get_permissions_for_role( + "anonymous") assert insert_rec.acl == state_acl @@ -624,11 +657,11 @@ def test_full_edit_review_publish_cycle(): rec.update() # start review - switch_to_test_user("team-leader") rec.state = db.State(model="EditReviewPublish", name="ReviewState") rec.update() # as team-leader + switch_to_test_user("team-leader") rec.get_property("TestProperty").value = next(val) rec.update() @@ -804,3 +837,29 @@ def test_transitions_included_after_empty_update(): db.Transition(name="Transition4", from_state="State2", to_state="State2")} + + +def test_missing_retrieve_permission(): + """When the retrieve permission is missing, the state must not be leaked.""" + # @review Florian Spreckelsen 2022-03-22 + rec = db.Record() + rec.description = "old description" + rec.add_parent("TestRT") + rec.state = db.State(model="Model1", name="State1") + rec.insert(flags={"ACL": None}) + print(rec) + + # switch to anonymous + db.administration.set_server_property("AUTH_OPTIONAL", "TRUE") + db.configure_connection(password_method="unauthenticated") + assert db.Info().user_info.roles == ["anonymous"] + + rec2 = db.Record(id=rec.id) + with pytest.raises(db.TransactionError) as te: + rec2.retrieve() + assert te.value.has_error(db.AuthorizationError) + + rec2 = db.Record(id=rec.id) + rec2.retrieve(raise_exception_on_error=False) + assert len(rec2.get_errors()) > 0 + assert rec2.state is None diff --git a/tests/test_tickets.py b/tests/test_tickets.py index bcffcd31a05b1fcce33af415f9e27bcc11579b6b..fb41af36e86131fa913d83faf391ca02c90cd82a 100644 --- a/tests/test_tickets.py +++ b/tests/test_tickets.py @@ -32,14 +32,14 @@ import pytest from tests import test_misc -def setup(): +def setup_function(function): d = db.execute_query("FIND Test*") if len(d) > 0: d.delete() -def teardown(): - setup() +def teardown_function(function): + setup_function(function) def test_ticket_103a(): diff --git a/tests/test_tickets_300.py b/tests/test_tickets_300.py index 43fbd97f0fc3ea67e23736657d9cac07886fff35..cf34637d82d3a8dfb00751d26f3b7cfc40351d60 100644 --- a/tests/test_tickets_300.py +++ b/tests/test_tickets_300.py @@ -45,11 +45,11 @@ def teardown_module(): _delete_test_entities() -def setup(): +def setup_function(function): setup_module() -def teardown(): +def teardown_function(function): teardown_module() diff --git a/tests/test_update.py b/tests/test_update.py index f783ff1339289679e1866e7ae8130560d1c76500..becaf5bb4469650f54c481977b1e05d2c667812f 100644 --- a/tests/test_update.py +++ b/tests/test_update.py @@ -34,14 +34,14 @@ from caosdb.common.utils import xml2str from caosdb.common.models import raise_errors -def setup(): +def setup_function(function): d = db.execute_query("FIND Entity WITH ID > 99") if len(d) > 0: d.delete() -def teardown(): - setup() +def teardown_function(function): + setup_function(function) def test_property_no_id(): diff --git a/tests/test_version.py b/tests/test_version.py index 2b8aafa882832a419fe1b796a703b0b31cb3b766..4abf10a19f8e4c059334d5e247b0aae59738f395 100644 --- a/tests/test_version.py +++ b/tests/test_version.py @@ -25,14 +25,14 @@ from pytest import mark, raises import caosdb as c -def setup(): +def setup_function(function): d = c.execute_query("FIND Test*") if len(d) > 0: d.delete() -def teardown(): - setup() +def teardown_function(function): + setup_function(function) def test_version_object(): diff --git a/tox.ini b/tox.ini index 26c5d1594c48fe755a355a3aee711fd6608c6f97..03ab50d132a82e6f7ee4b26cb55156e211f24b01 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,10 @@ [tox] -envlist=py36, py37, py38, py39 +envlist=py36, py37, py38, py39, py310 skip_missing_interpreters = true + +[pycodestyle] +max_line_length = 100 + [testenv] setenv = PASSWORD_STORE_DIR = {env:HOME}/.password-store passenv = PYCAOSDBINI