# Path: amivapi/ldap.py
# def init_app(app):
# def authenticate_user(cn, password):
# def sync_one(cn):
# def sync_all():
# def _search(query):
# def _escape(query):
# def _process_data(data):
# def _create_or_update_user(ldap_data):
# 
# Path: amivapi/tests/utils.py
# class WebTest(unittest.TestCase, FixtureMixin):
#     """Base test class for tests against the full WSGI stack.
# 
#     Inspired by eve standard testing class.
#     """
# 
#     # Test Config overwrites
#     test_config = {
#         'MONGO_DBNAME': 'test_amivapi',
#         'MONGO_USERNAME': 'test_user',
#         'MONGO_PASSWORD': 'test_pw',
#         'API_MAIL': 'api@test.ch',
#         'SMTP_SERVER': '',
#         'TESTING': True,
#         'DEBUG': True,   # This makes eve's error messages more helpful
#         'LDAP_USERNAME': None,  # LDAP test require special treatment
#         'LDAP_PASSWORD': None,  # LDAP test require special treatment
#         'SENTRY_DSN': None,
#         'SENTRY_ENVIRONMENT': None,
#         'PASSWORD_CONTEXT': CryptContext(
#             schemes=["pbkdf2_sha256"],
#             pbkdf2_sha256__default_rounds=10,
#             # min_rounds is used to determine if a hash needs to be upgraded
#             pbkdf2_sha256__min_rounds=8,
#         )
#     }
# 
#     def setUp(self, **extra_config):
#         """Set up the testing client and database connection.
# 
#         self.api will be a flask TestClient to make requests
#         self.db will be a MongoDB database
#         """
#         super().setUp()
# 
#         # In 3.2, assertItemsEqual was replaced by assertCountEqual
#         # Make assertItemsEqual work in tests for py3 as well
#         if sys.version_info >= (3, 2):
#             self.assertItemsEqual = self.assertCountEqual
# 
#         # create eve app and test client
#         config = {}
#         config.update(self.test_config)
#         config.update(extra_config)
#         self.app = bootstrap.create_app(**config)
#         self.app.response_class = TestResponse
#         self.app.test_client_class = TestClient
#         self.app.test_mails = []
#         self.api = self.app.test_client()
# 
#         # Create a separate mongo connection and db reference for tests
#         self.connection = MongoClient(host=self.app.config['MONGO_HOST'],
#                                       port=self.app.config['MONGO_PORT'])
#         self.db = self.connection[self.app.config['MONGO_DBNAME']]
#         self.db.authenticate(name=self.app.config['MONGO_USERNAME'],
#                              password=self.app.config['MONGO_PASSWORD'],
#                              source=self.app.config['MONGO_DBNAME'])
# 
#     def tearDown(self):
#         """Tear down after testing."""
#         # delete testing database
#         self.connection.drop_database(self.test_config['MONGO_DBNAME'])
#         # close database connection
#         self.connection.close()
# 
#     # Shortcuts to get a token
#     counter = count()
# 
#     def get_user_token(self, user_id, created=None):
#         """Create session for a user and return a token.
# 
#         Args:
#             user_id (str): user_id as string.
# 
#         Returns:
#             str: Token that can be used to authenticate user.
#         """
#         if created is None:
#             created = datetime.now(timezone.utc)
# 
#         token = "test_token_" + str(next(self.counter))
#         self.db['sessions'].insert_one({u'user': ObjectId(user_id),
#                                         u'token': token,
#                                         u'_created': created})
#         return token
# 
#     def get_root_token(self):
#         """The root password is the root token.
# 
#         Returns:
#             str: Token for the root user
#         """
#         return ROOT_PASSWORD
# 
# class WebTestNoAuth(WebTest):
#     """WebTest without authentification."""
# 
#     def setUp(self, **extra_config):
#         """Use auth hook to always authenticate as root for every request."""
#         super().setUp(**extra_config)
# 
#         def authenticate_root(resource):
#             g.resource_admin = True
# 
#         self.app.after_auth += authenticate_root
# 
# def skip_if_false(condition, reason):
#     """Decorator to mark tests to be skipped if condition is false."""
#     def _skip(func):
#         return func if condition else pytest.mark.skip(reason=reason)(func)
#     return _skip


from unittest.mock import MagicMock, patch, call
from os import getenv
from pprint import pformat
from amivapi import ldap
from amivapi.tests.utils import WebTest, WebTestNoAuth, skip_if_false
import warnings
    @requires_credentials
    @skip_if_false(LDAP_USER_NETHZ,
                   "LDAP user test requires environment variable"
                   "'LDAP_TEST_USER_NETHZ'")
    def test_sync_one(self):
        """Assert synchronizing one user works."""
        with self.app.test_request_context():
            user = ldap.sync_one(LDAP_USER_NETHZ)
            data_only = {key: value for (key, value) in user.items()
                         if not key.startswith('_')}  # no meta fields
            data_only.pop('password_set')  # meta field as well

            # Double check with database
            db_user = self.db['users'].find_one({'nethz': LDAP_USER_NETHZ})

            # Compare with database (ignore meta fields)
            for key in data_only:
                self.assertEqual(user[key], db_user[key])

            # Display user data for manual verification

            message = 'Manual data check required:\n%s' % pformat(data_only)
            warnings.warn(UserWarning(message))

    @requires_credentials
    def test_sync_all(self):
        """Test sync all imports users by checking the test user."""
        with self.app.test_request_context():
            # No users in db
            self.assertEqual(self.db['users'].count_documents({}), 0)

