# 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


from amivapi.tests.utils import WebTest, WebTestNoAuth
        url = "/apikeys"

        self.api.post(url, data=data, status_code=401)
        self.api.post(url, data=data, token=user_token, status_code=403)
        self.api.post(url, data=data, token=admin_token, status_code=201)

    def test_only_admin_can_update(self):
        """PATCH only for admins."""
        (key, user_token, admin_token) = self._prepare_tokens_and_key()
        data = {'name': 2 * key['name']}  # New: Twice the fun!
        url = "/apikeys/%s" % key['_id']
        etag = {'If-Match': key['_etag']}

        self.api.patch(url, data=data, headers=etag, status_code=401)
        self.api.patch(url, data=data, headers=etag, token=user_token,
                       status_code=403)
        self.api.patch(url, data=data, headers=etag, token=admin_token,
                       status_code=200)

    def test_only_admin_can_delete(self):
        """PATCH only for admins."""
        (key, user_token, admin_token) = self._prepare_tokens_and_key()
        url = "/apikeys/%s" % key['_id']
        etag = {'If-Match': key['_etag']}

        self.api.delete(url, headers=etag, status_code=401)
        self.api.delete(url, headers=etag, token=user_token, status_code=403)
        self.api.delete(url, headers=etag, token=admin_token, status_code=204)



# 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


# Path: amivapi/tests/auth/test_apikeys.py
from amivapi.tests.utils import WebTest, WebTestNoAuth

        url = "/apikeys"

        self.api.post(url, data=data, status_code=401)
        self.api.post(url, data=data, token=user_token, status_code=403)
        self.api.post(url, data=data, token=admin_token, status_code=201)

    def test_only_admin_can_update(self):
        """PATCH only for admins."""
        (key, user_token, admin_token) = self._prepare_tokens_and_key()
        data = {'name': 2 * key['name']}  # New: Twice the fun!
        url = "/apikeys/%s" % key['_id']
        etag = {'If-Match': key['_etag']}

        self.api.patch(url, data=data, headers=etag, status_code=401)
        self.api.patch(url, data=data, headers=etag, token=user_token,
                       status_code=403)
        self.api.patch(url, data=data, headers=etag, token=admin_token,
                       status_code=200)

    def test_only_admin_can_delete(self):
        """PATCH only for admins."""
        (key, user_token, admin_token) = self._prepare_tokens_and_key()
        url = "/apikeys/%s" % key['_id']
        etag = {'If-Match': key['_etag']}

        self.api.delete(url, headers=etag, status_code=401)
        self.api.delete(url, headers=etag, token=user_token, status_code=403)
        self.api.delete(url, headers=etag, token=admin_token, status_code=204)



class ApiKeyPermissionsTest(WebTest):