Repository: conan-io/conan
Pull request #16642 (2024-07-10 06:22:42)

[settings] subsettings from fake settings 
Changelog: Bugfix: Avoid `settings.update_values()` failing when deducing compatibility. Otherwise, it will fail.
Docs: omit

cc @AbrilRBS 


Patch:
diff --git a/conan/tools/cmake/layout.py b/conan/tools/cmake/layout.py
index dad6ce312..fbff89c20 100644
--- a/conan/tools/cmake/layout.py
+++ b/conan/tools/cmake/layout.py
@@ -94,9 +94,11 @@ def get_build_folder_custom_vars(conanfile):
                     tmp = "{}_{}".format(var, value)
         elif group == "self":
             tmp = getattr(conanfile, var, None)
+        elif group == "const":
+            tmp = var
         else:
             raise ConanException("Invalid 'tools.cmake.cmake_layout:build_folder_vars' value, it has"
-                                 " to start with 'settings.' or 'options.': {}".format(s))
+                                 f" to start with 'settings.', 'options.', 'self.' or 'const.': {s}")
         if tmp:
             ret.append(tmp.lower())
 
diff --git a/conan/tools/cmake/toolchain/blocks.py b/conan/tools/cmake/toolchain/blocks.py
index 0d6585718..425e62b2a 100644
--- a/conan/tools/cmake/toolchain/blocks.py
+++ b/conan/tools/cmake/toolchain/blocks.py
@@ -724,7 +724,7 @@ class ExtraFlagsBlock(Block):
         {% if defines %}
         {% if config %}
         {% for define in defines %}
-        add_compile_definitions($<$<CONFIG:{{config}}>:"{{ define }}">)
+        add_compile_definitions("$<$<CONFIG:{{config}}>:{{ define }}>")
         {% endfor %}
         {% else %}
         add_compile_definitions({% for define in defines %} "{{ define }}"{% endfor %})