# Path: amivapi/ldap.py
# def init_app(app):
# def authenticate_user(cn, password):
# def sync_one(cn):
# def sync_all():
# def _search(query):
# def _escape(query):
# def _process_data(data):
# def _create_or_update_user(ldap_data):
# 
# Path: amivapi/tests/utils.py
# class WebTest(unittest.TestCase, FixtureMixin):
#     """Base test class for tests against the full WSGI stack.
# 
#     Inspired by eve standard testing class.
#     """
# 
#     # Test Config overwrites
#     test_config = {
#         'MONGO_DBNAME': 'test_amivapi',
#         'MONGO_USERNAME': 'test_user',
#         'MONGO_PASSWORD': 'test_pw',
#         'API_MAIL': 'api@test.ch',
#         'SMTP_SERVER': '',
#         'TESTING': True,
#         'DEBUG': True,   # This makes eve's error messages more helpful
#         'LDAP_USERNAME': None,  # LDAP test require special treatment
#         'LDAP_PASSWORD': None,  # LDAP test require special treatment
#         'SENTRY_DSN': None,
#         'SENTRY_ENVIRONMENT': None,
#         'PASSWORD_CONTEXT': CryptContext(
#             schemes=["pbkdf2_sha256"],
#             pbkdf2_sha256__default_rounds=10,
#             # min_rounds is used to determine if a hash needs to be upgraded
#             pbkdf2_sha256__min_rounds=8,
#         )
#     }
# 
#     def setUp(self, **extra_config):
#         """Set up the testing client and database connection.
# 
#         self.api will be a flask TestClient to make requests
#         self.db will be a MongoDB database
#         """
#         super().setUp()
# 
#         # In 3.2, assertItemsEqual was replaced by assertCountEqual
#         # Make assertItemsEqual work in tests for py3 as well
#         if sys.version_info >= (3, 2):
#             self.assertItemsEqual = self.assertCountEqual
# 
#         # create eve app and test client
#         config = {}
#         config.update(self.test_config)
#         config.update(extra_config)
#         self.app = bootstrap.create_app(**config)
#         self.app.response_class = TestResponse
#         self.app.test_client_class = TestClient
#         self.app.test_mails = []
#         self.api = self.app.test_client()
# 
#         # Create a separate mongo connection and db reference for tests
#         self.connection = MongoClient(host=self.app.config['MONGO_HOST'],
#                                       port=self.app.config['MONGO_PORT'])
#         self.db = self.connection[self.app.config['MONGO_DBNAME']]
#         self.db.authenticate(name=self.app.config['MONGO_USERNAME'],
#                              password=self.app.config['MONGO_PASSWORD'],
#                              source=self.app.config['MONGO_DBNAME'])
# 
#     def tearDown(self):
#         """Tear down after testing."""
#         # delete testing database
#         self.connection.drop_database(self.test_config['MONGO_DBNAME'])
#         # close database connection
#         self.connection.close()
# 
#     # Shortcuts to get a token
#     counter = count()
# 
#     def get_user_token(self, user_id, created=None):
#         """Create session for a user and return a token.
# 
#         Args:
#             user_id (str): user_id as string.
# 
#         Returns:
#             str: Token that can be used to authenticate user.
#         """
#         if created is None:
#             created = datetime.now(timezone.utc)
# 
#         token = "test_token_" + str(next(self.counter))
#         self.db['sessions'].insert_one({u'user': ObjectId(user_id),
#                                         u'token': token,
#                                         u'_created': created})
#         return token
# 
#     def get_root_token(self):
#         """The root password is the root token.
# 
#         Returns:
#             str: Token for the root user
#         """
#         return ROOT_PASSWORD
# 
# class WebTestNoAuth(WebTest):
#     """WebTest without authentification."""
# 
#     def setUp(self, **extra_config):
#         """Use auth hook to always authenticate as root for every request."""
#         super().setUp(**extra_config)
# 
#         def authenticate_root(resource):
#             g.resource_admin = True
# 
#         self.app.after_auth += authenticate_root
# 
# def skip_if_false(condition, reason):
#     """Decorator to mark tests to be skipped if condition is false."""
#     def _skip(func):
#         return func if condition else pytest.mark.skip(reason=reason)(func)
#     return _skip


# Path: amivapi/tests/test_ldap.py
from unittest.mock import MagicMock, patch, call
from os import getenv
from pprint import pformat
from amivapi import ldap
from amivapi.tests.utils import WebTest, WebTestNoAuth, skip_if_false
import warnings

    @requires_credentials
    @skip_if_false(LDAP_USER_NETHZ,
                   "LDAP user test requires environment variable"
                   "'LDAP_TEST_USER_NETHZ'")
    def test_sync_one(self):
        """Assert synchronizing one user works."""
        with self.app.test_request_context():
            user = ldap.sync_one(LDAP_USER_NETHZ)
            data_only = {key: value for (key, value) in user.items()
                         if not key.startswith('_')}  # no meta fields
            data_only.pop('password_set')  # meta field as well

            # Double check with database
            db_user = self.db['users'].find_one({'nethz': LDAP_USER_NETHZ})

            # Compare with database (ignore meta fields)
            for key in data_only:
                self.assertEqual(user[key], db_user[key])

            # Display user data for manual verification

            message = 'Manual data check required:\n%s' % pformat(data_only)
            warnings.warn(UserWarning(message))

    @requires_credentials
    def test_sync_all(self):
        """Test sync all imports users by checking the test user."""
        with self.app.test_request_context():
            # No users in db
            self.assertEqual(self.db['users'].count_documents({}), 0)

            ldap.sync_all()