Skip to content
This repository was archived by the owner on Apr 26, 2024. It is now read-only.

Commit 1ead1ca

Browse files
committed
Implement create_appservice_txn with tests.
1 parent 1c2dcf7 commit 1ead1ca

File tree

2 files changed

+109
-4
lines changed

2 files changed

+109
-4
lines changed

synapse/storage/appservice.py

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
import simplejson as json
1818
from twisted.internet import defer
1919

20+
from syutil.jsonutil import encode_canonical_json
2021
from synapse.api.constants import Membership
2122
from synapse.api.errors import StoreError
22-
from synapse.appservice import ApplicationService, ApplicationServiceState
23+
from synapse.appservice import ApplicationService, AppServiceTransaction
2324
from synapse.storage.roommember import RoomsForUser
2425
from ._base import SQLBaseStore
2526

@@ -417,9 +418,46 @@ def create_appservice_txn(self, service, events):
417418
Returns:
418419
AppServiceTransaction: A new transaction.
419420
"""
420-
# TODO: work out txn id (highest txn id for this service += 1)
421-
# TODO: Within same db transaction, Insert new txn into txn table
422-
pass
421+
return self.runInteraction(
422+
"create_appservice_txn",
423+
self._create_appservice_txn,
424+
service, events
425+
)
426+
427+
def _create_appservice_txn(self, txn, service, events):
428+
# work out new txn id (highest txn id for this service += 1)
429+
# The highest id may be the last one sent (in which case it is last_txn)
430+
# or it may be the highest in the txns list (which are waiting to be/are
431+
# being sent)
432+
result = txn.execute(
433+
"SELECT last_txn FROM application_services_state WHERE as_id=?",
434+
(service.id,)
435+
)
436+
last_txn_id = result.fetchone()
437+
if last_txn_id is None: # no row exists
438+
last_txn_id = 0
439+
else:
440+
last_txn_id = int(last_txn_id[0]) # select 'last_txn' col
441+
442+
result = txn.execute(
443+
"SELECT MAX(txn_id) FROM application_services_txns WHERE as_id=?",
444+
(service.id,)
445+
)
446+
highest_txn_id = result.fetchone()[0]
447+
if highest_txn_id is None:
448+
highest_txn_id = 0
449+
450+
new_txn_id = max(highest_txn_id, last_txn_id) + 1
451+
452+
# Insert new txn into txn table
453+
txn.execute(
454+
"INSERT INTO application_services_txns(as_id, txn_id, content) "
455+
"VALUES(?,?,?)",
456+
(service.id, new_txn_id, encode_canonical_json(events))
457+
)
458+
return AppServiceTransaction(
459+
service=service, id=new_txn_id, events=events
460+
)
423461

424462
def complete_appservice_txn(self, txn_id, service):
425463
"""Completes an application service transaction.

tests/storage/test_appservice.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
ApplicationServiceStore, ApplicationServiceTransactionStore
2222
)
2323

24+
import json
2425
from mock import Mock
2526
from tests.utils import SQLiteMemoryDbPool, MockClock
2627

@@ -166,6 +167,20 @@ def _set_state(self, id, state, txn=None):
166167
(id, state, txn)
167168
)
168169

170+
def _insert_txn(self, as_id, txn_id, content):
171+
return self.db_pool.runQuery(
172+
"INSERT INTO application_services_txns(as_id, txn_id, content) "
173+
"VALUES(?,?,?)",
174+
(as_id, txn_id, json.dumps(content))
175+
)
176+
177+
def _set_last_txn(self, as_id, txn_id):
178+
return self.db_pool.runQuery(
179+
"INSERT INTO application_services_state(as_id, last_txn, state) "
180+
"VALUES(?,?,?)",
181+
(as_id, txn_id, ApplicationServiceState.UP)
182+
)
183+
169184
@defer.inlineCallbacks
170185
def test_get_appservice_state_none(self):
171186
service = Mock(id=999)
@@ -237,6 +252,58 @@ def test_set_appservices_state_multiple_up(self):
237252
)
238253
self.assertEquals(service.id, rows[0][0])
239254

255+
@defer.inlineCallbacks
256+
def test_create_appservice_txn_first(self):
257+
service = Mock(id=self.as_list[0]["id"])
258+
events = [{"type": "nothing"}, {"type": "here"}]
259+
txn = yield self.store.create_appservice_txn(service, events)
260+
self.assertEquals(txn.id, 1)
261+
self.assertEquals(txn.events, events)
262+
self.assertEquals(txn.service, service)
263+
264+
@defer.inlineCallbacks
265+
def test_create_appservice_txn_older_last_txn(self):
266+
service = Mock(id=self.as_list[0]["id"])
267+
events = [{"type": "nothing"}, {"type": "here"}]
268+
yield self._set_last_txn(service.id, 9643) # AS is falling behind
269+
yield self._insert_txn(service.id, 9644, events)
270+
yield self._insert_txn(service.id, 9645, events)
271+
txn = yield self.store.create_appservice_txn(service, events)
272+
self.assertEquals(txn.id, 9646)
273+
self.assertEquals(txn.events, events)
274+
self.assertEquals(txn.service, service)
275+
276+
@defer.inlineCallbacks
277+
def test_create_appservice_txn_up_to_date_last_txn(self):
278+
service = Mock(id=self.as_list[0]["id"])
279+
events = [{"type": "nothing"}, {"type": "here"}]
280+
yield self._set_last_txn(service.id, 9643)
281+
txn = yield self.store.create_appservice_txn(service, events)
282+
self.assertEquals(txn.id, 9644)
283+
self.assertEquals(txn.events, events)
284+
self.assertEquals(txn.service, service)
285+
286+
@defer.inlineCallbacks
287+
def test_create_appservice_txn_up_fuzzing(self):
288+
service = Mock(id=self.as_list[0]["id"])
289+
events = [{"type": "nothing"}, {"type": "here"}]
290+
yield self._set_last_txn(service.id, 9643)
291+
292+
# dump in rows with higher IDs to make sure the queries aren't wrong.
293+
yield self._set_last_txn(self.as_list[1]["id"], 119643)
294+
yield self._set_last_txn(self.as_list[2]["id"], 9)
295+
yield self._set_last_txn(self.as_list[3]["id"], 9643)
296+
yield self._insert_txn(self.as_list[1]["id"], 119644, events)
297+
yield self._insert_txn(self.as_list[1]["id"], 119645, events)
298+
yield self._insert_txn(self.as_list[1]["id"], 119646, events)
299+
yield self._insert_txn(self.as_list[2]["id"], 10, events)
300+
yield self._insert_txn(self.as_list[3]["id"], 9643, events)
301+
302+
txn = yield self.store.create_appservice_txn(service, events)
303+
self.assertEquals(txn.id, 9644)
304+
self.assertEquals(txn.events, events)
305+
self.assertEquals(txn.service, service)
306+
240307
@defer.inlineCallbacks
241308
def test_get_appservices_by_state_single(self):
242309
yield self._set_state(

0 commit comments

Comments
 (0)