diff --git a/conan/tools/gnu/gnutoolchain.py b/conan/tools/gnu/gnutoolchain.py
index 95c32129e..9848e18fc 100644
--- a/conan/tools/gnu/gnutoolchain.py
+++ b/conan/tools/gnu/gnutoolchain.py
@@ -123,15 +123,13 @@ class GnuToolchain:
         if is_msvc(self._conanfile):
             extra_env_vars = {"CC": "cl -nologo",
                               "CXX": "cl -nologo",
-                              "LD": "link -nologo",
-                              "AR": "lib",
                               "NM": "dumpbin -symbols",
                               "OBJDUMP": ":",
                               "RANLIB": ":",
                               "STRIP": ":"}
         # Configuration map
         compilers_mapping = {"c": "CC", "cpp": "CXX", "cuda": "NVCC", "fortran": "FC",
-                             "rc": "RC", "ld": "LD", "ar": "AR", "nm": "NM", "ranlib": "RANLIB",
+                             "rc": "RC", "nm": "NM", "ranlib": "RANLIB",
                              "objdump": "OBJDUMP", "strip": "STRIP"}
         # Compiler definitions by conf
         compilers_by_conf = self._conanfile.conf.get("tools.build:compiler_executables", default={},
diff --git a/conan/tools/scm/git.py b/conan/tools/scm/git.py
index 1c8a12fc0..117a064b8 100644
--- a/conan/tools/scm/git.py
+++ b/conan/tools/scm/git.py
@@ -34,6 +34,7 @@ class Git:
                 self._excluded = c.get("core.scm:excluded", check_type=list)
             else:
                 self._excluded = conf_excluded
+        self._local_url = global_conf.get("core.scm:local_url", choices=["allow", "block"])
 
     def run(self, cmd, hidden_output=None):
         """
@@ -176,16 +177,14 @@ class Git:
         in_remote = self.commit_in_remote(commit, remote=remote)
         if in_remote:
             return url, commit
-        # TODO: Once we know how to pass [conf] to export, enable this
-        # conf_name = "tools.scm:local"
-        # allow_local = self._conanfile.conf[conf_name]
-        # if not allow_local:
-        #    raise ConanException("Current commit {} doesn't exist in remote {}\n"
-        #                         "use '-c {}=1' to allow it".format(commit, remote, conf_name))
-
-        self._conanfile.output.warning("Current commit {} doesn't exist in remote {}\n"
-                                       "This revision will not be buildable in other "
-                                       "computer".format(commit, remote))
+        if self._local_url == "block":
+            raise ConanException(f"Current commit {commit} doesn't exist in remote {remote}\n"
+                                 "Failing according to 'core.scm:local_url=block' conf")
+
+        if self._local_url != "allow":
+            self._conanfile.output.warning("Current commit {} doesn't exist in remote {}\n"
+                                           "This revision will not be buildable in other "
+                                           "computer".format(commit, remote))
         return self.get_repo_root(), commit
 
     def get_repo_root(self):
diff --git a/conans/client/cmd/uploader.py b/conans/client/cmd/uploader.py
index cff1385a9..6c56a69be 100644
--- a/conans/client/cmd/uploader.py
+++ b/conans/client/cmd/uploader.py
@@ -7,7 +7,7 @@ from conan.api.output import ConanOutput
 from conans.client.source import retrieve_exports_sources
 from conans.errors import ConanException, NotFoundException
 from conan.internal.paths import (CONAN_MANIFEST, CONANFILE, EXPORT_SOURCES_TGZ_NAME,
-                          EXPORT_TGZ_NAME, PACKAGE_TGZ_NAME, CONANINFO)
+                                  EXPORT_TGZ_NAME, PACKAGE_TGZ_NAME, CONANINFO)
 from conans.util.files import (clean_dirty, is_dirty, gather_files,
                                gzopen_without_timestamps, set_dirty_context_manager, mkdir,
                                human_size)
@@ -81,10 +81,17 @@ class PackagePreparator:
         self._global_conf = global_conf
 
     def prepare(self, upload_bundle, enabled_remotes):
+        local_url = self._global_conf.get("core.scm:local_url", choices=["allow", "block"])
         for ref, bundle in upload_bundle.refs().items():
             layout = self._app.cache.recipe_layout(ref)
             conanfile_path = layout.conanfile()
             conanfile = self._app.loader.load_basic(conanfile_path)
+            url = conanfile.conan_data.get("scm", {}).get("url") if conanfile.conan_data else None
+            if local_url != "allow" and url is not None:
+                if not any(url.startswith(v) for v in ("ssh", "git", "http", "file")):
+                    raise ConanException(f"Package {ref} contains conandata scm url={url}\n"
+                                         "This isn't a remote URL, the build won't be reproducible\n"
+                                         "Failing because conf 'core.scm:local_url!=allow'")
 
             if bundle.get("upload"):
                 self._prepare_recipe(ref, bundle, conanfile, enabled_remotes)
diff --git a/conans/client/graph/compatibility.py b/conans/client/graph/compatibility.py
index 7805878c2..129fe221d 100644
--- a/conans/client/graph/compatibility.py
+++ b/conans/client/graph/compatibility.py
@@ -146,12 +146,12 @@ class BinaryCompatibility:
                 compat_info = conanfile.original_info.clone()
                 settings = elem.get("settings")
                 if settings:
-                    compat_info.settings.update_values(settings)
+                    compat_info.settings.update_values(settings, raise_undefined=False)
                 options = elem.get("options")
                 if options:
                     compat_info.options.update(options_values=OrderedDict(options))
                 result.append(compat_info)
                 settings_target = elem.get("settings_target")
                 if settings_target and compat_info.settings_target:
-                    compat_info.settings_target.update_values(settings_target)
+                    compat_info.settings_target.update_values(settings_target, raise_undefined=False)
         return result
diff --git a/conans/model/conf.py b/conans/model/conf.py
index 1a36d24a5..c04e48d95 100644
--- a/conans/model/conf.py
+++ b/conans/model/conf.py
@@ -52,6 +52,7 @@ BUILT_IN_CONFS = {
     "core.gzip:compresslevel": "The Gzip compression level for Conan artifacts (default=9)",
     # Excluded from revision_mode = "scm" dirty and Git().is_dirty() checks
     "core.scm:excluded": "List of excluded patterns for builtin git dirty checks",
+    "core.scm:local_url": "By default allows to store local folders as remote url, but not upload them. Use 'allow' for allowing upload and 'block' to completely forbid it",
     # Tools
     "tools.android:ndk_path": "Argument for the CMAKE_ANDROID_NDK",
     "tools.android:cmake_legacy_toolchain": "Define to explicitly pass ANDROID_USE_LEGACY_TOOLCHAIN_FILE in CMake toolchain",
@@ -117,7 +118,7 @@ BUILT_IN_CONFS = {
     "tools.apple:enable_visibility": "(boolean) Enable/Disable Visibility Apple Clang flags",
     "tools.env.virtualenv:powershell": "If it is set to True it will generate powershell launchers if os=Windows",
     # Compilers/Flags configurations
-    "tools.build:compiler_executables": "Defines a Python dict-like with the compilers path to be used. Allowed keys {'c', 'cpp', 'cuda', 'objc', 'objcxx', 'rc', 'fortran', 'asm', 'hip', 'ispc', 'ld', 'ar'}",
+    "tools.build:compiler_executables": "Defines a Python dict-like with the compilers path to be used. Allowed keys {'c', 'cpp', 'cuda', 'objc', 'objcxx', 'rc', 'fortran', 'asm', 'hip', 'ispc'}",
     "tools.build:cxxflags": "List of extra CXX flags used by different toolchains like CMakeToolchain, AutotoolsToolchain and MesonToolchain",
     "tools.build:cflags": "List of extra C flags used by different toolchains like CMakeToolchain, AutotoolsToolchain and MesonToolchain",
     "tools.build:defines": "List of extra definition flags used by different toolchains like CMakeToolchain, AutotoolsToolchain and MesonToolchain",
diff --git a/conans/model/settings.py b/conans/model/settings.py
index f0735f901..2c56f7a38 100644
--- a/conans/model/settings.py
+++ b/conans/model/settings.py
@@ -302,23 +302,24 @@ class Settings(object):
     def items(self):
         return self.values_list
 
-    def update_values(self, vals):
-        """ receives a list of tuples (compiler.version, value)
-        This is more an updated than a setter
+    def update_values(self, values, raise_undefined=True):
+        """
+        Receives a list of tuples (compiler.version, value)
+        This is more an updater than a setter.
         """
         self._frozen = False  # Could be restored at the end, but not really necessary
-        assert isinstance(vals, (list, tuple)), vals
-        for (name, value) in vals:
+        assert isinstance(values, (list, tuple)), values
+        for (name, value) in values:
             list_settings = name.split(".")
             attr = self
             try:
                 for setting in list_settings[:-1]:
                     attr = getattr(attr, setting)
-            except ConanException:  # fails if receiving settings doesn't have it defined
-                pass
-            else:
                 value = str(value) if value is not None else None
                 setattr(attr, list_settings[-1], value)
+            except ConanException:  # fails if receiving settings doesn't have it defined
+                if raise_undefined:
+                    raise
 
     def constrained(self, constraint_def):
         """ allows to restrict a given Settings object with the input of another Settings object
diff --git a/conans/server/crypto/jwt/jwt_credentials_manager.py b/conans/server/crypto/jwt/jwt_credentials_manager.py
index f2699f887..609469875 100644
--- a/conans/server/crypto/jwt/jwt_credentials_manager.py
+++ b/conans/server/crypto/jwt/jwt_credentials_manager.py
@@ -1,19 +1,26 @@
-from conans.server.crypto.jwt.jwt_manager import JWTManager
+from datetime import datetime, timezone
+from calendar import timegm
 
+import jwt
 
-class JWTCredentialsManager(JWTManager):
+
+class JWTCredentialsManager:
     """JWT for manage auth credentials"""
 
     def __init__(self, secret, expire_time):
-        super(JWTCredentialsManager, self).__init__(secret, expire_time)
+        """expire_time is a timedelta
+        secret is a string with the secret encoding key"""
+        self.secret = secret
+        self.expire_time = expire_time
 
-    def get_token_for(self, brl_user):
+    def get_token_for(self, user):
         """Generates a token with the brl_user and additional data dict if needed"""
-        return JWTManager.get_token_for(self, {"user": brl_user})
+        profile_fields = {"user": user,
+                          "exp": timegm((datetime.now(timezone.utc) + self.expire_time).timetuple())}
+        return jwt.encode(profile_fields, self.secret, algorithm="HS256")
 
     def get_user(self, token):
         """Gets the user from credentials object. None if no credentials.
         Can raise jwt.ExpiredSignature and jwt.DecodeError"""
-        profile = self.get_profile(token)
-        username = profile.get("user", None)
-        return username
+        profile = jwt.decode(token, self.secret, algorithms=["HS256"])
+        return profile.get("user", None)
diff --git a/conans/server/crypto/jwt/jwt_manager.py b/conans/server/crypto/jwt/jwt_manager.py
deleted file mode 100644
index fadd972f2..000000000
--- a/conans/server/crypto/jwt/jwt_manager.py
+++ /dev/null
@@ -1,33 +0,0 @@
-from datetime import datetime, timezone
-from calendar import timegm
-
-import jwt
-
-
-class JWTManager:
-    """
-        Handles the JWT token generation and encryption.
-    """
-
-    def __init__(self, secret, expire_time):
-        """expire_time is a timedelta
-           secret is a string with the secret encoding key"""
-        self.secret = secret
-        self.expire_time = expire_time
-
-    def get_token_for(self, profile_fields=None):
-        """Generates a token with the provided fields.
-        if exp is True, expiration time will be used"""
-        profile_fields = profile_fields or {}
-
-        if self.expire_time:
-            profile_fields["exp"] = timegm((datetime.now(timezone.utc)
-                                            + self.expire_time).timetuple())
-
-        return jwt.encode(profile_fields, self.secret, algorithm="HS256")
-
-    def get_profile(self, token):
-        """Gets the user from credentials object. None if no credentials.
-        Can raise jwt.ExpiredSignature and jwt.DecodeError"""
-        profile = jwt.decode(token, self.secret, algorithms=["HS256"])
-        return profile


Test patch:
diff --git a/test/functional/toolchains/cmake/test_cmake_toolchain.py b/test/functional/toolchains/cmake/test_cmake_toolchain.py
index acd6c5ee1..b64c5c791 100644
--- a/test/functional/toolchains/cmake/test_cmake_toolchain.py
+++ b/test/functional/toolchains/cmake/test_cmake_toolchain.py
@@ -1913,3 +1913,106 @@ def test_cmake_toolchain_cxxflags_multi_config():
     assert 'DEFINE conan_test_answer=123' in c.out
     assert 'other=' not in c.out
     assert "CPLUSPLUS: __cplusplus19" in c.out
+
+
+@pytest.mark.tool("ninja")
+@pytest.mark.tool("cmake", "3.23")
+def test_cmake_toolchain_ninja_multi_config():
+    c = TestClient()
+    profile_release = textwrap.dedent(r"""
+        include(default)
+        [conf]
+        tools.cmake.cmaketoolchain:generator=Ninja Multi-Config
+        tools.build:defines=["conan_test_answer=42", "conan_test_other=24"]
+        """)
+    profile_debug = textwrap.dedent(r"""
+        include(default)
+        [settings]
+        build_type=Debug
+        [conf]
+        tools.cmake.cmaketoolchain:generator=Ninja Multi-Config
+        tools.build:defines=["conan_test_answer=123"]
+        """)
+    profile_relwithdebinfo = textwrap.dedent(r"""
+        include(default)
+        [settings]
+        build_type=RelWithDebInfo
+        [conf]
+        tools.cmake.cmaketoolchain:generator=Ninja Multi-Config
+        tools.build:defines=["conan_test_answer=456", "conan_test_other=abc", 'conan_test_complex="1 2"']
+        """)
+
+    conanfile = textwrap.dedent(r'''
+        from conan import ConanFile
+        from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
+
+        class Test(ConanFile):
+            exports_sources = "CMakeLists.txt", "src/*"
+            settings = "os", "compiler", "arch", "build_type"
+            generators = "CMakeToolchain"
+
+            def layout(self):
+                cmake_layout(self)
+
+            def build(self):
+                cmake = CMake(self)
+                cmake.configure()
+                cmake.build()
+        ''')
+
+    main = textwrap.dedent(r"""
+        #include <iostream>
+        #include <stdio.h>
+
+        #define STR(x)   #x
+        #define SHOW_DEFINE(x) printf("DEFINE %s=%s!\n", #x, STR(x))
+
+        int main() {
+            SHOW_DEFINE(conan_test_answer);
+            #ifdef conan_test_other
+            SHOW_DEFINE(conan_test_other);
+            #endif
+            #ifdef conan_test_complex
+            SHOW_DEFINE(conan_test_complex);
+            #endif
+        }
+        """)
+
+    cmakelists = textwrap.dedent("""
+        cmake_minimum_required(VERSION 3.15)
+        project(Test CXX)
+        add_executable(example src/main.cpp)
+        """)
+
+    c.save({"conanfile.py": conanfile,
+            "profile_release": profile_release,
+            "profile_debug": profile_debug,
+            "profile_relwithdebinfo": profile_relwithdebinfo,
+            "src/main.cpp": main,
+            "CMakeLists.txt": cmakelists})
+    c.run("install . -pr=./profile_release")
+    c.run("install . -pr=./profile_debug")
+    c.run("install . -pr=./profile_relwithdebinfo")
+
+    with c.chdir("build"):
+        env = r".\generators\conanbuild.bat &&" if platform.system() == "Windows" else ""
+        c.run_command(f"{env} cmake .. -G \"Ninja Multi-Config\" "
+                      "-DCMAKE_TOOLCHAIN_FILE=generators/conan_toolchain.cmake")
+        c.run_command(f"{env} cmake --build . --config Release")
+        c.run_command(f"{env} cmake --build . --config Debug")
+        c.run_command(f"{env} cmake --build . --config RelWithDebInfo")
+
+    c.run_command(os.sep.join([".", "build", "Release", "example"]))
+    assert 'DEFINE conan_test_answer=42!' in c.out
+    assert 'DEFINE conan_test_other=24!' in c.out
+    assert 'complex=' not in c.out
+
+    c.run_command(os.sep.join([".", "build", "Debug", "example"]))
+    assert 'DEFINE conan_test_answer=123' in c.out
+    assert 'other=' not in c.out
+    assert 'complex=' not in c.out
+
+    c.run_command(os.sep.join([".", "build", "RelWithDebInfo", "example"]))
+    assert 'DEFINE conan_test_answer=456!' in c.out
+    assert 'DEFINE conan_test_other=abc!' in c.out
+    assert 'DEFINE conan_test_complex="1 2"!' in c.out
diff --git a/test/functional/tools/scm/test_git.py b/test/functional/tools/scm/test_git.py
index af7336054..c566270d8 100644
--- a/test/functional/tools/scm/test_git.py
+++ b/test/functional/tools/scm/test_git.py
@@ -617,7 +617,7 @@ class TestGitBasicSCMFlow:
                                                    "CMakeLists.txt": "mycmake"}, folder=folder)
 
         c = TestClient(default_server_user=True)
-        c.run_command('git clone "{}" .'.format(url))
+        c.run_command('git clone "file://{}" .'.format(url))
         c.run("create .")
         assert "pkg/0.1: MYCMAKE: mycmake" in c.out
         assert "pkg/0.1: MYFILE: myheader!" in c.out
@@ -648,7 +648,7 @@ class TestGitBasicSCMFlow:
         conanfile = self.conanfile_scm if conanfile_scm else self.conanfile_full
         url = git_create_bare_repo()
         c = TestClient(default_server_user=True)
-        c.run_command('git clone "{}" .'.format(url))
+        c.run_command('git clone "file://{}" .'.format(url))
         c.save({"conanfile.py": conanfile,
                 "src/myfile.h": "myheader!",
                 "CMakeLists.txt": "mycmake"})
diff --git a/test/integration/command/user_test.py b/test/integration/command/user_test.py
index b5e4857a1..960ba8640 100644
--- a/test/integration/command/user_test.py
+++ b/test/integration/command/user_test.py
@@ -418,7 +418,7 @@ class TestRemoteAuth:
 
     def test_remote_auth_server_expire_token(self):
         server = TestServer(users={"myuser": "password", "myotheruser": "otherpass"})
-        server.test_server.ra.api_v2.credentials_manager.expire_time = timedelta(seconds=1)
+        server.test_server.ra.api_v2.credentials_manager.expire_time = timedelta(seconds=2)
         c = TestClient(servers={"default": server}, inputs=["myuser", "password",
                                                             "myotheruser", "otherpass",
                                                             "user", "pass", "user", "pass",
@@ -429,10 +429,10 @@ class TestRemoteAuth:
         c.run("remote auth *")
         assert "user: myuser" in c.out
         # Token should expire
-        time.sleep(2)
+        time.sleep(2.5)
         c.run("remote auth *")
         assert "user: myotheruser" in c.out
         # Token should expire
-        time.sleep(2)
+        time.sleep(2.5)
         c.run("remote auth *")
         assert "error: Too many failed login attempts, bye!" in c.out
diff --git a/test/integration/settings/test_non_defining_settings.py b/test/integration/settings/test_non_defining_settings.py
index 5b68e1524..addc2629b 100644
--- a/test/integration/settings/test_non_defining_settings.py
+++ b/test/integration/settings/test_non_defining_settings.py
@@ -1,5 +1,6 @@
 import textwrap
 
+from conan.test.assets.genconanfile import GenConanfile
 from conan.test.utils.tools import TestClient
 
 
@@ -29,3 +30,15 @@ def test_settings_not_defined_consuming():
     # It doesn't fail, even if settings not defined
     c.run("install --requires=pkg/1.0 -pr=profile -s os=Linux -s arch=x86")
     # It doesn't fail, even if settings different value
+
+
+def test_settings_undefined():
+    client = TestClient()
+    client.save({
+        "conanfile.py": GenConanfile(name="hello", version="1.0")
+    })
+    # Undefined settings field
+    client.run("install . -s foo=None", assert_error=True)
+    assert "'settings.foo' doesn't exist for 'settings'" in client.out
+    client.run("install . -s foo.bar=None", assert_error=True)
+    assert "'settings.foo' doesn't exist for 'settings'" in client.out
diff --git a/test/integration/toolchains/cmake/test_cmaketoolchain.py b/test/integration/toolchains/cmake/test_cmaketoolchain.py
index dee27284e..38ac9049b 100644
--- a/test/integration/toolchains/cmake/test_cmaketoolchain.py
+++ b/test/integration/toolchains/cmake/test_cmaketoolchain.py
@@ -1278,6 +1278,32 @@ def test_build_folder_vars_self_name_version():
     assert "conan-windows-pkg-0.1-debug" in presets
 
 
+def test_build_folder_vars_constants_user():
+    c = TestClient()
+    conanfile = textwrap.dedent("""
+        from conan import ConanFile
+        from conan.tools.cmake import cmake_layout
+
+        class Conan(ConanFile):
+            name = "dep"
+            version = "0.1"
+            settings = "os", "build_type"
+            generators = "CMakeToolchain"
+
+            def layout(self):
+                cmake_layout(self)
+        """)
+    c.save({"conanfile.py": conanfile})
+    conf = "tools.cmake.cmake_layout:build_folder_vars='[\"const.myvalue\"]'"
+    settings = " -s os=FreeBSD -s arch=armv8 -s build_type=Debug"
+    c.run("install . -c={} {}".format(conf, settings))
+    assert "cmake --preset conan-myvalue-debug" in c.out
+    assert os.path.exists(os.path.join(c.current_folder, "build", "myvalue", "Debug"))
+    presets = load(os.path.join(c.current_folder,
+                                "build/myvalue/Debug/generators/CMakePresets.json"))
+    assert "conan-myvalue-debug" in presets
+
+
 def test_extra_flags():
     client = TestClient()
     conanfile = textwrap.dedent("""
diff --git a/test/integration/toolchains/gnu/test_gnutoolchain.py b/test/integration/toolchains/gnu/test_gnutoolchain.py
index 653599ae6..d35d45b04 100644
--- a/test/integration/toolchains/gnu/test_gnutoolchain.py
+++ b/test/integration/toolchains/gnu/test_gnutoolchain.py
@@ -381,8 +381,6 @@ def test_msvc_profile_defaults():
             # Default values and conf ones
             assert r'set "CC=clang"' in content  # conf value has precedence
             assert r'set "CXX=clang++"' in content  # conf value has precedence
-            assert 'set "LD=link -nologo"' in content
-            assert r'set "AR=lib"' in content
             assert 'set "NM=dumpbin -symbols"' in content
             assert 'set "OBJDUMP=:"' in content
             assert 'set "RANLIB=:"' in content
@@ -412,8 +410,6 @@ def test_msvc_profile_defaults():
             # Prepending compiler wrappers
             tc.extra_env.prepend("CC", "compile")
             tc.extra_env.prepend("CXX", "compile")
-            tc.extra_env.prepend("AR", "ar-lib")
-            tc.extra_env.append("LD", "-fixed")
             tc.extra_env.define("OBJDUMP", "other-value")
             tc.extra_env.unset("RANLIB")
             tc.generate()
@@ -424,8 +420,6 @@ def test_msvc_profile_defaults():
             # Default values
             assert r'set "CC=compile clang"' in content
             assert r'set "CXX=compile clang++"' in content
-            assert 'set "LD=link -nologo -fixed"' in content  # appended new value
-            assert r'set "AR=ar-lib lib"' in content
             assert 'set "NM=dumpbin -symbols"' in content
             assert 'set "OBJDUMP=other-value"' in content  # redefined
             assert 'set "RANLIB=:"' not in content  # removed
diff --git a/test/unittests/model/settings_test.py b/test/unittests/model/settings_test.py
index 63960772d..da418033c 100644
--- a/test/unittests/model/settings_test.py
+++ b/test/unittests/model/settings_test.py
@@ -481,3 +481,25 @@ def test_settings_intel_cppstd_03():
     settings.compiler = "intel-cc"
     # This doesn't crash, it used to crash due to "03" not quoted in setting.yml
     settings.compiler.cppstd = "03"
+
+
+def test_set_value_non_existing_values():
+    data = {
+        "compiler": {
+            "gcc": {
+                "version": ["4.8", "4.9"],
+                "arch": {"x86": {"speed": ["A", "B"]},
+                         "x64": {"speed": ["C", "D"]}}}
+        },
+        "os": ["Windows", "Linux"]
+    }
+    settings = Settings(data)
+    with pytest.raises(ConanException) as cm:
+        settings.update_values([("foo", "A")])
+    assert "'settings.foo' doesn't exist for 'settings'" in str(cm.value)
+    with pytest.raises(ConanException) as cm:
+        settings.update_values([("foo.bar", "A")])
+    assert "'settings.foo' doesn't exist for 'settings'" in str(cm.value)
+    # it does not raise any error
+    settings.update_values([("foo", "A")], raise_undefined=False)
+    settings.update_values([("foo.bar", "A")], raise_undefined=False)
diff --git a/test/unittests/server/crypto/jwt_test.py b/test/unittests/server/crypto/jwt_test.py
index 9c6b916a4..d1253232b 100644
--- a/test/unittests/server/crypto/jwt_test.py
+++ b/test/unittests/server/crypto/jwt_test.py
@@ -1,40 +1,26 @@
 import time
-import unittest
 from datetime import timedelta
 
 import jwt
+import pytest
 from jwt import DecodeError
 
 from conans.server.crypto.jwt.jwt_credentials_manager import JWTCredentialsManager
-from conans.server.crypto.jwt.jwt_manager import JWTManager
 
 
-class JwtTest(unittest.TestCase):
+def test_jwt_manager():
+    # Instance the manager to generate tokens that expires in 10 ms
+    manager = JWTCredentialsManager(secret="1234asdf", expire_time=timedelta(seconds=1))
 
-    def setUp(self):
-        unittest.TestCase.setUp(self)
-        self.secret = "123123123qweqwe"
-        self.expire_time = timedelta(seconds=1)  # No lower resolution available
+    # Encrypt a profile
+    token = manager.get_token_for("myuser")
 
-    def test_jwt_manager(self):
-        # Instance the manager to generate tokens that expires in 10 ms
+    # Decrypt the profile
+    assert "myuser" == manager.get_user(token)
+    with pytest.raises(DecodeError):
+        manager.get_user("invalid_user")
 
-        manager = JWTManager(self.secret, self.expire_time)
-
-        # Encrypt a profile
-        profile = {"hello": "world"}
-        token = manager.get_token_for(profile)
-
-        # Decrypt the profile
-        decrypted_profile = manager.get_profile(token)
-        self.assertEqual(profile, decrypted_profile)
-
-        # Now wait 2 seconds and check if its valid now
-        time.sleep(2)
-        self.assertRaises(jwt.ExpiredSignatureError, manager.get_profile, token)
-
-    def test_jwt_credentials_manager(self):
-        manager = JWTCredentialsManager(self.secret, self.expire_time)
-        token = manager.get_token_for("lasote")
-        self.assertEqual(manager.get_user(token), "lasote")
-        self.assertRaises(DecodeError, manager.get_user, "invalid_user")
+    # Now wait 2 seconds and check if its valid now
+    time.sleep(2)
+    with pytest.raises(jwt.ExpiredSignatureError):
+        manager.get_user(token)