Skip to content
Snippets Groups Projects
Select Git revision
  • 766eac99e9b218d82ca114fac23820c2eb31be75
  • main default protected
  • dev protected
  • f-fix-accent-sensitivity
  • f-filesystem-import
  • f-update-acl
  • f-filesystem-link
  • f-filesystem-directory
  • f-filesystem-core
  • f-filesystem-cleanup
  • f-string-ids
  • f-filesystem-main
  • f-multipart-encoding
  • f-trigger-advanced-user-tools
  • f-real-rename-test-pylibsolo2
  • f-real-rename-test-pylibsolo
  • f-real-rename-test
  • f-linkahead-rename
  • f-reference-record
  • f-xml-serialization
  • f-xfail-server-181
  • linkahead-pylib-v0.18.0
  • linkahead-control-v0.16.0
  • linkahead-pylib-v0.17.0
  • linkahead-mariadbbackend-v8.0.0
  • linkahead-server-v0.13.0
  • caosdb-pylib-v0.15.0
  • caosdb-pylib-v0.14.0
  • caosdb-pylib-v0.13.2
  • caosdb-server-v0.12.1
  • caosdb-pylib-v0.13.1
  • caosdb-pylib-v0.12.0
  • caosdb-server-v0.10.0
  • caosdb-pylib-v0.11.1
  • caosdb-pylib-v0.11.0
  • caosdb-server-v0.9.0
  • caosdb-pylib-v0.10.0
  • caosdb-server-v0.8.1
  • caosdb-pylib-v0.8.0
  • caosdb-server-v0.8.0
  • caosdb-pylib-v0.7.2
41 results

test_issues_server.py

