Current File : /home/inlingua/miniconda3/lib/python3.1/site-packages/conda/testing/notices/helpers.py |
# Copyright (C) 2012 Anaconda, Inc
# SPDX-License-Identifier: BSD-3-Clause
"""Collection of helper functions used in conda.notices tests."""
from __future__ import annotations
import datetime
import json
import os
import uuid
from itertools import chain
from pathlib import Path
from typing import TYPE_CHECKING
from ...models.channel import get_channel_objs
from ...notices.cache import get_notices_cache_file
from ...notices.core import get_channel_name_and_urls
from ...notices.types import ChannelNoticeResponse
if TYPE_CHECKING:
from collections.abc import Sequence
from unittest import mock
from ...base.context import Context
DEFAULT_NOTICE_MESG = "Here is an example message that will be displayed to users"
def get_test_notices(
messages: Sequence[str],
level: str | None = "info",
created_at: datetime.datetime | None = None,
expired_at: datetime.datetime | None = None,
) -> dict:
created_at = created_at or datetime.datetime.now(datetime.timezone.utc)
expired_at = expired_at or created_at + datetime.timedelta(days=7)
return {
"notices": [
{
"id": str(uuid.uuid4()),
"message": message,
"level": level,
"created_at": created_at.isoformat(),
"expired_at": expired_at.isoformat(),
}
for message in messages
]
}
def add_resp_to_mock(
mock_session: mock.MagicMock,
status_code: int,
messages_json: dict,
raise_exc: bool = False,
) -> None:
"""Adds any number of MockResponse to MagicMock object as side_effects"""
def forever_404():
while True:
yield MockResponse(404, {})
def one_200():
yield MockResponse(status_code, messages_json, raise_exc=raise_exc)
chn = chain(one_200(), forever_404())
mock_session().get.side_effect = tuple(next(chn) for _ in range(100))
def create_notice_cache_files(
cache_dir: Path,
cache_files: Sequence[str],
messages_json_seq: Sequence[dict],
) -> None:
"""Creates the cache files that we use in tests"""
for message_json, file in zip(messages_json_seq, cache_files):
with cache_dir.joinpath(file).open("w") as fp:
json.dump(message_json, fp)
def offset_cache_file_mtime(mtime_offset) -> None:
"""
Allows for offsetting the mtime of the notices cache file. This is often
used to mock an older creation time the cache file.
"""
cache_file = get_notices_cache_file()
os.utime(
cache_file,
times=(cache_file.stat().st_atime, cache_file.stat().st_mtime - mtime_offset),
)
class DummyArgs:
"""Dummy object that sets all kwargs as object properties."""
def __init__(self, **kwargs):
self.no_ansi_colors = True
for key, val in kwargs.items():
setattr(self, key, val)
def notices_decorator_assert_message_in_stdout(
captured,
messages: Sequence[str],
dummy_mesg: str | None = None,
not_in: bool = False,
):
"""
Tests a run of notices decorator where we expect to see the messages
print to stdout.
"""
assert captured.err == ""
assert dummy_mesg in captured.out
for mesg in messages:
if not_in:
assert mesg not in captured.out
else:
assert mesg in captured.out
class MockResponse:
def __init__(self, status_code, json_data, raise_exc=False):
self.status_code = status_code
self.json_data = json_data
self.raise_exc = raise_exc
def json(self):
if self.raise_exc:
raise ValueError("Error")
return self.json_data
def get_notice_cache_filenames(ctx: Context) -> tuple[str]:
"""Returns the filenames of the cache files that will be searched for"""
channel_urls_and_names = get_channel_name_and_urls(get_channel_objs(ctx))
return tuple(
ChannelNoticeResponse.get_cache_key(url, Path("")).name
for url, name in channel_urls_and_names
)