Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion scripts/prepare_program_solutions_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@
from unittest.mock import patch


def stable_json_value(value):
if isinstance(value, (memoryview, bytes, bytearray)):
return {"binary_hex": bytes(value).hex()}
return str(value)


def main():
sys.path.insert(0, os.getcwd())
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "procollab.settings")
Expand Down Expand Up @@ -39,7 +45,9 @@ def main():
manager = get_user_model().objects.get(pk=manager_id, is_active=True)

def digest(value):
return hashlib.sha256(json.dumps(value, sort_keys=True, default=str).encode()).hexdigest()
return hashlib.sha256(
json.dumps(value, sort_keys=True, default=stable_json_value).encode()
).hexdigest()

def rows(model, ids):
return list(model._base_manager.filter(pk__in=ids).order_by("pk").values())
Expand Down
10 changes: 9 additions & 1 deletion scripts/verify_program_solutions_dev.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
"""Приемка API на dev; новые записи всегда откатываются транзакцией."""


def stable_json_value(value):
if isinstance(value, (memoryview, bytes, bytearray)):
return {"binary_hex": bytes(value).hex()}
return str(value)


def main():
import hashlib
import io
Expand Down Expand Up @@ -42,7 +48,9 @@ def main():
checks, wire, programs = [], [], []

def digest(value):
return hashlib.sha256(json.dumps(value, sort_keys=True, default=str).encode()).hexdigest()
return hashlib.sha256(
json.dumps(value, sort_keys=True, default=stable_json_value).encode()
).hexdigest()

models = [
model
Expand Down
36 changes: 36 additions & 0 deletions tests/test_solution_acceptance_retention.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"""Бинарные данные сертификата должны сравниваться по содержимому."""
import hashlib
import json
import runpy
from pathlib import Path
from unittest import TestCase


class AcceptanceRetentionTests(TestCase):
scripts = ("prepare_program_solutions_browser.py", "verify_program_solutions_dev.py")

def functions(self):
root = Path(__file__).resolve().parents[1]
for name in self.scripts:
yield name, runpy.run_path(str(root / "scripts" / name))["stable_json_value"]

def test_independent_binary_values_with_equal_content_have_equal_hashes(self):
payload = bytes(range(256))
for name, encode in self.functions():
with self.subTest(script=name):
variants = [memoryview(payload), memoryview(bytes(payload)), payload, bytearray(payload)]
hashes = {
hashlib.sha256(json.dumps({"content": value}, default=encode).encode()).hexdigest()
for value in variants
}
self.assertEqual(len(hashes), 1)

def test_changed_content_and_false_zero_are_distinguished(self):
for name, encode in self.functions():
with self.subTest(script=name):
values = [memoryview(b"before"), memoryview(b"after"), 0, False, None]
hashes = {
hashlib.sha256(json.dumps({"value": value}, default=encode).encode()).hexdigest()
for value in values
}
self.assertEqual(len(hashes), len(values))
Loading