diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 42e7907b8d802faa6a4fc20d89ce1c677a85e6df..d0d0982745ac95edadccfef823ac0931c6a5e39e 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -163,7 +163,6 @@ test:
   dependencies: [cert]
   timeout: 3h
   artifacts:
-    when: on_failure
     paths:
       - caosdb_log.txt
       - mariadb_log.txt
@@ -218,10 +217,12 @@ cert:
   script:
       - cd .docker
       - CAOSHOSTNAME=caosdb-server ./cert.sh
+
 style:
   tags: [docker]
   stage: style
   image: $CI_REGISTRY_IMAGE
+  needs: []
   script:
       - autopep8 -r --diff --exit-code .
   allow_failure: true
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_issues_server.py b/tests/test_issues_server.py
index a61be841f25ef8c619084f912be37cba31f59349..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."""
 
@@ -553,7 +549,6 @@ def test_issue_130():
     assert row == [("ReferencedRecord",)]  # FAILS
 
 
-@pytest.mark.xfail(reason="fix https://gitlab.com/caosdb/caosdb-server/-/issues/132")
 def test_issue_132():
     """Query: Parenthesis around subproperties.
 
@@ -604,3 +599,108 @@ def test_issue_132():
     # 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_state.py b/tests/test_state.py
index eee4b1dad6485ab9e2c238a0cc87398eab1dbafa..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
@@ -111,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()
@@ -146,6 +169,8 @@ def setup_module():
 
 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"})
@@ -480,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
 
 
@@ -806,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/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