From f8d197a8bac454151d0c457efa72fc98ae959118 Mon Sep 17 00:00:00 2001 From: Chenxiong Qi Date: Jan 04 2018 02:48:10 +0000 Subject: Avoid adding duplicate dependent event Signed-off-by: Chenxiong Qi --- diff --git a/freshmaker/migrations/versions/f3223db11e48_add_unique_index_to_eventdependency.py b/freshmaker/migrations/versions/f3223db11e48_add_unique_index_to_eventdependency.py new file mode 100644 index 0000000..36a40d5 --- /dev/null +++ b/freshmaker/migrations/versions/f3223db11e48_add_unique_index_to_eventdependency.py @@ -0,0 +1,26 @@ +"""Add unique index to EventDependency + +Revision ID: f3223db11e48 +Revises: e06434b3ef5e +Create Date: 2018-01-04 09:45:25.153391 + +""" + +# revision identifiers, used by Alembic. +revision = 'f3223db11e48' +down_revision = 'e06434b3ef5e' + +from alembic import op +import sqlalchemy as sa + + +def upgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.create_index('idx_event_dependency_rel', 'event_dependencies', ['event_id', 'event_dependency_id'], unique=True) + # ### end Alembic commands ### + + +def downgrade(): + # ### commands auto generated by Alembic - please adjust! ### + op.drop_index('idx_event_dependency_rel', table_name='event_dependencies') + # ### end Alembic commands ### diff --git a/freshmaker/models.py b/freshmaker/models.py index 1bf7ac9..27c8232 100644 --- a/freshmaker/models.py +++ b/freshmaker/models.py @@ -235,9 +235,24 @@ class Event(FreshmakerBase): return INVERSE_EVENT_TYPES[self.event_type_id] def add_event_dependency(self, session, event): - dep = EventDependency(event_id=self.id, - event_dependency_id=event.id) - session.add(dep) + """Add a dependent event + + :param session: the `db.session`. + :param event: the dependent event to be added. + :type event: :py:class:`Event` + :return: instance of :py:class:`EventDependency`. Caller is responsible + for committing changes to database. If `event` has been added + already, nothing changed and `None` will be returned. + """ + dep = session.query(EventDependency.id).filter_by( + event_id=self.id, event_dependency_id=event.id).first() + if dep is None: + dep = EventDependency(event_id=self.id, + event_dependency_id=event.id) + session.add(dep) + return dep + else: + return None @property def event_dependencies(self): @@ -356,6 +371,13 @@ class EventDependency(FreshmakerBase): event_dependency_id = db.Column(db.Integer, db.ForeignKey('events.id'), nullable=False) +Index( + 'idx_event_dependency_rel', + EventDependency.event_id, + EventDependency.event_dependency_id, + unique=True) + + class ArtifactBuild(FreshmakerBase): __tablename__ = "artifact_builds" id = db.Column(db.Integer, primary_key=True) diff --git a/tests/test_models.py b/tests/test_models.py index 241cc9d..580b2f6 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -80,19 +80,6 @@ class TestModels(unittest.TestCase): self.assertEqual(build3.get_root_dep_on(), build1) self.assertEqual(build4.get_root_dep_on(), build1) - def test_event_dependencies(self): - event = Event.create(db.session, "test_msg_id", "test", events.TestingEvent) - db.session.commit() - self.assertEqual(event.event_dependencies, []) - - event1 = Event.create(db.session, "test_msg_id2", "test2", events.TestingEvent) - db.session.commit() - event.add_event_dependency(db.session, event1) - db.session.commit() - self.assertEqual(event.event_dependencies, [event1]) - self.assertEqual(event.event_dependencies[0].search_key, "test2") - self.assertEqual(event1.event_dependencies, []) - def test_depending_artifact_builds(self): event = Event.create(db.session, "test_msg_id", "test", events.TestingEvent) parent = ArtifactBuild.create(db.session, event, "parent", "module", 1234) @@ -358,3 +345,58 @@ class TestArtifactBuildComposesRel(unittest.TestCase): self.assertEqual( builds, sorted([rel.build.id for rel in compose.builds])) + + +class TestEventDependency(unittest.TestCase): + """Test Event.add_event_dependency""" + + def setUp(self): + db.session.remove() + db.drop_all() + db.create_all() + db.session.commit() + + def tearDown(self): + db.session.remove() + db.drop_all() + db.session.commit() + + def test_event_dependencies(self): + event = Event.create(db.session, "test_msg_id", "test", events.TestingEvent) + db.session.commit() + self.assertEqual(event.event_dependencies, []) + + def test_add_a_dependent_event(self): + event = Event.create(db.session, "test_msg_id", "test", events.TestingEvent) + event1 = Event.create(db.session, "test_msg_id2", "test2", events.TestingEvent) + db.session.commit() + + event.add_event_dependency(db.session, event1) + db.session.commit() + + self.assertEqual(event.event_dependencies, [event1]) + self.assertEqual(event.event_dependencies[0].search_key, "test2") + self.assertEqual(event1.event_dependencies, []) + + def test_add_existing_dependent_event(self): + event = Event.create(db.session, "test_msg_id", "test", events.TestingEvent) + event1 = Event.create(db.session, "test_msg_id2", "test2", events.TestingEvent) + db.session.commit() + event.add_event_dependency(db.session, event1) + db.session.commit() + + rel = event.add_event_dependency(db.session, event1) + + self.assertIsNone(rel) + self.assertEqual(event.event_dependencies, [event1]) + + def test_return_added_dependency_relationship(self): + event = Event.create(db.session, "test_msg_id", "test", events.TestingEvent) + event1 = Event.create(db.session, "test_msg_id2", "test2", events.TestingEvent) + db.session.commit() + + dep_rel = event.add_event_dependency(db.session, event1) + db.session.commit() + + self.assertEqual(event.id, dep_rel.event_id) + self.assertEqual(event1.id, dep_rel.event_dependency_id)