Blame
  • Code owners
    Assign users and groups as approvers for specific file changes. Learn more.
    test_issues_server.py 16.65 KiB
    # -*- 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) 2020 Florian Spreckelsen <f.spreckelsen@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
    
    """Tests for issues on gitlab.com, project caosdb-server."""
    
    import os
    import tempfile
    import time
    
    import caosdb as db
    import pytest
    from caosdb.exceptions import TransactionError
    
    
    def setup_module():
        try:
            db.execute_query("FIND ENTITY WITH ID > 99").delete()
        except Exception as delete_exc:
            print(delete_exc)
    
    
    def setup():
        """No setup required."""
        setup_module()
    
    
    def teardown():
        """Deleting entities again."""
        setup_module()
        pass
    
    
    # ########################### Issue tests start here #####################
    
    
    def test_issue_39():
        """Query Language Bug - quotes around year
    
        Test for https://gitlab.com/caosdb/caosdb-server/-/issues/39
        """
        date_str = "2020-01-01"
        prop_name = "Test_Date"
        db.Property(name=prop_name, datatype=db.DATETIME).insert()
        db.RecordType(name="Test_Type").add_property(name=prop_name).insert()
        db.Record(name="Test_Record").add_parent(name="Test_Type").add_property(
            name=prop_name, value=date_str).insert()
        # Quotes around years should work in the query
        ent = db.execute_query("FIND entity WITH A Test_Date IN \"2020\"",
                               unique=True)
        assert ent.get_property(prop_name).value == date_str
        # This should raise a transaction error
        with pytest.raises(TransactionError):
            db.execute_query("FIND entity WITH A Test_Date IN \"abcd\"")
    
    
    @pytest.mark.xfail(reason="to be fixed in server repo")
    def test_issue_62():
        """datatype is not changed when recordtype name changes
    
        Tests for https://gitlab.com/caosdb/caosdb-server/-/issues/62
        """
        db.RecordType(name="Test_RTA").insert()
        db.Property(name="Test_Prop", datatype="Test_RTA").insert()
        db.Record(name="Test_Record").add_parent(
            name="Test_RTA").add_property(name="Test_Prop").insert()
        # rename Test_RTA to Test_RTB
        rtb = db.execute_query("FIND RecordType Test_RTA", unique=True)
        rtb.name = "Test_RTB"
        rtb.update()
        # renaming has to be reflected in Test_Record and Test_Prop
        rec = db.execute_query("FIND Record Test_Record", unique=True)
        assert rec.parents[0].name == rtb.name
        prop = db.execute_query("FIND Property Test_Prop", unique=True)
        assert prop.datatype == rtb.name  # fails; datatype not updated
        # Can't use Test_RTA as datatype anymore
        prop2 = db.Property(name="Test_Prop2", datatype="Test_RTA")
        with pytest.raises(TransactionError):
            prop2.insert()
    
    
    def test_issue_85_a():
        """SQLIntegrityConstraintViolationException for special inheritance patterns.
    
        Tests for https://gitlab.com/caosdb/caosdb-server/-/issues/85
        """
        A = db.RecordType(name="A")
        B = db.RecordType(name="B")
        C = db.RecordType(name="C")
    
        B.add_parent(A)
    
        # This order is important for the test to fail.
        C.add_parent(B)
        C.add_parent(C)
        C.add_parent(A)
    
        c = db.Container()
        # c.extend([C, B, A])  # worked before #86 was fixed
        # c.extend([C, A, B])  # worked before #86 was fixed
        c.extend([B, C, A])    # insert() failed before #86 was fixed
        c.insert()  # Raised java.sql.SQLIntegrityConstraintViolationException:
        #           # Duplicate entry '12345-12346-12345' for key 'PRIMARY'
    
    
    def test_issue_85_b():
        """SQLIntegrityConstraintViolationException for special inheritance patterns.
    
        Tests for https://gitlab.com/caosdb/caosdb-server/-/issues/85
        """
        A = db.RecordType(name="A")
        B = db.RecordType(name="B")
        C = db.RecordType(name="C")
        A.insert()
        B.insert()
        C.insert()
        B.add_parent(A)
        B.update()
        C.add_parent(B)
        C.update()
        C.add_parent(C)
        C.update()
        C.add_parent(A)
        C.update()  # Failed at this step
    
    
    @pytest.mark.local_server
    def test_issue_99():
        """Checksum updating failed with versioning enabled.
        """
    
        # Using files in extroot, because this allows us to update the file
        # content from the outside.
        local_dir = os.path.join(db.get_config().get("IntegrationTests",
                                                     "test_files.test_insert_files_in_dir.local"),
                                 "test_issue_99")
        docker_dir = os.path.join(db.get_config().get("IntegrationTests",
                                                      "test_files.test_insert_files_in_dir.server"),
                                  "test_issue_99")
        os.makedirs(local_dir, exist_ok=True)
        with tempfile.NamedTemporaryFile(dir=local_dir) as file_99:
            # Create File entity in CaosDB
            file_99.write("test 99\n".encode())
            os.fchmod(file_99.fileno(), 0o744)  # make the file world readable
            cont = db.Container()
            cont.insert(unique=False, raise_exception_on_error=False,
                        flags={"InsertFilesInDir": docker_dir})
            dbfile = cont[0]
    
            # Checksum should exist after a short time
            time.sleep(0.1)
            dbfile.retrieve()
            assert dbfile.checksum is not None
    
    
    def test_issue_110():
        """query ignores ID: FIND MusicalInstrument which is referenced by Analysis with ID=124 """
        cont = db.Container()
        A = db.RecordType(name="TypeA")
        B = db.RecordType(name="TypeB")
        prop = db.Property(name="prop_ba", datatype=db.REFERENCE)
    
        # Referenced Records
        a1 = db.Record().add_parent(A)
        a2 = db.Record().add_parent(A)
    
        # Referencing Records
        b1 = db.Record().add_parent(B).add_property(prop, value=a1)
        b2 = db.Record().add_parent(B).add_property(prop, value=a2)
    
        cont.extend([A, B, prop, a1, a2, b1, b2])
        cont.insert()
    
        id_b1 = b1.id
        query = "FIND TypeA WHICH IS REFERENCED BY TypeB WITH ID={}".format(id_b1)
        print(query)
        result = db.execute_query(query)
        print(result)
        assert len(result) == 1
        print(result[0])
        print(a1)
        assert result[0].id == a1.id
    
    
    def test_issue_120():
        """Editing entities that were created with a no longer existing user leads
        to a server error.
    
        The server should throw an error when CHECK_ENTITY_ACL_ROLES_MODE=MUST,
        otherwise a warning.
        """
        # insert an entity
        entity = db.RecordType("TestRT").insert(flags={"ACL": None})
    
        db.administration.set_server_property("CHECK_ENTITY_ACL_ROLES_MODE",
                                              "SHOULD")
        # update with non-existing user, realm and role
        entity.deny(
            realm="CaosDB",
            username="NON_EXISTING_USER",
            permission="USE:AS_REFERENCE")
        entity.update(flags={"ACL": None})
        assert entity.messages["Warning", 1104][0] == "User Role does not exist."
    
        entity.deny(
            realm="NON_EXISTING_REALM",
            username="NON_EXISTING_USER",
            permission="USE:AS_REFERENCE")
        entity.update(flags={"ACL": None})
        assert entity.messages["Warning", 1104][0] == "User Role does not exist."
    
        entity.deny(
            role="ALSO_NON_EXISTING_ROLE",
            permission="USE:AS_REFERENCE")
        entity.update(flags={"ACL": None})
        assert entity.messages["Warning", 1104][0] == "User Role does not exist."
    
    
    def test_issue_134():
        """multiple white space characters after `FROM`"""
        db.execute_query("SELECT pname FROM  ename")
    
    
    def test_issue_131():
        """white space befor unit with strange character"""
        rt = db.RecordType(name="TestType").insert()
        prop = db.Property(name="TestProp", datatype=db.INTEGER, unit="").insert()
        rec = db.Record(name="TestRecord").add_property(
            name=prop.name, value=101, unit="")
        rec.add_parent(rt)
        rec.insert()
        result_ids = [ent.id for ent in db.execute_query(
            "FIND Entity WITH {} > 100 €".format(prop.name))]
    
        assert rec.id in result_ids
    
        result_ids = [ent.id for ent in db.execute_query(
            "FIND Entity WITH {} > 100.5 €".format(prop.name))]
    
        assert rec.id in result_ids
    
    
    def test_issue_154_no_versioning():
        """ FIND MusicalInstrument WITH Manufacturer = "Antonio Stradivari" and
        FIND MusicalInstrument WITH Manufacturer != "Antonio Stradivari" """
        rt_man = db.RecordType("Manufacturer")
        rt_inst = db.RecordType("MusicalInstrument").add_property(rt_man)
    
        rec_man = db.Record("Antonio Stradivari").add_parent("Manufacturer")
        rec_man2 = db.Record("The other guy").add_parent("Manufacturer")
        rec_inst = db.Record("Violin").add_parent(
            "MusicalInstrument").add_property("Manufacturer", rec_man)
        rec_inst2 = db.Record("Guitar").add_parent(
            "MusicalInstrument").add_property("Manufacturer", rec_man2)
        rec_inst3 = db.Record("Broken Record").add_parent("MusicalInstrument")
    
        c = db.Container().extend([rt_man, rt_inst, rec_man, rec_inst, rec_man2,
                                   rec_inst2, rec_inst3]).insert()
    
        assert "Violin" not in [e.name for e in db.execute_query(
            "FIND RECORD MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")]
        assert "Violin" not in [e.name for e in db.execute_query(
            "FIND RECORD MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")]
        assert len(db.execute_query("FIND MusicalInstrument")) == 4
        assert len(db.execute_query("FIND RECORD MusicalInstrument")) == 3
        assert len(db.execute_query(
            "FIND MusicalInstrument WITH Manufacturer")) == 3
        assert len(db.execute_query(
            "FIND RECORD MusicalInstrument WITH Manufacturer")) == 2
        assert rec_inst.id == db.execute_query(
            "FIND MusicalInstrument WITH Manufacturer = 'Antonio Stradivari'",
            unique=True).id
        assert len(db.execute_query(
            "FIND MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")) == 3
        assert len(db.execute_query(
            "FIND RECORD MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")) == 2
        assert len(db.execute_query(
            "FIND MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")) == 1
        assert len(db.execute_query(
            "FIND RECORD MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")) == 1
    
    
    def test_issue_154_with_versioning():
        """ FIND MusicalInstrument WITH Manufacturer = "Antonio Stradivari" and
        FIND MusicalInstrument WITH Manufacturer != "Antonio Stradivari" """
        rt_man = db.RecordType("Manufacturer")
        rt_inst = db.RecordType("MusicalInstrument").add_property(rt_man)
    
        rec_man = db.Record("Antonio Stradivari").add_parent("Manufacturer")
        rec_man2 = db.Record("The other guy").add_parent("Manufacturer")
        rec_inst = db.Record("Violin").add_parent(
            "MusicalInstrument").add_property("Manufacturer", rec_man)
        rec_inst2 = db.Record("Guitar").add_parent(
            "MusicalInstrument").add_property("Manufacturer", rec_man2)
        rec_inst3 = db.Record("Broken Record").add_parent("MusicalInstrument")
    
        db.Container().extend([rt_man, rt_inst, rec_man,
                               rec_inst, rec_man2, rec_inst2, rec_inst3]).insert()
    
        assert "Violin" not in [e.name for e in db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")]
        assert "Violin" not in [e.name for e in db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")]
        assert len(db.execute_query("FIND ANY VERSION OF MusicalInstrument")) == 4
        assert len(db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument")) == 3
        assert len(db.execute_query(
            "FIND ANY VERSION OF MusicalInstrument WITH Manufacturer")) == 3
        assert len(db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH Manufacturer")) == 2
        assert rec_inst.id == db.execute_query(
            "FIND ANY VERSION OF MusicalInstrument WITH Manufacturer = 'Antonio Stradivari'",
            unique=True).id
        assert len(db.execute_query(
            "FIND ANY VERSION OF MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")) == 3
        assert len(db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")) == 2
        assert len(db.execute_query(
            "FIND ANY VERSION OF MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")) == 1
        assert len(db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")) == 1
    
        # now, some updates
        rt_man.description = "Updated Description"
        rt_inst.description = "Updated Description"
    
        rec_man.description = "Updated Description"
        rec_man2.description = "Updated Description"
        rec_inst.description = "Updated Description"
        rec_inst2.description = "Updated Description"
        rec_inst3.description = "Updated Description"
        db.Container().extend([rt_man, rt_inst, rec_man,
                               rec_inst, rec_man2, rec_inst2, rec_inst3]).update()
    
        assert "Violin" not in [e.name for e in db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")]
        assert "Violin" not in [e.name for e in db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")]
        assert len(db.execute_query("FIND ANY VERSION OF MusicalInstrument")) == 8
        assert len(db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument")) == 6
        assert len(db.execute_query(
            "FIND ANY VERSION OF MusicalInstrument WITH Manufacturer")) == 6
        assert len(db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH Manufacturer")) == 4
        assert len(db.execute_query(
            "FIND ANY VERSION OF MusicalInstrument WITH Manufacturer = 'Antonio Stradivari'")) == 2
        assert len(db.execute_query(
            "FIND ANY VERSION OF MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")) == 6
        assert len(db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH NOT Manufacturer = 'Antonio Stradivari'")) == 4
        assert len(db.execute_query(
            "FIND ANY VERSION OF MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")) == 2
        assert len(db.execute_query(
            "FIND ANY VERSION OF RECORD MusicalInstrument WITH Manufacturer != 'Antonio Stradivari'")) == 2
    
    
    def test_issue_127():
        """https://gitlab.com/caosdb/caosdb-server/-/issues/127"""
        p = db.Property(
            name="TestDoubleProperty",
            datatype=db.LIST(
                db.DOUBLE)).insert()
        rt = db.RecordType(name="TestRecordType").add_property(name="TestDoubleProperty",
                                                               value=["nan"]).insert()
    
        test1 = db.execute_query("FIND TestRecordType", unique=True)
        assert math.isnan(test1.get_property("TestDoubleProperty").value[0])
    
        test2 = db.execute_query(
            "FIND TestRecordType WITH TestDoubleProperty = NaN", unique=True)
        assert math.isnan(test1.get_property("TestDoubleProperty").value[0])
    
    
    def test_issue_170():
        """update scalar data type to list data type"""
        p = db.Property(name="TestProp1", datatype=db.LIST(db.INTEGER))
        p.value = [1, 2]
        p.insert()
    
        p2 = db.execute_query("FIND TestProp1", unique=True)
        assert p2.datatype == db.LIST(db.INTEGER)
        assert p2.value == [1, 2]
    
        p.description = "TestDescription"
        p.update()  # this failed
    
        p2 = db.execute_query("FIND TestProp1", unique=True)
        assert p2.datatype == db.LIST(db.INTEGER)
        assert p2.value == [1, 2]
        assert p2.description == "TestDescription"
    
        p = db.Property(name="TestProp2", datatype=db.DOUBLE)
        p.insert()
    
        p.datatype = db.LIST(db.INTEGER)
        p.update()  # this worked because no value yet
        p2 = db.execute_query("FIND TestProp2", unique=True)
        assert p2.datatype == db.LIST(db.INTEGER)
        p.value = [1, 2]
    
        p.update()  # this failed
        p2 = db.execute_query("FIND TestProp2", unique=True)
        assert p2.datatype == db.LIST(db.INTEGER)
        assert p2.value == [1, 2]
    
        p = db.Property(name="TestProp3", datatype=db.DOUBLE)
        p.insert()
    
        p.datatype = db.LIST(db.INTEGER)
        p.value = [1, 2]
        p.update()  # this failed
    
        p2 = db.execute_query("FIND TestProp3", unique=True)
        assert p2.datatype == db.LIST(db.INTEGER)
        assert p2.value == [1, 2]