feat: basic support for displaying version history
this is not terribly feature-rich yet, just the basics
This commit is contained in:
parent
6d2eccd0ea
commit
f33448f64a
18 changed files with 1323 additions and 66 deletions
|
|
@ -11,9 +11,10 @@ from pyramid import testing
|
|||
from sqlalchemy import orm
|
||||
|
||||
from wuttjamaican.conf import WuttaConfig
|
||||
from wuttjamaican.testing import DataTestCase
|
||||
from wuttaweb.forms import schema as mod
|
||||
from wuttaweb.forms import widgets
|
||||
from wuttaweb.testing import DataTestCase, WebTestCase
|
||||
from wuttaweb.testing import WebTestCase
|
||||
|
||||
|
||||
class TestWuttaDateTime(TestCase):
|
||||
|
|
|
|||
|
|
@ -576,10 +576,6 @@ class TestDateAlchemyFilter(WebTestCase):
|
|||
|
||||
def setUp(self):
|
||||
self.setup_web()
|
||||
model = self.app.model
|
||||
|
||||
# nb. create table for TheLocalThing
|
||||
model.Base.metadata.create_all(bind=self.session.bind)
|
||||
|
||||
self.sample_data = [
|
||||
{"id": 1, "date": datetime.date(2024, 1, 1)},
|
||||
|
|
|
|||
222
tests/test_diffs.py
Normal file
222
tests/test_diffs.py
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
|
||||
from wuttaweb import diffs as mod
|
||||
from wuttaweb.testing import WebTestCase, VersionWebTestCase
|
||||
|
||||
|
||||
# nb. using WebTestCase here only for mako support in render_html()
|
||||
class TestDiff(WebTestCase):
|
||||
|
||||
def make_diff(self, *args, **kwargs):
|
||||
return mod.Diff(*args, **kwargs)
|
||||
|
||||
def test_constructor(self):
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "baz"}
|
||||
diff = self.make_diff(old_data, new_data, fields=["foo"])
|
||||
self.assertEqual(diff.fields, ["foo"])
|
||||
|
||||
def test_make_fields(self):
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "bar", "baz": "zer"}
|
||||
# nb. this calls make_fields()
|
||||
diff = self.make_diff(old_data, new_data)
|
||||
# TODO: should the fields be cumulative? or just use new_data?
|
||||
self.assertEqual(diff.fields, ["baz", "foo"])
|
||||
|
||||
def test_values(self):
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "baz"}
|
||||
diff = self.make_diff(old_data, new_data)
|
||||
self.assertEqual(diff.old_value("foo"), "bar")
|
||||
self.assertEqual(diff.new_value("foo"), "baz")
|
||||
|
||||
def test_values_differ(self):
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "baz"}
|
||||
diff = self.make_diff(old_data, new_data)
|
||||
self.assertTrue(diff.values_differ("foo"))
|
||||
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "bar"}
|
||||
diff = self.make_diff(old_data, new_data)
|
||||
self.assertFalse(diff.values_differ("foo"))
|
||||
|
||||
def test_render_values(self):
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "baz"}
|
||||
diff = self.make_diff(old_data, new_data)
|
||||
self.assertEqual(diff.render_old_value("foo"), "'bar'")
|
||||
self.assertEqual(diff.render_new_value("foo"), "'baz'")
|
||||
|
||||
def test_get_old_value_attrs(self):
|
||||
|
||||
# no change
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "bar"}
|
||||
diff = self.make_diff(old_data, new_data, nature="update")
|
||||
self.assertEqual(diff.get_old_value_attrs(False), {})
|
||||
|
||||
# update
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "baz"}
|
||||
diff = self.make_diff(old_data, new_data, nature="update")
|
||||
self.assertEqual(
|
||||
diff.get_old_value_attrs(True),
|
||||
{"style": f"background-color: {diff.old_color};"},
|
||||
)
|
||||
|
||||
# delete
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {}
|
||||
diff = self.make_diff(old_data, new_data, nature="delete")
|
||||
self.assertEqual(
|
||||
diff.get_old_value_attrs(True),
|
||||
{"style": f"background-color: {diff.old_color};"},
|
||||
)
|
||||
|
||||
def test_get_new_value_attrs(self):
|
||||
|
||||
# no change
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "bar"}
|
||||
diff = self.make_diff(old_data, new_data, nature="update")
|
||||
self.assertEqual(diff.get_new_value_attrs(False), {})
|
||||
|
||||
# update
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "baz"}
|
||||
diff = self.make_diff(old_data, new_data, nature="update")
|
||||
self.assertEqual(
|
||||
diff.get_new_value_attrs(True),
|
||||
{"style": f"background-color: {diff.new_color};"},
|
||||
)
|
||||
|
||||
# create
|
||||
old_data = {}
|
||||
new_data = {"foo": "bar"}
|
||||
diff = self.make_diff(old_data, new_data, nature="create")
|
||||
self.assertEqual(
|
||||
diff.get_new_value_attrs(True),
|
||||
{"style": f"background-color: {diff.new_color};"},
|
||||
)
|
||||
|
||||
def test_render_field_row(self):
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "baz"}
|
||||
diff = self.make_diff(old_data, new_data)
|
||||
row = diff.render_field_row("foo")
|
||||
self.assertIn("<tr>", row)
|
||||
self.assertIn("'bar'", row)
|
||||
self.assertIn(f'style="background-color: {diff.old_color};"', row)
|
||||
self.assertIn("'baz'", row)
|
||||
self.assertIn(f'style="background-color: {diff.new_color};"', row)
|
||||
self.assertIn("</tr>", row)
|
||||
|
||||
def test_render_html(self):
|
||||
old_data = {"foo": "bar"}
|
||||
new_data = {"foo": "baz"}
|
||||
diff = self.make_diff(old_data, new_data)
|
||||
html = diff.render_html()
|
||||
self.assertIn("<table", html)
|
||||
self.assertIn("<tr>", html)
|
||||
self.assertIn("'bar'", html)
|
||||
self.assertIn(f'style="background-color: {diff.old_color};"', html)
|
||||
self.assertIn("'baz'", html)
|
||||
self.assertIn(f'style="background-color: {diff.new_color};"', html)
|
||||
self.assertIn("</tr>", html)
|
||||
self.assertIn("</table>", html)
|
||||
|
||||
|
||||
class TestVersionDiff(VersionWebTestCase):
|
||||
|
||||
def make_diff(self, *args, **kwargs):
|
||||
return mod.VersionDiff(*args, **kwargs)
|
||||
|
||||
def test_constructor(self):
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
model = self.app.model
|
||||
user = model.User(username="fred")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
user.username = "freddie"
|
||||
self.session.commit()
|
||||
self.session.delete(user)
|
||||
self.session.commit()
|
||||
|
||||
txncls = continuum.transaction_class(model.User)
|
||||
vercls = continuum.version_class(model.User)
|
||||
versions = self.session.query(vercls).order_by(vercls.transaction_id).all()
|
||||
self.assertEqual(len(versions), 3)
|
||||
|
||||
version = versions[0]
|
||||
diff = self.make_diff(version)
|
||||
self.assertEqual(diff.nature, "create")
|
||||
self.assertEqual(
|
||||
diff.fields,
|
||||
["active", "password", "person_uuid", "prevent_edit", "username", "uuid"],
|
||||
)
|
||||
|
||||
version = versions[1]
|
||||
diff = self.make_diff(version)
|
||||
self.assertEqual(diff.nature, "update")
|
||||
self.assertEqual(
|
||||
diff.fields,
|
||||
["active", "password", "person_uuid", "prevent_edit", "username", "uuid"],
|
||||
)
|
||||
|
||||
version = versions[2]
|
||||
diff = self.make_diff(version)
|
||||
self.assertEqual(diff.nature, "delete")
|
||||
self.assertEqual(
|
||||
diff.fields,
|
||||
["active", "password", "person_uuid", "prevent_edit", "username", "uuid"],
|
||||
)
|
||||
|
||||
def test_render_values(self):
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
model = self.app.model
|
||||
user = model.User(username="fred")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
user.username = "freddie"
|
||||
self.session.commit()
|
||||
self.session.delete(user)
|
||||
self.session.commit()
|
||||
|
||||
txncls = continuum.transaction_class(model.User)
|
||||
vercls = continuum.version_class(model.User)
|
||||
versions = self.session.query(vercls).order_by(vercls.transaction_id).all()
|
||||
self.assertEqual(len(versions), 3)
|
||||
|
||||
version = versions[0]
|
||||
diff = self.make_diff(version)
|
||||
self.assertEqual(diff.nature, "create")
|
||||
self.assertEqual(diff.render_old_value("username"), "")
|
||||
self.assertEqual(
|
||||
diff.render_new_value("username"),
|
||||
'<span style="font-family: monospace;">'fred'</span>',
|
||||
)
|
||||
|
||||
version = versions[1]
|
||||
diff = self.make_diff(version)
|
||||
self.assertEqual(diff.nature, "update")
|
||||
self.assertEqual(
|
||||
diff.render_old_value("username"),
|
||||
'<span style="font-family: monospace;">'fred'</span>',
|
||||
)
|
||||
self.assertEqual(
|
||||
diff.render_new_value("username"),
|
||||
'<span style="font-family: monospace;">'freddie'</span>',
|
||||
)
|
||||
|
||||
version = versions[2]
|
||||
diff = self.make_diff(version)
|
||||
self.assertEqual(diff.nature, "delete")
|
||||
self.assertEqual(
|
||||
diff.render_old_value("username"),
|
||||
'<span style="font-family: monospace;">'freddie'</span>',
|
||||
)
|
||||
self.assertEqual(diff.render_new_value("username"), "")
|
||||
|
|
@ -1,43 +1,15 @@
|
|||
# -*- coding: utf-8; -*-
|
||||
|
||||
from wuttjamaican.conf import WuttaConfig
|
||||
from wuttjamaican.testing import FileConfigTestCase
|
||||
from wuttaweb.menus import MenuHandler
|
||||
|
||||
|
||||
class DataTestCase(FileConfigTestCase):
|
||||
"""
|
||||
Base class for test suites requiring a full (typical) database.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
self.setup_db()
|
||||
|
||||
def setup_db(self):
|
||||
self.setup_files()
|
||||
self.config = WuttaConfig(
|
||||
defaults={
|
||||
"wutta.db.default.url": "sqlite://",
|
||||
}
|
||||
)
|
||||
self.app = self.config.get_app()
|
||||
|
||||
# init db
|
||||
model = self.app.model
|
||||
model.Base.metadata.create_all(bind=self.config.appdb_engine)
|
||||
self.session = self.app.make_session()
|
||||
|
||||
def tearDown(self):
|
||||
self.teardown_db()
|
||||
|
||||
def teardown_db(self):
|
||||
self.teardown_files()
|
||||
|
||||
|
||||
class NullMenuHandler(MenuHandler):
|
||||
"""
|
||||
Dummy menu handler for testing.
|
||||
Dummy :term:`menu handler` for testing.
|
||||
"""
|
||||
|
||||
def make_menus(self, request, **kwargs):
|
||||
"""
|
||||
This always returns an empty menu set.
|
||||
"""
|
||||
return []
|
||||
|
|
|
|||
|
|
@ -31,12 +31,6 @@ class MockBatchHandler(BatchHandler):
|
|||
|
||||
class TestBatchMasterView(WebTestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.setup_web()
|
||||
|
||||
# nb. create MockBatch, MockBatchRow
|
||||
model.Base.metadata.create_all(bind=self.session.bind)
|
||||
|
||||
def make_handler(self):
|
||||
return MockBatchHandler(self.config)
|
||||
|
||||
|
|
@ -51,7 +45,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
self.assertEqual(view.batch_handler, 42)
|
||||
|
||||
def test_get_fallback_templates(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
|
|
@ -67,7 +61,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
|
||||
def test_render_to_response(self):
|
||||
model = self.app.model
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
|
|
@ -87,7 +81,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
self.assertIs(context["batch_handler"], handler)
|
||||
|
||||
def test_configure_grid(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.multiple(mod.BatchMasterView, create=True, model_class=MockBatch):
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
|
|
@ -98,7 +92,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
view.configure_grid(grid)
|
||||
|
||||
def test_render_batch_id(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
|
|
@ -112,7 +106,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
self.assertIsNone(result)
|
||||
|
||||
def test_get_instance_title(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
|
|
@ -127,7 +121,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
self.assertEqual(result, "00000043 runnin some numbers")
|
||||
|
||||
def test_configure_form(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.multiple(mod.BatchMasterView, create=True, model_class=MockBatch):
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
|
|
@ -163,7 +157,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
view.configure_form(form)
|
||||
|
||||
def test_objectify(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.multiple(mod.BatchMasterView, create=True, model_class=MockBatch):
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
|
|
@ -194,7 +188,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
|
||||
def test_redirect_after_create(self):
|
||||
self.pyramid_config.add_route("mock_batches.view", "/batch/mock/{uuid}")
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
|
|
@ -247,7 +241,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
|
||||
def test_populate_thread(self):
|
||||
model = self.app.model
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
|
|
@ -315,7 +309,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
def test_execute(self):
|
||||
self.pyramid_config.add_route("mock_batches.view", "/batch/mock/{uuid}")
|
||||
model = self.app.model
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
|
||||
user = model.User(username="barney")
|
||||
self.session.add(user)
|
||||
|
|
@ -345,7 +339,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
self.assertTrue(self.request.session.peek_flash("error"))
|
||||
|
||||
def test_get_row_model_class(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
with patch.object(
|
||||
mod.BatchMasterView, "get_batch_handler", return_value=handler
|
||||
):
|
||||
|
|
@ -370,7 +364,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
self.assertIs(cls, MockBatchRow)
|
||||
|
||||
def test_get_row_grid_data(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
model = self.app.model
|
||||
|
||||
user = model.User(username="barney")
|
||||
|
|
@ -401,7 +395,7 @@ class TestBatchMasterView(WebTestCase):
|
|||
self.assertEqual(data.count(), 1)
|
||||
|
||||
def test_configure_row_grid(self):
|
||||
handler = MockBatchHandler(self.config)
|
||||
handler = self.make_handler()
|
||||
model = self.app.model
|
||||
|
||||
user = model.User(username="barney")
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ from wuttaweb.views import master as mod
|
|||
from wuttaweb.views import View
|
||||
from wuttaweb.progress import SessionProgress
|
||||
from wuttaweb.subscribers import new_request_set_user
|
||||
from wuttaweb.testing import WebTestCase
|
||||
from wuttaweb.testing import WebTestCase, VersionWebTestCase
|
||||
from wuttaweb.grids import Grid
|
||||
|
||||
|
||||
class TestMasterView(WebTestCase):
|
||||
|
|
@ -1841,3 +1842,247 @@ class TestMasterView(WebTestCase):
|
|||
# class may specify
|
||||
with patch.object(view, "rows_title", create=True, new="Mock Rows"):
|
||||
self.assertEqual(view.get_rows_title(), "Mock Rows")
|
||||
|
||||
|
||||
class TestVersionedMasterView(VersionWebTestCase):
|
||||
|
||||
def make_view(self):
|
||||
return mod.MasterView(self.request)
|
||||
|
||||
def test_defaults(self):
|
||||
model = self.app.model
|
||||
|
||||
with patch.multiple(mod.MasterView, model_class=model.User, has_versions=True):
|
||||
mod.MasterView.defaults(self.pyramid_config)
|
||||
|
||||
def test_get_model_version_class(self):
|
||||
model = self.app.model
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
view = self.make_view()
|
||||
vercls = view.get_model_version_class()
|
||||
self.assertEqual(vercls.__name__, "UserVersion")
|
||||
|
||||
def test_should_expose_versions(self):
|
||||
model = self.app.model
|
||||
with patch.multiple(mod.MasterView, model_class=model.User, has_versions=True):
|
||||
|
||||
# fully enabled for root user
|
||||
with patch.object(self.request, "is_root", new=True):
|
||||
view = self.make_view()
|
||||
self.assertTrue(view.should_expose_versions())
|
||||
|
||||
# but not if user has no access
|
||||
view = self.make_view()
|
||||
self.assertFalse(view.should_expose_versions())
|
||||
|
||||
# again, works for root user
|
||||
with patch.object(self.request, "is_root", new=True):
|
||||
view = self.make_view()
|
||||
self.assertTrue(view.should_expose_versions())
|
||||
|
||||
# but not if config disables versioning
|
||||
with patch.object(view.app, "continuum_is_enabled", return_value=False):
|
||||
self.assertFalse(view.should_expose_versions())
|
||||
|
||||
def test_get_version_grid_key(self):
|
||||
model = self.app.model
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
|
||||
# default
|
||||
view = self.make_view()
|
||||
self.assertEqual(view.get_version_grid_key(), "users.history")
|
||||
|
||||
# custom
|
||||
with patch.object(
|
||||
mod.MasterView,
|
||||
"version_grid_key",
|
||||
new="users_custom_history",
|
||||
create=True,
|
||||
):
|
||||
view = self.make_view()
|
||||
self.assertEqual(view.get_version_grid_key(), "users_custom_history")
|
||||
|
||||
def test_get_version_grid_columns(self):
|
||||
model = self.app.model
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
|
||||
# default
|
||||
view = self.make_view()
|
||||
self.assertEqual(
|
||||
view.get_version_grid_columns(),
|
||||
["id", "issued_at", "user", "remote_addr"],
|
||||
)
|
||||
|
||||
# custom
|
||||
with patch.object(
|
||||
mod.MasterView,
|
||||
"version_grid_columns",
|
||||
new=["issued_at", "user"],
|
||||
create=True,
|
||||
):
|
||||
view = self.make_view()
|
||||
self.assertEqual(view.get_version_grid_columns(), ["issued_at", "user"])
|
||||
|
||||
def test_get_version_grid_data(self):
|
||||
model = self.app.model
|
||||
|
||||
user = model.User(username="fred")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
user.username = "freddie"
|
||||
self.session.commit()
|
||||
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
view = self.make_view()
|
||||
query = view.get_version_grid_data(user)
|
||||
self.assertIsInstance(query, orm.Query)
|
||||
transactions = query.all()
|
||||
self.assertEqual(len(transactions), 2)
|
||||
|
||||
def test_configure_version_grid(self):
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
model = self.app.model
|
||||
txncls = continuum.transaction_class(model.User)
|
||||
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
view = self.make_view()
|
||||
|
||||
# this is mostly just for coverage, but we at least can
|
||||
# confirm something does change
|
||||
grid = view.make_grid(model_class=txncls)
|
||||
self.assertNotIn("issued_at", grid.linked_columns)
|
||||
view.configure_version_grid(grid)
|
||||
self.assertIn("issued_at", grid.linked_columns)
|
||||
|
||||
def test_make_version_grid(self):
|
||||
model = self.app.model
|
||||
|
||||
user = model.User(username="fred")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
user.username = "freddie"
|
||||
self.session.commit()
|
||||
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
with patch.object(mod.MasterView, "Session", return_value=self.session):
|
||||
with patch.dict(self.request.matchdict, uuid=user.uuid):
|
||||
view = self.make_view()
|
||||
grid = view.make_version_grid()
|
||||
self.assertIsInstance(grid, Grid)
|
||||
self.assertIsInstance(grid.data, orm.Query)
|
||||
self.assertEqual(len(grid.data.all()), 2)
|
||||
|
||||
def test_view_versions(self):
|
||||
self.pyramid_config.add_route("home", "/")
|
||||
self.pyramid_config.add_route("login", "/auth/login")
|
||||
self.pyramid_config.add_route("users", "/users/")
|
||||
self.pyramid_config.add_route("users.view", "/users/{uuid}")
|
||||
self.pyramid_config.add_route("users.version", "/users/{uuid}/versions/{txnid}")
|
||||
model = self.app.model
|
||||
|
||||
user = model.User(username="fred")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
user.username = "freddie"
|
||||
self.session.commit()
|
||||
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
with patch.object(mod.MasterView, "Session", return_value=self.session):
|
||||
with patch.dict(self.request.matchdict, uuid=user.uuid):
|
||||
view = self.make_view()
|
||||
|
||||
# normal, full page
|
||||
response = view.view_versions()
|
||||
self.assertEqual(response.content_type, "text/html")
|
||||
self.assertIn("<b-table", response.text)
|
||||
|
||||
# partial page
|
||||
with patch.dict(self.request.params, partial="1"):
|
||||
response = view.view_versions()
|
||||
self.assertEqual(response.content_type, "application/json")
|
||||
self.assertIn("data", response.json)
|
||||
self.assertEqual(len(response.json["data"]), 2)
|
||||
|
||||
def test_get_relevant_versions(self):
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
model = self.app.model
|
||||
txncls = continuum.transaction_class(model.User)
|
||||
vercls = continuum.version_class(model.User)
|
||||
|
||||
user = model.User(username="fred")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
|
||||
txn = (
|
||||
self.session.query(txncls)
|
||||
.join(vercls, vercls.transaction_id == txncls.id)
|
||||
.order_by(txncls.id)
|
||||
.first()
|
||||
)
|
||||
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
with patch.object(mod.MasterView, "Session", return_value=self.session):
|
||||
view = self.make_view()
|
||||
versions = view.get_relevant_versions(txn, user)
|
||||
self.assertEqual(len(versions), 1)
|
||||
version = versions[0]
|
||||
self.assertIsInstance(version, vercls)
|
||||
|
||||
def test_view_version(self):
|
||||
import sqlalchemy_continuum as continuum
|
||||
|
||||
self.pyramid_config.add_route("home", "/")
|
||||
self.pyramid_config.add_route("login", "/auth/login")
|
||||
self.pyramid_config.add_route("users", "/users/")
|
||||
self.pyramid_config.add_route("users.view", "/users/{uuid}")
|
||||
self.pyramid_config.add_route("users.versions", "/users/{uuid}/versions/")
|
||||
self.pyramid_config.add_route("users.version", "/users/{uuid}/versions/{txnid}")
|
||||
model = self.app.model
|
||||
txncls = continuum.transaction_class(model.User)
|
||||
vercls = continuum.version_class(model.User)
|
||||
|
||||
user = model.User(username="fred")
|
||||
self.session.add(user)
|
||||
self.session.commit()
|
||||
user.username = "freddie"
|
||||
self.session.commit()
|
||||
|
||||
transactions = (
|
||||
self.session.query(txncls)
|
||||
.join(vercls, vercls.transaction_id == txncls.id)
|
||||
.order_by(txncls.id)
|
||||
.all()
|
||||
)
|
||||
self.assertEqual(len(transactions), 2)
|
||||
|
||||
with patch.object(mod.MasterView, "model_class", new=model.User):
|
||||
with patch.object(mod.MasterView, "Session", return_value=self.session):
|
||||
|
||||
# invalid txnid
|
||||
with patch.dict(self.request.matchdict, uuid=user.uuid, txnid=999999):
|
||||
view = self.make_view()
|
||||
self.assertRaises(HTTPNotFound, view.view_version)
|
||||
|
||||
# first txn
|
||||
first = transactions[0]
|
||||
with patch.dict(self.request.matchdict, uuid=user.uuid, txnid=first.id):
|
||||
view = self.make_view()
|
||||
response = view.view_version()
|
||||
self.assertIn(
|
||||
'<table class="table is-fullwidth is-bordered is-narrow">',
|
||||
response.text,
|
||||
)
|
||||
|
||||
# second txn
|
||||
second = transactions[1]
|
||||
with patch.dict(
|
||||
self.request.matchdict, uuid=user.uuid, txnid=second.id
|
||||
):
|
||||
view = self.make_view()
|
||||
response = view.view_version()
|
||||
self.assertIn(
|
||||
'<table class="table is-fullwidth is-bordered is-narrow">',
|
||||
response.text,
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue