mirror of
https://github.com/OPSnet/eac_logchecker.py.git
synced 2026-11-09 17:39:06 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84f35b3349 | ||
|
|
c57b56d586 | ||
|
|
7f98399782 | ||
|
|
12d96935ca | ||
|
|
fc3856de07 | ||
|
|
ef17ea3b7f | ||
|
|
67e93d1732 | ||
|
|
5759035277 | ||
|
|
0d31170f0d | ||
|
|
a4760b83c1 |
No files matched your search
+3
-1
@@ -2,4 +2,6 @@
|
||||
build/
|
||||
dist/
|
||||
*.egg-info/
|
||||
.eggs/
|
||||
.eggs/
|
||||
.pytest_cache/
|
||||
__pycache__/
|
||||
+10
-10
@@ -1,16 +1,16 @@
|
||||
language: python
|
||||
dist: trusty
|
||||
sudo: true
|
||||
python:
|
||||
- "3.5"
|
||||
- "3.6"
|
||||
- "3.7"
|
||||
- "3.8"
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- python: '3.5'
|
||||
- python: '3.6'
|
||||
- python: '3.7'
|
||||
dist: xenial
|
||||
install:
|
||||
- python3 -m pip install pytest
|
||||
- python3 -m pip install -e .
|
||||
|
||||
script:
|
||||
- python3 setup.py test
|
||||
- pytest
|
||||
|
||||
deploy:
|
||||
provider: pypi
|
||||
@@ -20,4 +20,4 @@ deploy:
|
||||
secure: rGBkzH4DOs8Y4AY/J5yJNVGzEabV/cnKhZmh5bN5GxR6H0H/he3/J3+0pXb+omLkXyvcIiQQ/paoIs/TMQ2Ujgvkp1iSVB10OrPmhCZZv6sw3+wkQO2tuiCggHbuYZbOwZFFjaapqIW1RONHCl+qE2hvN7aVfDxbohAyVnsVUYoEGl6kKuPVuMmSBikIyWFO/NuIPYaKUSqTCORty/qfUNTOSp2nQUqg1jQb7WDb3YuBLMVPUSU7XvdswkN2nrlcJwM75AbX7B8SVfkyoVQvkgwhdVLFwTjJmXyHqfpS10CKQt9fM1442yxrI8G7+ss/fvXgaaUN+zZzu8GlPs6mpDhYNnHZ1SOHqznTag87fJFhRxhrjoxomv0m5wPX1iB9eIzqjygfn5bsatNOCPUGEhOPysF7FcchmqTqR02XXOfVhw1+OAHExadGk5ySaWazG3ajNwWQjFXu9mYh5oLZSH7ZsWjB4TiwDsta9P7Db24Y086vF/zHOHNoNf81y9G+ArUUpfZuK4QZSfTHw61+CRT4W1unAGaixDN3THcx6B5rsGuFkN6bXyWtWNT6i1X1p4wQSdIGba+2vp8VMSGENoPDpbBEd2vMl5DDqJd3mA7+nywFnQCfb89lh1Hd/ihY+Qcxag6+L82bf23Y8xULB/d0sbeZUcHf1WfK6HOTLFo=
|
||||
on:
|
||||
python: '3.6'
|
||||
tags: true
|
||||
tags: true
|
||||
@@ -1,13 +0,0 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[dev-packages]
|
||||
|
||||
[packages]
|
||||
chardet = "*"
|
||||
pprp = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.6"
|
||||
@@ -1,6 +1,6 @@
|
||||
# EAC Logchecker
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
This is a transparent implementation of the Exact Audio Copy log checksum algorithm in Python 3.5+.
|
||||
@@ -9,12 +9,12 @@ This is a fork of https://github.com/puddly/eac_logsigner, with modifications to
|
||||
better match the output of the actual EAC Logchecker to be used in downstream applications. All
|
||||
credit goes to puddly for reverse-engineering the closed source EAC to develop the base.
|
||||
|
||||
# Requirements
|
||||
## Requirements
|
||||
|
||||
* Python 3.5+
|
||||
* [pprp](http://pypi.org/project/pprp)
|
||||
* [pprp](http://pypi.org/project/pprp)==0.2.6
|
||||
|
||||
# Installation
|
||||
## Installation
|
||||
|
||||
From PyPI:
|
||||
|
||||
@@ -26,7 +26,7 @@ From source:
|
||||
$ cd eac_logchecker.py
|
||||
$ python setup.py install
|
||||
|
||||
# Usage
|
||||
## Usage
|
||||
|
||||
usage: eac_logchecker.py [-h] [--json] file
|
||||
|
||||
@@ -39,7 +39,7 @@ From source:
|
||||
-h, --help show this help message and exit
|
||||
--json Output as JSON
|
||||
|
||||
# Example
|
||||
## Example
|
||||
|
||||
$ eac_logchecker logs/01.log
|
||||
Log Integrity Checker (C) 2010 by Andre Wiethoff
|
||||
@@ -51,18 +51,18 @@ From source:
|
||||
|
||||
1. Log entry is fine!
|
||||
2. Log entry is fine!
|
||||
$ eac_logchecker --json logs/05.log
|
||||
$ eac_logchecker --json logs/05.log
|
||||
[{"message": "Log entry is fine!", "status": "OK"}, {"message": "Log entry is fine!", "status": "OK"}]
|
||||
|
||||
# Algorithm
|
||||
## Algorithm
|
||||
|
||||
1. Strip the log file of newlines and BOMs.
|
||||
2. Cut off the existing signature block and (re-)encode the log text back into little-endian UTF-16
|
||||
3. Encrypt the log file with Rijndael-256:
|
||||
- in CBC mode
|
||||
- with a 256-bit block size (most AES implementations hard-code a 128-bit block size)
|
||||
- all-zeroes IV
|
||||
- zero-padding
|
||||
- the hex key `9378716cf13e4265ae55338e940b376184da389e50647726b35f6f341ee3efd9`
|
||||
* in CBC mode
|
||||
* with a 256-bit block size (most AES implementations hard-code a 128-bit block size)
|
||||
* all-zeroes IV
|
||||
* zero-padding
|
||||
* the hex key `9378716cf13e4265ae55338e940b376184da389e50647726b35f6f341ee3efd9`
|
||||
4. XOR together all of the resulting 256-bit ciphertext blocks. You can do it byte-by-byte, it doesn't matter in the end.
|
||||
5. Output the little-endian representation of the above number, in uppercase hex.
|
||||
+86
-37
@@ -1,16 +1,29 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import argparse
|
||||
import contextlib
|
||||
import json
|
||||
from pathlib import Path
|
||||
import re
|
||||
import pprp
|
||||
|
||||
CHECKSUM_MIN_VERSION = ('V1.0', 'beta', '1')
|
||||
EAC_KEY = '9378716cf13e4265ae55338e940b376184da389e50647726b35f6f341ee3efd9'
|
||||
|
||||
__version__ = '0.8.1'
|
||||
|
||||
|
||||
def eac_checksum(text):
|
||||
class Log:
|
||||
def __init__(self, text):
|
||||
self.text = text
|
||||
self.unsigned_text = self.text
|
||||
self.version = None
|
||||
self.modified = False
|
||||
self.old_checksum = None
|
||||
self.checksum = None
|
||||
|
||||
|
||||
def eac_checksum(log):
|
||||
text = log.unsigned_text
|
||||
# Ignore newlines
|
||||
text = text.replace('\r', '').replace('\n', '')
|
||||
|
||||
@@ -19,8 +32,9 @@ def eac_checksum(text):
|
||||
|
||||
# Setup Rijndael-256 with a 256-bit blocksize
|
||||
cipher = pprp.crypto_3.rijndael(
|
||||
# Probably SHA256('super secret password') but it doesn't actually matter
|
||||
key=bytes.fromhex('9378716cf13e4265ae55338e940b376184da389e50647726b35f6f341ee3efd9'),
|
||||
# Probably SHA256('super secret password') but it doesn't
|
||||
# actually matter
|
||||
key=bytes.fromhex(EAC_KEY),
|
||||
block_size=256 // 8
|
||||
)
|
||||
|
||||
@@ -28,7 +42,7 @@ def eac_checksum(text):
|
||||
plaintext = text.encode('utf-16-le')
|
||||
|
||||
# The IV is all zeroes so we don't have to handle it
|
||||
signature = b'\x00' * 32
|
||||
checksum = b'\x00' * 32
|
||||
|
||||
# Process it block-by-block
|
||||
for i in range(0, len(plaintext), 32):
|
||||
@@ -36,39 +50,37 @@ def eac_checksum(text):
|
||||
plaintext_block = plaintext[i:i + 32].ljust(32, b'\x00')
|
||||
|
||||
# CBC mode (XOR the previous ciphertext block into the plaintext)
|
||||
cbc_plaintext = bytes(a ^ b for a, b in zip(signature, plaintext_block))
|
||||
cbc_plaintext = bytes(
|
||||
a ^ b for a, b in zip(checksum, plaintext_block)
|
||||
)
|
||||
|
||||
# New signature is the ciphertext.
|
||||
signature = cipher.encrypt(cbc_plaintext)
|
||||
# New checksum is the ciphertext.
|
||||
checksum = cipher.encrypt(cbc_plaintext)
|
||||
|
||||
# Textual signature is just the hex representation
|
||||
return signature.hex().upper()
|
||||
# Textual checksum is just the hex representation
|
||||
log.checksum = checksum.hex().upper()
|
||||
|
||||
|
||||
def extract_info(text):
|
||||
if len(text) == 0:
|
||||
return text, None, None
|
||||
def extract_info(log):
|
||||
if len(log.text) == 0:
|
||||
return log
|
||||
|
||||
version = None
|
||||
for line in text.splitlines():
|
||||
for line in log.text.splitlines():
|
||||
if line.startswith('Exact Audio Copy'):
|
||||
version = tuple(line.split()[3:6])
|
||||
log.version = tuple(line.split()[3:6])
|
||||
elif re.match(r'[a-zA-Z]', line):
|
||||
break
|
||||
|
||||
match = re.search('\n\n==== (.*) ([A-Z0-9]+) ====', text)
|
||||
match = re.search('\n\n==== (.*) ([A-Z0-9]+) ====', log.text)
|
||||
if match:
|
||||
text, signature_parts = re.split('\n\n==== {}'.format(match.group(1)), text)
|
||||
signature = signature_parts.split()[0].strip()
|
||||
else:
|
||||
signature = None
|
||||
|
||||
return text, version, signature
|
||||
search = '\n\n==== {}'.format(match.group(1))
|
||||
log.unsigned_text, checksum_parts = re.split(search, log.text)
|
||||
log.old_checksum = checksum_parts.split()[0].strip()
|
||||
|
||||
|
||||
def eac_verify(text):
|
||||
unsigned_text, version, old_signature = extract_info(text)
|
||||
return unsigned_text, version, old_signature, eac_checksum(unsigned_text)
|
||||
def eac_verify(log):
|
||||
extract_info(log)
|
||||
eac_checksum(log)
|
||||
|
||||
|
||||
def get_logs(data):
|
||||
@@ -85,35 +97,64 @@ def get_logs(data):
|
||||
# Null bytes screw it up
|
||||
if '\x00' in text:
|
||||
text = text[:text.index('\x00')]
|
||||
|
||||
|
||||
# EAC crashes if there are more than 2^14 bytes in a line
|
||||
if any(len(l) + 1 > 2**13 for l in text.split('\n')):
|
||||
raise RuntimeError('EAC cannot handle lines longer than 2^13 chars')
|
||||
|
||||
return [x.strip() for x in re.split(r'[^-]-{60}[^-]', text)]
|
||||
splits = re.split('(\n\n==== .* [A-Z0-9]+ ====)', text)
|
||||
logs = []
|
||||
for split in splits:
|
||||
if split.strip() != '':
|
||||
logs.append(split)
|
||||
|
||||
if len(logs) > 1:
|
||||
length = len(logs) - 1 if len(logs) % 2 == 1 else len(logs)
|
||||
return_logs = []
|
||||
for i in range(0, length, 2):
|
||||
log = Log(logs[i] + logs[i+1])
|
||||
if i > 0:
|
||||
(log.text, matches) = re.subn(
|
||||
r'[^-]-{60}[^-]',
|
||||
'',
|
||||
log.text,
|
||||
1
|
||||
)
|
||||
if matches == 0:
|
||||
log.modified = True
|
||||
return_logs.append(log)
|
||||
for i in range(length, len(logs)):
|
||||
return_logs.append(Log(logs[i]))
|
||||
else:
|
||||
return_logs = [Log(logs[0])]
|
||||
|
||||
return return_logs
|
||||
|
||||
|
||||
def check_checksum(arg_file, arg_json):
|
||||
def check_checksum(arg_file):
|
||||
if not isinstance(arg_file, Path):
|
||||
arg_file = Path(arg_file)
|
||||
|
||||
|
||||
output = []
|
||||
|
||||
if not arg_file.exists():
|
||||
if not arg_json:
|
||||
print('Could not find logfile to examine.')
|
||||
output.append({
|
||||
'status': 'ERROR',
|
||||
'message': 'Could not find logfile to examine.'
|
||||
})
|
||||
return output
|
||||
|
||||
try:
|
||||
with arg_file.open('rb') as open_file:
|
||||
logs = get_logs(open_file.read())
|
||||
|
||||
for log in logs:
|
||||
data, version, old_signature, actual_signature = eac_verify(log)
|
||||
eac_verify(log)
|
||||
|
||||
if version is None or old_signature is None:
|
||||
if log.version is None or log.old_checksum is None:
|
||||
message = 'Log entry has no checksum!'
|
||||
status = "NO"
|
||||
elif old_signature != actual_signature:
|
||||
elif log.modified or log.old_checksum != log.checksum:
|
||||
message = 'Log entry was modified, checksum incorrect!'
|
||||
status = "BAD"
|
||||
else:
|
||||
@@ -135,7 +176,14 @@ def check_checksum(arg_file, arg_json):
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='Verifies and resigns EAC logs')
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Verifies and resigns EAC logs'
|
||||
)
|
||||
parser.add_argument(
|
||||
'--version',
|
||||
action='version',
|
||||
version='%(prog)s ' + __version__
|
||||
)
|
||||
parser.add_argument('--json', action='store_true', help='Output as JSON')
|
||||
parser.add_argument('file', type=Path, help='input log file')
|
||||
|
||||
@@ -145,12 +193,13 @@ def main():
|
||||
if not args.json:
|
||||
print('Log Integrity Checker (C) 2010 by Andre Wiethoff')
|
||||
print('')
|
||||
output = check_checksum(args.file, args.json)
|
||||
output = check_checksum(args.file)
|
||||
if args.json:
|
||||
print(json.dumps(output))
|
||||
else:
|
||||
for i in range(len(output)):
|
||||
print('{:d}. {:s}'.format(i+1, output[i]['message']))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
BIN
Binary file not shown.
@@ -1,15 +1,15 @@
|
||||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Note: To use the 'upload' functionality of this file, you must:
|
||||
# $ pip install twine
|
||||
|
||||
import io
|
||||
import os
|
||||
from pathlib import Path
|
||||
import re
|
||||
import sys
|
||||
from shutil import rmtree
|
||||
|
||||
from setuptools import find_packages, setup, Command
|
||||
from setuptools import setup, Command
|
||||
|
||||
# Package meta-data.
|
||||
NAME = 'eac_logchecker'
|
||||
@@ -18,17 +18,15 @@ URL = 'https://github.com/OPSnet/eac_logchecker.py'
|
||||
EMAIL = '[email protected]'
|
||||
AUTHOR = 'OPS'
|
||||
REQUIRES_PYTHON = '>=3.5.0'
|
||||
VERSION = '0.7.1'
|
||||
|
||||
here = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
# Import the README and use it as the long-description.
|
||||
# Note: this will only work if 'README.md' is present in your MANIFEST.in file!
|
||||
try:
|
||||
with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
|
||||
long_description = '\n' + f.read()
|
||||
except FileNotFoundError:
|
||||
long_description = DESCRIPTION
|
||||
setup_dir = Path(__file__).resolve().parent
|
||||
version = re.search(
|
||||
r"__version__ = '(.*)'",
|
||||
Path(setup_dir, 'eac_logchecker.py').read_text()
|
||||
)
|
||||
if version is None:
|
||||
raise SystemExit("Could not determine version to use")
|
||||
VERSION = version.group(1)
|
||||
|
||||
|
||||
class UploadCommand(Command):
|
||||
@@ -51,12 +49,14 @@ class UploadCommand(Command):
|
||||
def run(self):
|
||||
try:
|
||||
self.status('Removing previous builds…')
|
||||
rmtree(os.path.join(here, 'dist'))
|
||||
rmtree(Path(setup_dir, 'dist'))
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
self.status('Building Source and Wheel (universal) distribution…')
|
||||
os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable))
|
||||
os.system(
|
||||
'{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)
|
||||
)
|
||||
|
||||
self.status('Uploading the package to PyPI via Twine…')
|
||||
os.system('twine upload dist/*')
|
||||
@@ -64,12 +64,11 @@ class UploadCommand(Command):
|
||||
sys.exit()
|
||||
|
||||
|
||||
# Where the magic happens:
|
||||
setup(
|
||||
name=NAME,
|
||||
version=VERSION,
|
||||
description=DESCRIPTION,
|
||||
long_description=long_description,
|
||||
long_description=Path(setup_dir, 'README.md').read_text(),
|
||||
long_description_content_type='text/markdown',
|
||||
author=AUTHOR,
|
||||
author_email=EMAIL,
|
||||
@@ -81,16 +80,18 @@ setup(
|
||||
'eac_logchecker = eac_logchecker:main'
|
||||
]
|
||||
},
|
||||
install_requires=['pprp'],
|
||||
install_requires=['pprp==0.2.6'],
|
||||
tests_require=['pytest'],
|
||||
license='MIT',
|
||||
classifiers=[
|
||||
'Development Status :: 4 - Beta',
|
||||
'Development Status :: 5 - Production/Stable',
|
||||
'License :: OSI Approved :: MIT License',
|
||||
'Programming Language :: Python',
|
||||
'Programming Language :: Python :: 3',
|
||||
'Programming Language :: Python :: 3.5',
|
||||
'Programming Language :: Python :: 3.6',
|
||||
'Programming Language :: Python :: 3.7'
|
||||
'Programming Language :: Python :: 3.7',
|
||||
'Programming Language :: Python :: 3.8',
|
||||
],
|
||||
# $ setup.py publish support.
|
||||
cmdclass={
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from pathlib import Path
|
||||
import unittest
|
||||
|
||||
import eac_logchecker
|
||||
|
||||
TESTS = [
|
||||
(Path('logs/01.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}, {'message': 'Log entry is fine!', 'status': 'OK'}]),
|
||||
(Path('logs/02.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}]),
|
||||
(Path('logs/03.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/04.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}, {'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/05.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}, {'message': 'Log entry is fine!', 'status': 'OK'}]),
|
||||
(Path('logs/06.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/07.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/08.log'), [{'message': 'Log entry was modified, checksum incorrect!', 'status': 'BAD'}]),
|
||||
(Path('logs/09.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/10.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/11.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/12.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}]),
|
||||
(Path('logs/13.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}]),
|
||||
(Path('logs/14.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/15.log'), [{'message': 'Log entry was modified, checksum incorrect!', 'status': 'BAD'}]),
|
||||
(Path('logs/16.log'), [{'message': 'Log entry was modified, checksum incorrect!', 'status': 'BAD'}]),
|
||||
(Path('logs/17.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/18.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}]),
|
||||
(Path('logs/19.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/20.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/21.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/22.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/23.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/24.log'), [{'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/25.log'), [{'message': 'Log entry is fine!', 'status': 'OK'}, {'message': 'Log entry has no checksum!', 'status': 'NO'}]),
|
||||
(Path('logs/26.log'), [{'message': 'Log entry was modified, checksum incorrect!', 'status': 'BAD'}])
|
||||
]
|
||||
|
||||
class TestLogchecker(unittest.TestCase):
|
||||
def test_logs(self):
|
||||
for log_file, expected in TESTS:
|
||||
with self.subTest(log=str(log_file)):
|
||||
actual = eac_logchecker.check_checksum(log_file, True)
|
||||
self.assertEqual(expected, actual)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
from pathlib import Path
|
||||
import pytest
|
||||
|
||||
import eac_logchecker
|
||||
|
||||
LOG_GOOD = {'message': 'Log entry is fine!', 'status': 'OK'}
|
||||
LOG_NO = {'message': 'Log entry has no checksum!', 'status': 'NO'}
|
||||
LOG_BAD = {
|
||||
'message': 'Log entry was modified, checksum incorrect!',
|
||||
'status': 'BAD'
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize("log_path, log_statuses", [
|
||||
(Path('logs/01.log'), [LOG_GOOD, LOG_GOOD]),
|
||||
(Path('logs/02.log'), [LOG_GOOD]),
|
||||
(Path('logs/03.log'), [LOG_NO]),
|
||||
(Path('logs/04.log'), [LOG_GOOD, LOG_NO]),
|
||||
(Path('logs/05.log'), [LOG_GOOD, LOG_GOOD]),
|
||||
(Path('logs/06.log'), [LOG_NO]),
|
||||
(Path('logs/07.log'), [LOG_NO]),
|
||||
(Path('logs/08.log'), [LOG_BAD]),
|
||||
(Path('logs/09.log'), [LOG_NO]),
|
||||
(Path('logs/10.log'), [LOG_NO]),
|
||||
(Path('logs/11.log'), [LOG_NO]),
|
||||
(Path('logs/12.log'), [LOG_GOOD]),
|
||||
(Path('logs/13.log'), [LOG_GOOD]),
|
||||
(Path('logs/14.log'), [LOG_NO]),
|
||||
(Path('logs/15.log'), [LOG_BAD]),
|
||||
(Path('logs/16.log'), [LOG_BAD]),
|
||||
(Path('logs/17.log'), [LOG_NO]),
|
||||
(Path('logs/18.log'), [LOG_GOOD]),
|
||||
(Path('logs/19.log'), [LOG_NO]),
|
||||
(Path('logs/20.log'), [LOG_NO]),
|
||||
(Path('logs/21.log'), [LOG_NO]),
|
||||
(Path('logs/22.log'), [LOG_NO]),
|
||||
(Path('logs/23.log'), [LOG_NO]),
|
||||
(Path('logs/24.log'), [LOG_NO]),
|
||||
(Path('logs/25.log'), [LOG_GOOD, LOG_NO]),
|
||||
(Path('logs/26.log'), [LOG_BAD]),
|
||||
(Path('logs/27.log'), [LOG_GOOD, LOG_BAD, LOG_BAD, LOG_BAD])
|
||||
])
|
||||
def test_log(log_path, log_statuses):
|
||||
actual = eac_logchecker.check_checksum(log_path)
|
||||
assert log_statuses == actual
|
||||
Reference in new issue
Block a user