chore: Merge skyline-log into skyline-apiserver

1. merge skyline-log into skyline-apiserver
2. move tests into skyline-apiserver
3. we will remove skyline-log after we merge skline-policy-manager
and skyline-nginx into skyline-apiserver

Change-Id: I04b6e0a8bcddc3139a423a6e31dd603d39498ad8
This commit is contained in:
zhu.boxiang 2022-05-11 16:07:03 +08:00
parent 240e26691d
commit b4d2d670cf
31 changed files with 589 additions and 65 deletions

1
.gitignore vendored
View File

@ -70,6 +70,7 @@ venv.bak/
.vscode/
/log/
tmp/
libs/skyline-apiserver/log/
# MAC OS
.DS_Store

View File

@ -45,17 +45,17 @@ lint:
# poetry run mypy --config-file=../../mypy.ini $(PY_FILES)
poetry run isort --check-only --diff $(PY_FILES)
poetry run black --check --diff --color --config ../../pyproject.toml $(PY_FILES)
poetry run flake8 $(PY_FILES)
poetry run flake8 --config ../../.flake8 $(PY_FILES)
.PHONY: test
test:
echo TODO
poetry run pytest
.PHONY: clean
clean:
rm -rf .venv dist
rm -rf .venv dist htmlcov .coverage log
.PHONY: db_revision
@ -74,4 +74,4 @@ db_sync:
# Find python files without "type annotations"
future_check:
@find src ! -size 0 -type f -name *.py -exec grep -L 'from __future__ import annotations' {} \;
@find skyline_apiserver ! -size 0 -type f -name *.py -exec grep -L 'from __future__ import annotations' {} \;

View File

