Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-msal-extensions for 
openSUSE:Factory checked in at 2024-02-11 15:45:58
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-msal-extensions (Old)
 and      /work/SRC/openSUSE:Factory/.python-msal-extensions.new.1815 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-msal-extensions"

Sun Feb 11 15:45:58 2024 rev:7 rq:1145585 version:1.1.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-msal-extensions/python-msal-extensions.changes
    2023-05-08 17:24:56.632929313 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-msal-extensions.new.1815/python-msal-extensions.changes
  2024-02-11 15:45:59.515576272 +0100
@@ -1,0 +2,7 @@
+Fri Feb  9 15:46:13 UTC 2024 - John Paul Adrian Glaubitz 
<adrian.glaub...@suse.com>
+
+- Update to version 1.1.0
+  + Support Python 3.12 by removing dependency on distutils (#120, #123)
+  + Dropping Python 2.7 (#122)
+
+-------------------------------------------------------------------

Old:
----
  msal-extensions-1.0.0.tar.gz

New:
----
  msal-extensions-1.1.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-msal-extensions.spec ++++++
--- /var/tmp/diff_new_pack.GRW6q0/_old  2024-02-11 15:46:00.083596695 +0100
+++ /var/tmp/diff_new_pack.GRW6q0/_new  2024-02-11 15:46:00.087596838 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-msal-extensions
 #
-# Copyright (c) 2023 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -21,7 +21,7 @@
 %define skip_python2 1
 %endif
 Name:           python-msal-extensions
-Version:        1.0.0
+Version:        1.1.0
 Release:        0
 Summary:        Microsoft Authentication Library (MSAL) for Python Extensions
 License:        MIT

++++++ msal-extensions-1.0.0.tar.gz -> msal-extensions-1.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/PKG-INFO 
new/msal-extensions-1.1.0/PKG-INFO
--- old/msal-extensions-1.0.0/PKG-INFO  2022-02-15 00:45:41.537072200 +0100
+++ new/msal-extensions-1.1.0/PKG-INFO  2023-12-09 05:12:27.996491700 +0100
@@ -1,14 +1,26 @@
 Metadata-Version: 2.1
 Name: msal-extensions
-Version: 1.0.0
+Version: 1.1.0
 Summary: Microsoft Authentication Library extensions (MSAL EX) provides a 
persistence API that can save your data on disk, encrypted on Windows, macOS 
and Linux. Concurrent data access will be coordinated by a file lock mechanism.
-License: MIT
+License: MIT License
 Project-URL: Changelog, 
https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases
-Platform: UNKNOWN
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Development Status :: 5 - Production/Stable
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Requires-Python: >=3.7
 Description-Content-Type: text/markdown
 License-File: LICENSE
+Requires-Dist: msal<2.0.0,>=0.4.1
+Requires-Dist: portalocker<3,>=1.0; platform_system != "Windows"
+Requires-Dist: portalocker<3,>=1.6; platform_system == "Windows"
+Requires-Dist: packaging
 
 
 # Microsoft Authentication Extensions for Python
@@ -101,6 +113,12 @@
 assert json.loads(persistence.load()) == data
 ```
 
+## Python version support policy
+
+Python versions which are 6 months older than their
+[end-of-life cycle defined by Python Software Foundation 
(PSF)](https://devguide.python.org/versions/#versions)
+will not receive new feature updates from this library.
+
 
 ## Community Help and Support
 
@@ -129,5 +147,3 @@
 ## We value and adhere to the Microsoft Open Source Code of Conduct
 
 This project has adopted the [Microsoft Open Source Code of 
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information 
see the [Code of Conduct 
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact 
[openc...@microsoft.com](mailto:openc...@microsoft.com) with any additional 
questions or comments.
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/README.md 
new/msal-extensions-1.1.0/README.md
--- old/msal-extensions-1.0.0/README.md 2022-02-15 00:45:30.000000000 +0100
+++ new/msal-extensions-1.1.0/README.md 2023-12-09 05:12:20.000000000 +0100
@@ -89,6 +89,12 @@
 assert json.loads(persistence.load()) == data
 ```
 
+## Python version support policy
+
+Python versions which are 6 months older than their
+[end-of-life cycle defined by Python Software Foundation 
(PSF)](https://devguide.python.org/versions/#versions)
+will not receive new feature updates from this library.
+
 
 ## Community Help and Support
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/msal_extensions/__init__.py 
new/msal-extensions-1.1.0/msal_extensions/__init__.py
--- old/msal-extensions-1.0.0/msal_extensions/__init__.py       2022-02-15 
00:45:30.000000000 +0100
+++ new/msal-extensions-1.1.0/msal_extensions/__init__.py       2023-12-09 
05:12:20.000000000 +0100
@@ -1,5 +1,5 @@
 """Provides auxiliary functionality to the `msal` package."""
-__version__ = "1.0.0"
+__version__ = "1.1.0"
 
 from .persistence import (
     FilePersistence,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/msal_extensions/cache_lock.py 
new/msal-extensions-1.1.0/msal_extensions/cache_lock.py
--- old/msal-extensions-1.0.0/msal_extensions/cache_lock.py     2022-02-15 
00:45:30.000000000 +0100
+++ new/msal-extensions-1.1.0/msal_extensions/cache_lock.py     2023-12-09 
05:12:20.000000000 +0100
@@ -4,9 +4,9 @@
 import errno
 import time
 import logging
-from distutils.version import LooseVersion
 
 import portalocker
+from packaging.version import Version
 
 
 logger = logging.getLogger(__name__)
@@ -21,7 +21,7 @@
         self._lockpath = lockfile_path
         # Support for passing through arguments to the open syscall was added 
in v1.4.0
         open_kwargs = ({'buffering': 0}
-            if LooseVersion(portalocker.__version__) >= LooseVersion("1.4.0") 
else {})
+            if Version(portalocker.__version__) >= Version("1.4.0") else {})
         self._lock = portalocker.Lock(
             lockfile_path,
             mode='wb+',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/msal_extensions/persistence.py 
new/msal-extensions-1.1.0/msal_extensions/persistence.py
--- old/msal-extensions-1.0.0/msal_extensions/persistence.py    2022-02-15 
00:45:30.000000000 +0100
+++ new/msal-extensions-1.1.0/msal_extensions/persistence.py    2023-12-09 
05:12:20.000000000 +0100
@@ -210,7 +210,7 @@
         except OSError as exception:
             raise PersistenceEncryptionError(
                 err_no=getattr(exception, "winerror", None),  # Exists in 
Python 3 on Windows
-                message="Encryption failed: {}. Consider disable 
encryption.".format(exception),
+                message="Encryption failed: {} Consider disable 
encryption.".format(exception),
                 )
         with os.fdopen(_open(self._location), 'wb+') as handle:
             handle.write(data)
@@ -237,7 +237,7 @@
         except OSError as exception:
             raise PersistenceDecryptionError(
                 err_no=getattr(exception, "winerror", None),  # Exists in 
Python 3 on Windows
-                message="Decryption failed: {}. "
+                message="Decryption failed: {} "
                     "App developer may consider this guidance: "
                     
"https://github.com/AzureAD/microsoft-authentication-extensions-for-python/wiki/PersistenceDecryptionError";
  # pylint: disable=line-too-long
                     .format(exception),
@@ -342,4 +342,3 @@
 # with a FilePersistence to achieve
 #  
https://github.com/AzureAD/microsoft-authentication-extensions-for-python/issues/12
 # But this idea is not pursued at this time.
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/msal_extensions/windows.py 
new/msal-extensions-1.1.0/msal_extensions/windows.py
--- old/msal-extensions-1.0.0/msal_extensions/windows.py        2022-02-15 
00:45:30.000000000 +0100
+++ new/msal-extensions-1.1.0/msal_extensions/windows.py        2023-12-09 
05:12:20.000000000 +0100
@@ -46,7 +46,7 @@
         "The computer must be trusted for delegation and "
         "the current user account must be configured to allow delegation. "
         "See also 
https://docs.microsoft.com/en-us/windows/security/threat-protection/security-policy-settings/enable-computer-and-user-accounts-to-be-trusted-for-delegation";,
-    13: "The data is invalid",
+    13: "The data is invalid.",
     }
 
 # This code is modeled from a StackOverflow question, which can be found here:
@@ -91,7 +91,7 @@
                 _LOCAL_FREE(result.pbData)
 
         err_code = _GET_LAST_ERROR()
-        raise OSError(None, _err_description.get(err_code), None, err_code)
+        raise OSError(None, _err_description.get(err_code, ''), None, err_code)
 
     def unprotect(self, cipher_text):
         # type: (bytes) -> str
@@ -120,4 +120,4 @@
             finally:
                 _LOCAL_FREE(result.pbData)
         err_code = _GET_LAST_ERROR()
-        raise OSError(None, _err_description.get(err_code), None, err_code)
+        raise OSError(None, _err_description.get(err_code, ''), None, err_code)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/msal-extensions-1.0.0/msal_extensions.egg-info/PKG-INFO 
new/msal-extensions-1.1.0/msal_extensions.egg-info/PKG-INFO
--- old/msal-extensions-1.0.0/msal_extensions.egg-info/PKG-INFO 2022-02-15 
00:45:41.000000000 +0100
+++ new/msal-extensions-1.1.0/msal_extensions.egg-info/PKG-INFO 2023-12-09 
05:12:27.000000000 +0100
@@ -1,14 +1,26 @@
 Metadata-Version: 2.1
 Name: msal-extensions
-Version: 1.0.0
+Version: 1.1.0
 Summary: Microsoft Authentication Library extensions (MSAL EX) provides a 
persistence API that can save your data on disk, encrypted on Windows, macOS 
and Linux. Concurrent data access will be coordinated by a file lock mechanism.
-License: MIT
+License: MIT License
 Project-URL: Changelog, 
https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases
-Platform: UNKNOWN
 Classifier: License :: OSI Approved :: MIT License
 Classifier: Development Status :: 5 - Production/Stable
+Classifier: Programming Language :: Python :: 3 :: Only
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.7
+Classifier: Programming Language :: Python :: 3.8
+Classifier: Programming Language :: Python :: 3.9
+Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
+Classifier: Programming Language :: Python :: 3.12
+Requires-Python: >=3.7
 Description-Content-Type: text/markdown
 License-File: LICENSE
+Requires-Dist: msal<2.0.0,>=0.4.1
+Requires-Dist: portalocker<3,>=1.0; platform_system != "Windows"
+Requires-Dist: portalocker<3,>=1.6; platform_system == "Windows"
+Requires-Dist: packaging
 
 
 # Microsoft Authentication Extensions for Python
@@ -101,6 +113,12 @@
 assert json.loads(persistence.load()) == data
 ```
 
+## Python version support policy
+
+Python versions which are 6 months older than their
+[end-of-life cycle defined by Python Software Foundation 
(PSF)](https://devguide.python.org/versions/#versions)
+will not receive new feature updates from this library.
+
 
 ## Community Help and Support
 
@@ -129,5 +147,3 @@
 ## We value and adhere to the Microsoft Open Source Code of Conduct
 
 This project has adopted the [Microsoft Open Source Code of 
Conduct](https://opensource.microsoft.com/codeofconduct/). For more information 
see the [Code of Conduct 
FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact 
[openc...@microsoft.com](mailto:openc...@microsoft.com) with any additional 
questions or comments.
-
-
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/msal-extensions-1.0.0/msal_extensions.egg-info/SOURCES.txt 
new/msal-extensions-1.1.0/msal_extensions.egg-info/SOURCES.txt
--- old/msal-extensions-1.0.0/msal_extensions.egg-info/SOURCES.txt      
2022-02-15 00:45:41.000000000 +0100
+++ new/msal-extensions-1.1.0/msal_extensions.egg-info/SOURCES.txt      
2023-12-09 05:12:27.000000000 +0100
@@ -13,4 +13,10 @@
 msal_extensions.egg-info/SOURCES.txt
 msal_extensions.egg-info/dependency_links.txt
 msal_extensions.egg-info/requires.txt
-msal_extensions.egg-info/top_level.txt
\ No newline at end of file
+msal_extensions.egg-info/top_level.txt
+tests/test_agnostic_backend.py
+tests/test_cache_lock_file_perf.py
+tests/test_crossplatlock.py
+tests/test_macos_backend.py
+tests/test_persistence.py
+tests/test_windows_backend.py
\ No newline at end of file
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/msal-extensions-1.0.0/msal_extensions.egg-info/requires.txt 
new/msal-extensions-1.1.0/msal_extensions.egg-info/requires.txt
--- old/msal-extensions-1.0.0/msal_extensions.egg-info/requires.txt     
2022-02-15 00:45:41.000000000 +0100
+++ new/msal-extensions-1.1.0/msal_extensions.egg-info/requires.txt     
2023-12-09 05:12:27.000000000 +0100
@@ -1,16 +1,8 @@
 msal<2.0.0,>=0.4.1
+packaging
 
-[:python_version < "3.0"]
-pathlib2
-
-[:python_version == "2.7" and platform_system != "Windows"]
-portalocker<2,>=1.0
-
-[:python_version == "2.7" and platform_system == "Windows"]
-portalocker<2,>=1.6
-
-[:python_version >= "3.5" and platform_system != "Windows"]
+[:platform_system != "Windows"]
 portalocker<3,>=1.0
 
-[:python_version >= "3.5" and platform_system == "Windows"]
+[:platform_system == "Windows"]
 portalocker<3,>=1.6
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/setup.cfg 
new/msal-extensions-1.1.0/setup.cfg
--- old/msal-extensions-1.0.0/setup.cfg 2022-02-15 00:45:41.537072200 +0100
+++ new/msal-extensions-1.1.0/setup.cfg 2023-12-09 05:12:28.000491600 +0100
@@ -1,12 +1,20 @@
 [bdist_wheel]
-universal = 1
+universal = 0
 
 [metadata]
-license = MIT
+license = MIT License
 project_urls = Changelog = 
https://github.com/AzureAD/microsoft-authentication-extensions-for-python/releases
 classifiers = 
        License :: OSI Approved :: MIT License
        Development Status :: 5 - Production/Stable
+       Programming Language :: Python :: 3 :: Only
+       Programming Language :: Python :: 3
+       Programming Language :: Python :: 3.7
+       Programming Language :: Python :: 3.8
+       Programming Language :: Python :: 3.9
+       Programming Language :: Python :: 3.10
+       Programming Language :: Python :: 3.11
+       Programming Language :: Python :: 3.12
 description = Microsoft Authentication Library extensions (MSAL EX) provides a 
persistence API that can save your data on disk, encrypted on Windows, macOS 
and Linux. Concurrent data access will be coordinated by a file lock mechanism.
 
 [egg_info]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/setup.py 
new/msal-extensions-1.1.0/setup.py
--- old/msal-extensions-1.0.0/setup.py  2022-02-15 00:45:30.000000000 +0100
+++ new/msal-extensions-1.1.0/setup.py  2023-12-09 05:12:20.000000000 +0100
@@ -20,22 +20,20 @@
     long_description=long_description,
     long_description_content_type="text/markdown",
     package_data={'': ['LICENSE']},
+    python_requires=">=3.7",
     install_requires=[
         'msal>=0.4.1,<2.0.0',
 
-        # In order to implement these requirements:
-        #       Lowerbound = (1.6 if playform_system == 'Windows' else 1.0)
-        #       Upperbound < (3 if python_version >= '3.5' else 2)
-        # The following 4 lines use the `and` syntax defined here:
-        #       https://www.python.org/dev/peps/pep-0508/#grammar
-        "portalocker<3,>=1.0;python_version>='3.5' and 
platform_system!='Windows'",
-        "portalocker<2,>=1.0;python_version=='2.7' and 
platform_system!='Windows'",
-        "portalocker<3,>=1.6;python_version>='3.5' and 
platform_system=='Windows'",
-        "portalocker<2,>=1.6;python_version=='2.7' and 
platform_system=='Windows'",
+        "portalocker<3,>=1.0;platform_system!='Windows'",
+        "portalocker<3,>=1.6;platform_system=='Windows'",
 
-        "pathlib2;python_version<'3.0'",
         ## We choose to NOT define a hard dependency on this.
         # "pygobject>=3,<4;platform_system=='Linux'",
+
+        # Packaging package uses YY.N versioning so we have no upperbound to 
pin.
+        # Neither do we need lowerbound because its `Version` API existed 
since its first release
+        # https://github.com/pypa/packaging/blame/14.0/packaging/version.py
+        'packaging',
     ],
     tests_require=['pytest'],
 )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/tests/test_agnostic_backend.py 
new/msal-extensions-1.1.0/tests/test_agnostic_backend.py
--- old/msal-extensions-1.0.0/tests/test_agnostic_backend.py    1970-01-01 
01:00:00.000000000 +0100
+++ new/msal-extensions-1.1.0/tests/test_agnostic_backend.py    2023-12-09 
05:12:20.000000000 +0100
@@ -0,0 +1,49 @@
+import os
+import shutil
+import tempfile
+import sys
+
+import msal
+import pytest
+
+from msal_extensions import *
+
+
+@pytest.fixture
+def temp_location():
+    test_folder = tempfile.mkdtemp(prefix="test_token_cache_roundtrip")
+    yield os.path.join(test_folder, 'token_cache.bin')
+    shutil.rmtree(test_folder, ignore_errors=True)
+
+
+def _test_token_cache_roundtrip(cache):
+    client_id = os.getenv('AZURE_CLIENT_ID')
+    client_secret = os.getenv('AZURE_CLIENT_SECRET')
+    if not (client_id and client_secret):
+        pytest.skip('no credentials present to test TokenCache round-trip 
with.')
+
+    app = msal.ConfidentialClientApplication(
+        client_id=client_id,
+        client_credential=client_secret,
+        token_cache=cache)
+    desired_scopes = ['https://graph.microsoft.com/.default']
+    token1 = app.acquire_token_for_client(scopes=desired_scopes)
+    os.utime(  # Mock having another process update the cache
+        cache._persistence.get_location(), None)
+    token2 = app.acquire_token_silent(scopes=desired_scopes, account=None)
+    assert token1['access_token'] == token2['access_token']
+
+def test_file_token_cache_roundtrip(temp_location):
+    
_test_token_cache_roundtrip(PersistedTokenCache(FilePersistence(temp_location)))
+
+def 
test_current_platform_cache_roundtrip_with_persistence_builder(temp_location):
+    
_test_token_cache_roundtrip(PersistedTokenCache(build_encrypted_persistence(temp_location)))
+
+def test_persisted_token_cache(temp_location):
+    
_test_token_cache_roundtrip(PersistedTokenCache(FilePersistence(temp_location)))
+
+def test_file_not_found_error_is_not_raised():
+    persistence = FilePersistence('non_existing_file')
+    cache = PersistedTokenCache(persistence)
+    # An exception raised here will fail the test case as it is supposed to be 
a NO-OP
+    cache.find('')
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/msal-extensions-1.0.0/tests/test_cache_lock_file_perf.py 
new/msal-extensions-1.1.0/tests/test_cache_lock_file_perf.py
--- old/msal-extensions-1.0.0/tests/test_cache_lock_file_perf.py        
1970-01-01 01:00:00.000000000 +0100
+++ new/msal-extensions-1.1.0/tests/test_cache_lock_file_perf.py        
2023-12-09 05:12:20.000000000 +0100
@@ -0,0 +1,75 @@
+import multiprocessing
+import os
+import shutil
+import tempfile
+
+import pytest
+
+from cache_file_generator import _acquire_lock_and_write_to_cache
+
+
+@pytest.fixture
+def temp_location():
+    test_folder = tempfile.mkdtemp(prefix="test_persistence_roundtrip")
+    yield os.path.join(test_folder, 'persistence.bin')
+    shutil.rmtree(test_folder, ignore_errors=True)
+
+
+def _validate_result_in_cache(cache_location):
+    with open(cache_location) as handle:
+        data = handle.read()
+    prev_process_id = None
+    count = 0
+    for line in data.split("\n"):
+        if line:
+            count += 1
+            tag, process_id = line.split(" ")
+            if prev_process_id is not None:
+                assert process_id == prev_process_id, "Process overlap found"
+                assert tag == '>', "Process overlap_found"
+                prev_process_id = None
+            else:
+                assert tag == '<', "Opening bracket not found"
+                prev_process_id = process_id
+    return count
+
+
+def _run_multiple_processes(no_of_processes, cache_location, sleep_interval):
+    open(cache_location, "w+")
+    processes = []
+    for i in range(no_of_processes):
+        process = multiprocessing.Process(
+            target=_acquire_lock_and_write_to_cache,
+            args=(cache_location, sleep_interval))
+        processes.append(process)
+
+    for process in processes:
+        process.start()
+
+    for process in processes:
+        process.join()
+
+
+def test_lock_for_normal_workload(temp_location):
+    num_of_processes = 4
+    sleep_interval = 0.1
+    _run_multiple_processes(num_of_processes, temp_location, sleep_interval)
+    count = _validate_result_in_cache(temp_location)
+    assert count == num_of_processes * 2, "Should not observe starvation"
+
+
+def test_lock_for_high_workload(temp_location):
+    num_of_processes = 80
+    sleep_interval = 0
+    _run_multiple_processes(num_of_processes, temp_location, sleep_interval)
+    count = _validate_result_in_cache(temp_location)
+    assert count <= num_of_processes * 2, "Starvation or not, we should not 
observe garbled payload"
+
+
+def test_lock_for_timeout(temp_location):
+    num_of_processes = 30
+    sleep_interval = 1
+    _run_multiple_processes(num_of_processes, temp_location, sleep_interval)
+    count = _validate_result_in_cache(temp_location)
+    assert count < num_of_processes * 2, "Should observe starvation"
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/tests/test_crossplatlock.py 
new/msal-extensions-1.1.0/tests/test_crossplatlock.py
--- old/msal-extensions-1.0.0/tests/test_crossplatlock.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/msal-extensions-1.1.0/tests/test_crossplatlock.py       2023-12-09 
05:12:20.000000000 +0100
@@ -0,0 +1,18 @@
+import pytest
+from msal_extensions.cache_lock import CrossPlatLock
+
+
+def test_ensure_file_deleted():
+    lockfile = './test_lock_1.txt'
+
+    try:
+        FileNotFoundError
+    except NameError:
+        FileNotFoundError = IOError
+
+    with CrossPlatLock(lockfile):
+        pass
+
+    with pytest.raises(FileNotFoundError):
+        with open(lockfile):
+            pass
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/tests/test_macos_backend.py 
new/msal-extensions-1.1.0/tests/test_macos_backend.py
--- old/msal-extensions-1.0.0/tests/test_macos_backend.py       1970-01-01 
01:00:00.000000000 +0100
+++ new/msal-extensions-1.1.0/tests/test_macos_backend.py       2023-12-09 
05:12:20.000000000 +0100
@@ -0,0 +1,46 @@
+import sys
+import os
+import shutil
+import tempfile
+import pytest
+import uuid
+import msal
+
+if not sys.platform.startswith('darwin'):
+    pytest.skip('skipping MacOS-only tests', allow_module_level=True)
+else:
+    from msal_extensions.osx import Keychain
+    from msal_extensions.token_cache import PersistedTokenCache
+    from msal_extensions.persistence import KeychainPersistence
+
+
+def test_keychain_roundtrip():
+    with Keychain() as subject:
+        location, account = "msal_extension_test1", "test_account1"
+        want = uuid.uuid4().hex
+        subject.set_generic_password(location, account, want)
+        got = subject.get_generic_password(location, account)
+        assert got == want
+
+
+def test_osx_token_cache_roundtrip():
+    client_id = os.getenv('AZURE_CLIENT_ID')
+    client_secret = os.getenv('AZURE_CLIENT_SECRET')
+    if not (client_id and client_secret):
+        pytest.skip('no credentials present to test PersistedTokenCache 
round-trip with.')
+
+    test_folder = 
tempfile.mkdtemp(prefix="msal_extension_test_osx_token_cache_roundtrip")
+    cache_file = os.path.join(test_folder, 'msal.cache')
+    try:
+        subject = PersistedTokenCache(KeychainPersistence(cache_file))
+        app = msal.ConfidentialClientApplication(
+            client_id=client_id,
+            client_credential=client_secret,
+            token_cache=subject)
+        desired_scopes = ['https://graph.microsoft.com/.default']
+        token1 = app.acquire_token_for_client(scopes=desired_scopes)
+        os.utime(cache_file, None)  # Mock having another process update the 
cache.
+        token2 = app.acquire_token_silent(scopes=desired_scopes, account=None)
+        assert token1['access_token'] == token2['access_token']
+    finally:
+        shutil.rmtree(test_folder, ignore_errors=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/tests/test_persistence.py 
new/msal-extensions-1.1.0/tests/test_persistence.py
--- old/msal-extensions-1.0.0/tests/test_persistence.py 1970-01-01 
01:00:00.000000000 +0100
+++ new/msal-extensions-1.1.0/tests/test_persistence.py 2023-12-09 
05:12:20.000000000 +0100
@@ -0,0 +1,96 @@
+import os
+import sys
+import shutil
+import tempfile
+import logging
+
+import pytest
+
+from msal_extensions.persistence import *
+
+
+def _is_env_var_defined(env_var):
+    return bool(  # (WTF) What-The-Finding:
+    # The bool(...) is necessary, otherwise skipif(...) would treat "true" as
+    # string conditions and then raise an undefined "true" exception.
+    # https://docs.pytest.org/en/latest/historical-notes.html#string-conditions
+        os.getenv(env_var))
+
+
+# Note: If you use tox, remember to pass them through via tox.ini
+# 
https://tox.wiki/en/latest/example/basic.html#passing-down-environment-variables
+is_running_on_travis_ci = _is_env_var_defined("TRAVIS")
+is_running_on_github_ci = _is_env_var_defined("GITHUB_ACTIONS")
+
+@pytest.fixture
+def temp_location():
+    test_folder = tempfile.mkdtemp(prefix="test_persistence_roundtrip")
+    yield os.path.join(test_folder, 'persistence.bin')
+    shutil.rmtree(test_folder, ignore_errors=True)
+
+def _test_persistence_roundtrip(persistence):
+    payload = 'arbitrary content'
+    persistence.save(payload)
+    assert persistence.load() == payload
+
+def _test_nonexistent_persistence(persistence):
+    with pytest.raises(PersistenceNotFound):
+        persistence.load()
+    with pytest.raises(PersistenceNotFound):
+        persistence.time_last_modified()
+
+def test_file_persistence(temp_location):
+    _test_persistence_roundtrip(FilePersistence(temp_location))
+
+def test_nonexistent_file_persistence(temp_location):
+    _test_nonexistent_persistence(FilePersistence(temp_location))
+
+@pytest.mark.skipif(
+    is_running_on_travis_ci or not sys.platform.startswith('win'),
+    reason="Requires Windows Desktop")
+def test_file_persistence_with_data_protection(temp_location):
+    try:
+        
_test_persistence_roundtrip(FilePersistenceWithDataProtection(temp_location))
+    except PersistenceDecryptionError:
+        if is_running_on_github_ci or is_running_on_travis_ci:
+            logging.warning("DPAPI tends to fail on Windows VM. Run this on 
your desktop to double check.")
+        else:
+            raise
+
+@pytest.mark.skipif(
+    is_running_on_travis_ci or not sys.platform.startswith('win'),
+    reason="Requires Windows Desktop")
+def test_nonexistent_file_persistence_with_data_protection(temp_location):
+    
_test_nonexistent_persistence(FilePersistenceWithDataProtection(temp_location))
+
+@pytest.mark.skipif(
+    not sys.platform.startswith('darwin'),
+    reason="Requires OSX. Whether running on TRAVIS CI does not seem to 
matter.")
+def test_keychain_persistence(temp_location):
+    _test_persistence_roundtrip(KeychainPersistence(temp_location))
+
+@pytest.mark.skipif(
+    not sys.platform.startswith('darwin'),
+    reason="Requires OSX. Whether running on TRAVIS CI does not seem to 
matter.")
+def test_nonexistent_keychain_persistence(temp_location):
+    random_service_name = random_account_name = str(id(temp_location))
+    _test_nonexistent_persistence(
+        KeychainPersistence(temp_location, random_service_name, 
random_account_name))
+
+@pytest.mark.skipif(
+    is_running_on_travis_ci or not sys.platform.startswith('linux'),
+    reason="Requires Linux Desktop. Headless or SSH session won't work.")
+def test_libsecret_persistence(temp_location):
+    _test_persistence_roundtrip(LibsecretPersistence(temp_location))
+
+@pytest.mark.skipif(
+    is_running_on_travis_ci or not sys.platform.startswith('linux'),
+    reason="Requires Linux Desktop. Headless or SSH session won't work.")
+def test_nonexistent_libsecret_persistence(temp_location):
+    random_schema_name = random_value = str(id(temp_location))
+    _test_nonexistent_persistence(LibsecretPersistence(
+        temp_location,
+        random_schema_name,
+        {"my_attr_1": random_value, "my_attr_2": random_value},
+        ))
+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/msal-extensions-1.0.0/tests/test_windows_backend.py 
new/msal-extensions-1.1.0/tests/test_windows_backend.py
--- old/msal-extensions-1.0.0/tests/test_windows_backend.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/msal-extensions-1.1.0/tests/test_windows_backend.py     2023-12-09 
05:12:20.000000000 +0100
@@ -0,0 +1,106 @@
+import sys
+import os
+import errno
+import shutil
+import tempfile
+import pytest
+import uuid
+import msal
+
+if not sys.platform.startswith('win'):
+    pytest.skip('skipping windows-only tests', allow_module_level=True)
+else:
+    from msal_extensions.windows import WindowsDataProtectionAgent
+    from msal_extensions.token_cache import PersistedTokenCache
+    from msal_extensions.persistence import FilePersistenceWithDataProtection
+
+
+def test_dpapi_roundtrip_with_entropy():
+    subject_without_entropy = WindowsDataProtectionAgent()
+    subject_with_entropy = WindowsDataProtectionAgent(entropy=uuid.uuid4().hex)
+
+    test_cases = [
+        '',
+        'lorem ipsum',
+        'lorem-ipsum',
+        '<Python>',
+        uuid.uuid4().hex,
+    ]
+
+    try:
+        for tc in test_cases:
+            ciphered = subject_with_entropy.protect(tc)
+            assert ciphered != tc
+
+            got = subject_with_entropy.unprotect(ciphered)
+            assert got == tc
+
+            ciphered = subject_without_entropy.protect(tc)
+            assert ciphered != tc
+
+            got = subject_without_entropy.unprotect(ciphered)
+            assert got == tc
+    except OSError as exp:
+        if exp.errno == errno.EIO and os.getenv('TRAVIS_REPO_SLUG'):
+            pytest.skip('DPAPI tests are known to fail in TravisCI. This 
effort tracked by '
+                        
'https://github.com/AzureAD/microsoft-authentication-extentions-for-python'
+                        '/issues/21')
+
+
+def test_read_msal_cache_direct():
+    """
+    This loads and unprotects an MSAL cache directly, only using the 
DataProtectionAgent.
+    """
+    localappdata_location = os.getenv('LOCALAPPDATA', os.path.expanduser('~'))
+    cache_locations = [
+        os.path.join(localappdata_location, '.IdentityService', 'msal.cache'), 
# this is where it's supposed to be
+        os.path.join(localappdata_location, '.IdentityServices', 
'msal.cache'), # There was a miscommunications about whether this was plural or 
not.
+        os.path.join(localappdata_location, 'msal.cache'), # The earliest most 
naive builds used this locations.
+    ]
+
+    found = False
+    for loc in cache_locations:
+        try:
+            with open(loc, mode='rb') as fh:
+                contents = fh.read()
+            found = True
+
+            break
+        except IOError as exp:
+            if exp.errno != errno.ENOENT:
+                raise exp
+
+    if not found:
+            pytest.skip('could not find the msal.cache file (try logging in 
using MSAL)')
+
+    subject = WindowsDataProtectionAgent()
+    raw = subject.unprotect(contents)
+    assert raw != ""
+
+    cache = msal.SerializableTokenCache()
+    cache.deserialize(raw)
+    access_tokens = cache.find(msal.TokenCache.CredentialType.ACCESS_TOKEN)
+    assert len(access_tokens) > 0
+
+
+def test_windows_token_cache_roundtrip():
+    client_id = os.getenv('AZURE_CLIENT_ID')
+    client_secret = os.getenv('AZURE_CLIENT_SECRET')
+    if not (client_id and client_secret):
+        pytest.skip('no credentials present to test PersistedTokenCache 
round-trip with.')
+
+    test_folder = 
tempfile.mkdtemp(prefix="msal_extension_test_windows_token_cache_roundtrip")
+    cache_file = os.path.join(test_folder, 'msal.cache')
+    try:
+        subject = 
PersistedTokenCache(FilePersistenceWithDataProtection(cache_file))
+        app = msal.ConfidentialClientApplication(
+            client_id=client_id,
+            client_credential=client_secret,
+            token_cache=subject)
+        desired_scopes = ['https://graph.microsoft.com/.default']
+        token1 = app.acquire_token_for_client(scopes=desired_scopes)
+        os.utime(cache_file, None)  # Mock having another process update the 
cache.
+        token2 = app.acquire_token_silent(scopes=desired_scopes, account=None)
+        assert token1['access_token'] == token2['access_token']
+    finally:
+        shutil.rmtree(test_folder, ignore_errors=True)

Reply via email to