@ -255,6 +255,17 @@ category = "main"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[[package]]
name = "coverage"
version = "6.3.2"
description = "Code coverage measurement for Python"
category = "dev"
optional = false
python-versions = ">=3.7"
[package.extras]
toml = ["tomli"]
[[package]]
name = "cryptography"
version = "37.0.2"
@ -737,6 +748,14 @@ category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "mimesis"
version = "4.1.3"
description = "Mimesis: fake data generator."
category = "dev"
optional = false
python-versions = "*"
[[package]]
name = "msgpack"
version = "1.0.3"
@ -1159,7 +1178,7 @@ test = ["flaky", "pretend", "pytest (>=3.0.1)"]
[[package]]
name = "pyparsing"
version = "3.0.8"
version = "3.0.9"
description = "pyparsing module - Classes and methods to define and execute parsing grammars"
category = "main"
optional = false
@ -1227,6 +1246,22 @@ pytest = ">=5.4.0"
[package.extras]
testing = ["coverage", "hypothesis (>=5.7.1)"]
[[package]]
name = "pytest-cov"
version = "2.12.1"
description = "Pytest plugin for measuring coverage."
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
[package.dependencies]
coverage = ">=5.2.1"
pytest = ">=4.6"
toml = "*"
[package.extras]
testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"]
[[package]]
name = "pytest-forked"
version = "1.4.0"
@ -1239,6 +1274,29 @@ python-versions = ">=3.6"
py = "*"
pytest = ">=3.10"
[[package]]
name = "pytest-html"
version = "3.1.1"
description = "pytest plugin for generating HTML reports"
category = "dev"
optional = false
python-versions = ">=3.6"
[package.dependencies]
pytest = ">=5.0,<6.0.0 || >6.0.0"
pytest-metadata = "*"
[[package]]
name = "pytest-metadata"
version = "1.11.0"
description = "pytest plugin for test session metadata"
category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
[package.dependencies]
pytest = ">=2.9.0"
[[package]]
name = "pytest-xdist"
version = "2.4.0"
@ -1614,15 +1672,10 @@ version = "0.1.0"
description = ""
category = "main"
optional = false
python-versions = "^3.8"
develop = true
python-versions = ">=3.8,<4.0"
[package.dependencies]
loguru = "0.5.3"
[package.source]
type = "directory"
url = "../skyline-log"
loguru = "*"
[[package]]
name = "skyline-policy-manager"
@ -1872,7 +1925,7 @@ testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
content-hash = "6fe9ff8d4b419b55eeb52e5c28abbc395362082f9baf915802c0afedfe6806dd"
content-hash = "ded4edfc5f1c33f84ed7fb28b5e2adadc53e1e694c8d78010156ff1b9a60f971"
[metadata.files]
add-trailing-comma = [
@ -2011,6 +2064,49 @@ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
]
coverage = [
{file = "coverage-6.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:9b27d894748475fa858f9597c0ee1d4829f44683f3813633aaf94b19cb5453cf"},
{file = "coverage-6.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:37d1141ad6b2466a7b53a22e08fe76994c2d35a5b6b469590424a9953155afac"},
{file = "coverage-6.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f9987b0354b06d4df0f4d3e0ec1ae76d7ce7cbca9a2f98c25041eb79eec766f1"},
{file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:26e2deacd414fc2f97dd9f7676ee3eaecd299ca751412d89f40bc01557a6b1b4"},
{file = "coverage-6.3.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4dd8bafa458b5c7d061540f1ee9f18025a68e2d8471b3e858a9dad47c8d41903"},
{file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:46191097ebc381fbf89bdce207a6c107ac4ec0890d8d20f3360345ff5976155c"},
{file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6f89d05e028d274ce4fa1a86887b071ae1755082ef94a6740238cd7a8178804f"},
{file = "coverage-6.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:58303469e9a272b4abdb9e302a780072c0633cdcc0165db7eec0f9e32f901e05"},
{file = "coverage-6.3.2-cp310-cp310-win32.whl", hash = "sha256:2fea046bfb455510e05be95e879f0e768d45c10c11509e20e06d8fcaa31d9e39"},
{file = "coverage-6.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:a2a8b8bcc399edb4347a5ca8b9b87e7524c0967b335fbb08a83c8421489ddee1"},
{file = "coverage-6.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:f1555ea6d6da108e1999b2463ea1003fe03f29213e459145e70edbaf3e004aaa"},
{file = "coverage-6.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5f4e1edcf57ce94e5475fe09e5afa3e3145081318e5fd1a43a6b4539a97e518"},
{file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a15dc0a14008f1da3d1ebd44bdda3e357dbabdf5a0b5034d38fcde0b5c234b7"},
{file = "coverage-6.3.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:21b7745788866028adeb1e0eca3bf1101109e2dc58456cb49d2d9b99a8c516e6"},
{file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:8ce257cac556cb03be4a248d92ed36904a59a4a5ff55a994e92214cde15c5bad"},
{file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b0be84e5a6209858a1d3e8d1806c46214e867ce1b0fd32e4ea03f4bd8b2e3359"},
{file = "coverage-6.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:acf53bc2cf7282ab9b8ba346746afe703474004d9e566ad164c91a7a59f188a4"},
{file = "coverage-6.3.2-cp37-cp37m-win32.whl", hash = "sha256:8bdde1177f2311ee552f47ae6e5aa7750c0e3291ca6b75f71f7ffe1f1dab3dca"},
{file = "coverage-6.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:b31651d018b23ec463e95cf10070d0b2c548aa950a03d0b559eaa11c7e5a6fa3"},
{file = "coverage-6.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:07e6db90cd9686c767dcc593dff16c8c09f9814f5e9c51034066cad3373b914d"},
{file = "coverage-6.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2c6dbb42f3ad25760010c45191e9757e7dce981cbfb90e42feef301d71540059"},
{file = "coverage-6.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c76aeef1b95aff3905fb2ae2d96e319caca5b76fa41d3470b19d4e4a3a313512"},
{file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cf5cfcb1521dc3255d845d9dca3ff204b3229401994ef8d1984b32746bb45ca"},
{file = "coverage-6.3.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8fbbdc8d55990eac1b0919ca69eb5a988a802b854488c34b8f37f3e2025fa90d"},
{file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ec6bc7fe73a938933d4178c9b23c4e0568e43e220aef9472c4f6044bfc6dd0f0"},
{file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9baff2a45ae1f17c8078452e9e5962e518eab705e50a0aa8083733ea7d45f3a6"},
{file = "coverage-6.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:fd9e830e9d8d89b20ab1e5af09b32d33e1a08ef4c4e14411e559556fd788e6b2"},
{file = "coverage-6.3.2-cp38-cp38-win32.whl", hash = "sha256:f7331dbf301b7289013175087636bbaf5b2405e57259dd2c42fdcc9fcc47325e"},
{file = "coverage-6.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:68353fe7cdf91f109fc7d474461b46e7f1f14e533e911a2a2cbb8b0fc8613cf1"},
{file = "coverage-6.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b78e5afb39941572209f71866aa0b206c12f0109835aa0d601e41552f9b3e620"},
{file = "coverage-6.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4e21876082ed887baed0146fe222f861b5815455ada3b33b890f4105d806128d"},
{file = "coverage-6.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34626a7eee2a3da12af0507780bb51eb52dca0e1751fd1471d0810539cefb536"},
{file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1ebf730d2381158ecf3dfd4453fbca0613e16eaa547b4170e2450c9707665ce7"},
{file = "coverage-6.3.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd6fe30bd519694b356cbfcaca9bd5c1737cddd20778c6a581ae20dc8c04def2"},
{file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:96f8a1cb43ca1422f36492bebe63312d396491a9165ed3b9231e778d43a7fca4"},
{file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:dd035edafefee4d573140a76fdc785dc38829fe5a455c4bb12bac8c20cfc3d69"},
{file = "coverage-6.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5ca5aeb4344b30d0bec47481536b8ba1181d50dbe783b0e4ad03c95dc1296684"},
{file = "coverage-6.3.2-cp39-cp39-win32.whl", hash = "sha256:f5fa5803f47e095d7ad8443d28b01d48c0359484fec1b9d8606d0e3282084bc4"},
{file = "coverage-6.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:9548f10d8be799551eb3a9c74bbf2b4934ddb330e08a73320123c07f95cc2d92"},
{file = "coverage-6.3.2-pp36.pp37.pp38-none-any.whl", hash = "sha256:18d520c6860515a771708937d2f78f63cc47ab3b80cb78e86573b0a760161faf"},
{file = "coverage-6.3.2.tar.gz", hash = "sha256:03e2a7826086b91ef345ff18742ee9fc47a6839ccd517061ef8fa1976e652ce9"},
]
cryptography = [
{file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:ef15c2df7656763b4ff20a9bc4381d8352e6640cfeb95c2972c38ef508e75181"},
{file = "cryptography-37.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:3c81599befb4d4f3d7648ed3217e00d21a9341a9a688ecdd615ff72ffbed7336"},
@ -2255,6 +2351,9 @@ mccabe = [
{file = "mccabe-0.6.1-py2.py3-none-any.whl", hash = "sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42"},
{file = "mccabe-0.6.1.tar.gz", hash = "sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"},
]
mimesis = [
{file = "mimesis-4.1.3.tar.gz", hash = "sha256:90f36c21c1bb9944afc17178eb5868b0c85aa1fe49eb04bcbdafafd1ad4ca2ba"},
]
msgpack = [
{file = "msgpack-1.0.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:96acc674bb9c9be63fa8b6dabc3248fdc575c4adc005c440ad02f87ca7edd079"},
{file = "msgpack-1.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c3ca57c96c8e69c1a0d2926a6acf2d9a522b41dc4253a8945c4c6cd4981a4e3"},
@ -2534,8 +2633,8 @@ pyopenssl = [
{file = "pyOpenSSL-22.0.0.tar.gz", hash = "sha256:660b1b1425aac4a1bea1d94168a85d99f0b3144c869dd4390d27629d0087f1bf"},
]
pyparsing = [
{file = "pyparsing-3.0.8-py3-none-any.whl", hash = "sha256:ef7b523f6356f763771559412c0d7134753f037822dad1b16945b7b846f7ad06"},
{file = "pyparsing-3.0.8.tar.gz", hash = "sha256:7bf433498c016c4314268d95df76c81b842a4cb2b276fa3312cfb1e1d85f6954"},
{file = "pyparsing-3.0.9-py3-none-any.whl", hash = "sha256:5026bae9a10eeaefb61dab2f09052b9f4307d44aee4eda64b309723d8d206bbc"},
{file = "pyparsing-3.0.9.tar.gz", hash = "sha256:2b020ecf7d21b687f219b71ecad3631f644a47f01403fa1d1036b0c6416d70fb"},
]
pyperclip = [
{file = "pyperclip-1.8.2.tar.gz", hash = "sha256:105254a8b04934f0bc84e9c24eb360a591aaf6535c9def5f29d92af107a9bf57"},
@ -2575,10 +2674,22 @@ pytest-asyncio = [
{file = "pytest-asyncio-0.15.1.tar.gz", hash = "sha256:2564ceb9612bbd560d19ca4b41347b54e7835c2f792c504f698e05395ed63f6f"},
{file = "pytest_asyncio-0.15.1-py3-none-any.whl", hash = "sha256:3042bcdf1c5d978f6b74d96a151c4cfb9dcece65006198389ccd7e6c60eb1eea"},
]
pytest-cov = [
{file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"},
{file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"},
]
pytest-forked = [
{file = "pytest-forked-1.4.0.tar.gz", hash = "sha256:8b67587c8f98cbbadfdd804539ed5455b6ed03802203485dd2f53c1422d7440e"},
{file = "pytest_forked-1.4.0-py3-none-any.whl", hash = "sha256:bbbb6717efc886b9d64537b41fb1497cfaf3c9601276be8da2cccfea5a3c8ad8"},
]
pytest-html = [
{file = "pytest-html-3.1.1.tar.gz", hash = "sha256:3ee1cf319c913d19fe53aeb0bc400e7b0bc2dbeb477553733db1dad12eb75ee3"},
{file = "pytest_html-3.1.1-py3-none-any.whl", hash = "sha256:b7f82f123936a3f4d2950bc993c2c1ca09ce262c9ae12f9ac763a2401380b455"},
]
pytest-metadata = [
{file = "pytest-metadata-1.11.0.tar.gz", hash = "sha256:71b506d49d34e539cc3cfdb7ce2c5f072bea5c953320002c95968e0238f8ecf1"},
{file = "pytest_metadata-1.11.0-py2.py3-none-any.whl", hash = "sha256:576055b8336dd4a9006dd2a47615f76f2f8c30ab12b1b1c039d99e834583523f"},
]
pytest-xdist = [
{file = "pytest-xdist-2.4.0.tar.gz", hash = "sha256:89b330316f7fc475f999c81b577c2b926c9569f3d397ae432c0c2e2496d61ff9"},
{file = "pytest_xdist-2.4.0-py3-none-any.whl", hash = "sha256:7b61ebb46997a0820a263553179d6d1e25a8c50d8a8620cd1aa1e20e3be99168"},
@ -2829,7 +2940,9 @@ six = [
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
skyline-config = []
skyline-log = []
skyline-log = [
{file = "skyline_log-0.1.0-py3-none-any.whl", hash = "sha256:60e61784ce43061c62ea424d271fd6ad0c04ba2a9e2df5d1e1f490a9cceb8d3b"},
]
skyline-policy-manager = []
sniffio = [
{file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"},

View File

@ -23,6 +23,7 @@ aiomysql = "0.0.21"
pymysql = "0.9.3"
aiosqlite = "0.17.0"
dnspython = "2.1.0"
loguru = "0.5.3"
python-keystoneclient = "3.21.0"
python-cinderclient = "5.0.2"
python-glanceclient = "2.17.1"
@ -33,7 +34,6 @@ python-octaviaclient = "1.10.1"
osc-placement = "1.7.0"
keystoneauth1 = "3.17.4"
skyline-policy-manager = "*"
skyline-log = "*"
skyline-config = "*"
[tool.poetry.dev-dependencies]
@ -45,16 +45,29 @@ mypy = "0.910"
pytest = "6.2.5"
pytest-xdist = "2.4.0"
pytest-asyncio = "0.15.1"
pytest-cov = "2.12.1"
pytest-html = "3.1.1"
mimesis = "4.1.3"
click = "7.1.2"
asgi-lifespan = "1.0.1"
types-PyYAML = "5.4.10"
skyline-policy-manager = {path = "../skyline-policy-manager", develop = true}
skyline-log = {path = "../skyline-log", develop = true}
skyline-config = {path = "../skyline-config", develop = true}
[tool.poetry.scripts]
swagger-generator = 'skyline_apiserver.cmd.generate_swagger:main'
config-sample-generator = 'skyline_apiserver.cmd.generate_sample_config:main'
[tool.pytest.ini_options]
minversion = "6.0"
addopts = "-v -s -p no:cacheprovider -n auto --cov=skyline_apiserver --cov-append --cov-report=term-missing --cov-report=html"
testpaths = [
"skyline_apiserver/tests",
]
markers = [
"ddt(*args: TestData): Mark the test as a data-driven test."
]
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

View File

@ -20,7 +20,7 @@ from pprint import pprint
import uvloop
from skyline_apiserver.config import configure
from skyline_log import setup
from skyline_apiserver.log import setup
async def main() -> None:

View File

@ -22,9 +22,9 @@ from skyline_apiserver import schemas
from skyline_apiserver.client.openstack import system
from skyline_apiserver.client.openstack.system import get_endpoints
from skyline_apiserver.config import CONF
from skyline_apiserver.log import LOG
from skyline_apiserver.schemas import common
from skyline_apiserver.types import constants
from skyline_log import LOG
router = APIRouter()

View File

@ -35,8 +35,8 @@ from skyline_apiserver.core.security import (
parse_access_token,
)
from skyline_apiserver.db import api as db_api
from skyline_apiserver.log import LOG
from skyline_apiserver.types import constants
from skyline_log import LOG
router = APIRouter()

View File

@ -22,8 +22,8 @@ from keystoneauth1.session import Session
from skyline_apiserver.client import utils
from skyline_apiserver.client.utils import get_system_session
from skyline_apiserver.config import CONF
from skyline_apiserver.log import LOG
from skyline_apiserver.types import constants
from skyline_log import LOG
from starlette.concurrency import run_in_threadpool

View File

@ -18,7 +18,7 @@ from alembic import context
from databases import DatabaseURL
from skyline_apiserver.config import CONF, configure
from skyline_apiserver.db.models import METADATA
from skyline_log import setup as log_setup
from skyline_apiserver.log import setup as log_setup
from sqlalchemy import create_engine, pool
configure("skyline")

View File

@ -0,0 +1,83 @@
# Copyright 2021 99cloud
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import inspect
import logging
from logging import Handler, LogRecord
from pathlib import PurePath
from typing import Optional, Union
import loguru
from loguru import logger
LOG = loguru.logger
class InterceptHandler(logging.Handler):
def emit(self, record: LogRecord) -> None:
# Get corresponding Loguru level if it exists
level = getattr(logger.level(record.levelname), "name", record.levelno)
# Find caller from where originated the logged message
frame, depth = getattr(inspect.currentframe(), "f_back", None), 1
while frame and frame.f_code.co_filename == logging.__file__:
frame = frame.f_back
depth += 1
logger.opt(depth=depth, exception=record.exc_info).log(
level,
record.getMessage(),
)
def setup(
sink: Union[PurePath, str, Handler],
debug: bool = False,
colorize: bool = False,
level: Optional[str] = None,
) -> None:
if debug:
default_level = "DEBUG"
backtrace = True
diagnose = True
else:
default_level = "WARNING"
backtrace = False
diagnose = True
if level is None:
level = default_level
LOG.remove()
LOG.add(
sink,
level=level,
format=(
"<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | <level>{level: <8}</level> |"
" <cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> -"
" <level>{message}</level>"
),
filter=None,
colorize=colorize,
backtrace=backtrace,
diagnose=diagnose,
serialize=False,
enqueue=False,
catch=True,
)
logging.basicConfig(handlers=[InterceptHandler()], level=0, force=True)
__all__ = ("LOG", "setup")

View File

@ -20,8 +20,8 @@ from fastapi import FastAPI
from skyline_apiserver.api.v1 import api_router
from skyline_apiserver.config import CONF, configure
from skyline_apiserver.db import setup as db_setup
from skyline_apiserver.log import LOG, setup as log_setup
from skyline_apiserver.policies import setup as policies_setup
from skyline_log import LOG, setup as log_setup
from starlette.middleware.cors import CORSMiddleware
PROJECT_NAME = "Skyline API"

View File

@ -84,6 +84,7 @@ async def test_switch_project(client: AsyncClient, login_jwt: str) -> None:
await utils._logout(client)
@pytest.mark.skipif(os.getenv("TEST_API") != "true", reason="No backend OpenStack for api-test.")
@pytest.mark.asyncio
async def test_get_profile_no_auth(client: AsyncClient) -> None:
r = await client.get(f"{main.API_PREFIX}/profile")
@ -92,6 +93,7 @@ async def test_get_profile_no_auth(client: AsyncClient) -> None:
assert result["detail"] == constants.ERR_MSG_TOKEN_NOTFOUND
@pytest.mark.skipif(os.getenv("TEST_API") != "true", reason="No backend OpenStack for api-test.")
@pytest.mark.asyncio
async def test_get_profile_token_expire(client: AsyncClient) -> None:
profile = utils.get_session_profile()
@ -107,6 +109,7 @@ async def test_get_profile_token_expire(client: AsyncClient) -> None:
assert result["detail"].startswith(constants.ERR_MSG_TOKEN_EXPIRED)
@pytest.mark.skipif(os.getenv("TEST_API") != "true", reason="No backend OpenStack for api-test.")
@pytest.mark.asyncio
async def test_get_profile_token_revoke(client: AsyncClient) -> None:
profile = utils.get_session_profile()
@ -123,6 +126,7 @@ async def test_get_profile_token_revoke(client: AsyncClient) -> None:
assert result["detail"] == constants.ERR_MSG_TOKEN_REVOKED
@pytest.mark.skipif(os.getenv("TEST_API") != "true", reason="No backend OpenStack for api-test.")
@pytest.mark.asyncio
async def test_logout(client: AsyncClient, session_token: str) -> None:
r = await client.post(

View File

@ -0,0 +1,70 @@
# Copyright 2021 99cloud
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import TYPE_CHECKING, Iterator, Optional
import pytest
from _pytest.mark import ParameterSet
from asgi_lifespan import LifespanManager
from httpx import AsyncClient
from skyline_apiserver.config import CONF
from skyline_apiserver.main import app
from skyline_apiserver.tests.models import TestData
from skyline_apiserver.tests.utils import utils
if TYPE_CHECKING:
from _pytest.python import Metafunc
@pytest.fixture(scope="function")
async def client() -> Iterator[AsyncClient]:
async with LifespanManager(app):
async with AsyncClient(app=app, base_url="http://test") as ac:
yield ac
CONF.cleanup()
@pytest.fixture(scope="function")
async def session_token(client: AsyncClient) -> str:
return utils.get_session_token()
@pytest.fixture(scope="function")
async def login_jwt(client: AsyncClient) -> str:
return await utils.get_jwt_from_cookie(client)
def pytest_generate_tests(metafunc: Optional["Metafunc"]) -> None:
for marker in metafunc.definition.iter_markers(name="ddt"):
test_data: TestData
for test_data in marker.args:
argument_length = len(test_data.arguments)
argvalues = []
for argument_data in test_data.argument_data_set:
if len(argument_data.values) != argument_length:
raise ValueError(
f'Argument data "{argument_data.id}" of method '
f'"{metafunc.function.__name__}" doesn\'t match '
"number of arguments.",
)
argvalues.append(
ParameterSet(
id=argument_data.id,
marks=argument_data.marks,
values=argument_data.values,
),
)
metafunc.parametrize(test_data.arguments, argvalues, indirect=test_data.indirect)

View File

@ -0,0 +1,19 @@
# Copyright 2021 99cloud
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from mimesis import Generic
FAKER = Generic()

View File

@ -0,0 +1,36 @@
# Copyright 2021 99cloud
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
from dataclasses import dataclass
from typing import Any, Collection, Sequence, Tuple, Union
@dataclass
class ArgumentData:
id: str
values: Sequence[object]
# TODO: Fix type annotation of `marks` after the pytest > 7.0.0
# marks: Collection[Union[pytest.MarkDecorator, pytest.Mark]]
marks: Collection[Any] = ()
@dataclass
class TestData:
arguments: Tuple[str, ...]
argument_data_set: Sequence[ArgumentData]
indirect: Union[bool, Tuple[str]] = False
__test__ = False

View File

@ -0,0 +1,226 @@
# Copyright 2021 99cloud
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from __future__ import annotations
import logging
from logging import StreamHandler
from pathlib import Path
import pytest
from _pytest.capture import CaptureFixture
from _pytest.fixtures import SubRequest
from skyline_apiserver.log import LOG, setup as log_setup
from skyline_apiserver.tests.fake import FAKER
from skyline_apiserver.tests.models import ArgumentData, TestData
class TestLog:
@pytest.fixture
def file_sink_captor(self, request: SubRequest, tmp_path: Path) -> Path:
file_name: str = request.param
file = tmp_path.joinpath(file_name)
file.touch()
return file
@pytest.mark.ddt(
TestData(
arguments=("file_sink_captor",),
indirect=("file_sink_captor",),
argument_data_set=[
ArgumentData(
id="str_file_path",
values=(FAKER.text.word(),),
),
],
),
TestData(
arguments=("debug",),
argument_data_set=[
ArgumentData(
id="enable_debug",
values=(True,),
),
ArgumentData(
id="disable_debug",
values=(False,),
),
],
),
TestData(
arguments=("level",),
argument_data_set=[
ArgumentData(
id="debug_level",
values=("debug",),
),
ArgumentData(
id="info_level",
values=("info",),
),
ArgumentData(
id="warning_level",
values=("warning",),
),
ArgumentData(
id="error_level",
values=("error",),
),
],
),
)
def test_file_sink_setup(self, file_sink_captor: Path, debug: bool, level: str) -> None:
log_setup(file_sink_captor.as_posix(), debug)
content = FAKER.text.text()
log = getattr(LOG, level)
log(content)
file_content = file_sink_captor.read_text()
if debug is False and level in ["debug", "info"]:
assert f"| {level.upper():<8} |" not in file_content
assert content not in file_content
else:
assert f"| {level.upper():<8} |" in file_content
assert content in file_content
@pytest.fixture
def stream_sink_captor(
self,
request: SubRequest,
capsys: CaptureFixture[str],
) -> CaptureFixture[str]:
return capsys
@pytest.mark.ddt(
TestData(
arguments=("stream_sink_captor",),
indirect=("stream_sink_captor",),
argument_data_set=[
ArgumentData(
id="std_output",
values=(StreamHandler,),
),
],
),
TestData(
arguments=("debug",),
argument_data_set=[
ArgumentData(
id="enable_debug",
values=(True,),
),
ArgumentData(
id="disable_debug",
values=(False,),
),
],
),
TestData(
arguments=("level",),
argument_data_set=[
ArgumentData(
id="debug_level",
values=("debug",),
),
ArgumentData(
id="info_level",
values=("info",),
),
ArgumentData(
id="warning_level",
values=("warning",),
),
ArgumentData(
id="error_level",
values=("error",),
),
],
),
)
def test_stream_sink_setup(
self,
stream_sink_captor: CaptureFixture[str],
debug: bool,
level: str,
) -> None:
log_setup(StreamHandler(), debug)
content = FAKER.text.text()
log = getattr(LOG, level)
log(content)
std_out, std_err = stream_sink_captor.readouterr()
if debug is False and level in ["debug", "info"]:
assert f"| {level.upper():<8} |" not in std_err
assert content not in std_err
else:
assert f"| {level.upper():<8} |" in std_err
assert content in std_err
@pytest.mark.ddt(
TestData(
arguments=("file_sink_captor",),
indirect=("file_sink_captor",),
argument_data_set=[
ArgumentData(
id="str_file_path",
values=(FAKER.text.word(),),
),
],
),
TestData(
arguments=("debug",),
argument_data_set=[
ArgumentData(
id="enable_debug",
values=(True,),
),
ArgumentData(
id="disable_debug",
values=(False,),
),
],
),
TestData(
arguments=("level",),
argument_data_set=[
ArgumentData(
id="debug_level",
values=("debug",),
),
ArgumentData(
id="info_level",
values=("info",),
),
ArgumentData(
id="warning_level",
values=("warning",),
),
ArgumentData(
id="error_level",
values=("error",),
),
],
),
)
def test_standard_logging(self, file_sink_captor: Path, debug: bool, level: str) -> None:
log_setup(file_sink_captor.as_posix(), debug)
content = FAKER.text.text()
std_logger = logging.getLogger()
log = getattr(std_logger, level)
log(content)
file_content = file_sink_captor.read_text()
if debug is False and level in ["debug", "info"]:
assert f"| {level.upper():<8} |" not in file_content
assert content not in file_content
else:
assert f"| {level.upper():<8} |" in file_content
assert content in file_content

View File

@ -1,41 +0,0 @@
# Copyright 2021 99cloud
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from typing import Iterator
import pytest
from asgi_lifespan import LifespanManager
from httpx import AsyncClient
from skyline_apiserver.config import CONF
from skyline_apiserver.main import app
from utils import utils
@pytest.fixture(scope="function")
async def client() -> Iterator[AsyncClient]:
async with LifespanManager(app):
async with AsyncClient(app=app, base_url="http://test") as ac:
yield ac
CONF.cleanup()
@pytest.fixture(scope="function")
async def session_token(client: AsyncClient) -> str:
return utils.get_session_token()
@pytest.fixture(scope="function")
async def login_jwt(client: AsyncClient) -> str:
return await utils.get_jwt_from_cookie(client)