From c8b2cc38deb49e106720cf3aae77c64749474a0b Mon Sep 17 00:00:00 2001 From: akwizgran <akwizgran@users.sourceforge.net> Date: Tue, 18 Oct 2011 17:32:32 +0100 Subject: [PATCH] Record when the transports and subscriptions visible to each contact were last modified. In future this will be used to determine when to send updates. --- components/net/sf/briar/db/Database.java | 26 +-- .../sf/briar/db/DatabaseComponentImpl.java | 53 ++---- components/net/sf/briar/db/JdbcDatabase.java | 161 +++++++++++++----- .../sf/briar/db/DatabaseComponentTest.java | 97 ++--------- 4 files changed, 172 insertions(+), 165 deletions(-) diff --git a/components/net/sf/briar/db/Database.java b/components/net/sf/briar/db/Database.java index 61f34953a7..7f5e16fcbd 100644 --- a/components/net/sf/briar/db/Database.java +++ b/components/net/sf/briar/db/Database.java @@ -116,12 +116,11 @@ interface Database<T> { boolean addPrivateMessage(T txn, Message m, ContactId c) throws DbException; /** - * Subscribes to the given group and returns true if the subscription did - * not previously exist. + * Subscribes to the given group. * <p> * Locking: subscriptions write. */ - boolean addSubscription(T txn, Group g) throws DbException; + void addSubscription(T txn, Group g) throws DbException; /** * Returns true if the database contains the given contact. @@ -407,14 +406,15 @@ interface Database<T> { void removeMessage(T txn, MessageId m) throws DbException; /** - * Unsubscribes from the given group and returns true if a subscription - * previously existed. Any messages belonging to the group - * are deleted from the database. + * Unsubscribes from the given group and returns the IDs of any contacts + * affected by the change. Any messages belonging to the group are deleted + * from the database. * <p> * Locking: contacts read, messages write, messageStatuses write, * subscriptions write. */ - boolean removeSubscription(T txn, GroupId g) throws DbException; + Collection<ContactId> removeSubscription(T txn, GroupId g) + throws DbException; /** * Sets the configuration for the given transport, replacing any existing @@ -436,11 +436,12 @@ interface Database<T> { /** * Sets the local transport properties for the given transport, replacing - * any existing properties for that transport. + * any existing properties for that transport. Returns true if the + * properties have changed. * <p> * Locking: transports write. */ - void setLocalProperties(T txn, TransportId t, TransportProperties p) + boolean setLocalProperties(T txn, TransportId t, TransportProperties p) throws DbException; /** @@ -517,10 +518,11 @@ interface Database<T> { /** * Makes the given group visible to the given set of contacts and invisible - * to any other contacts. + * to any other contacts. Returns the IDs of any contacts affected by the + * change. * <p> * Locking: contacts read, subscriptions write. */ - void setVisibility(T txn, GroupId g, Collection<ContactId> visible) - throws DbException; + Collection<ContactId> setVisibility(T txn, GroupId g, + Collection<ContactId> visible) throws DbException; } diff --git a/components/net/sf/briar/db/DatabaseComponentImpl.java b/components/net/sf/briar/db/DatabaseComponentImpl.java index 7fdebaa51e..ab0a56ab63 100644 --- a/components/net/sf/briar/db/DatabaseComponentImpl.java +++ b/components/net/sf/briar/db/DatabaseComponentImpl.java @@ -11,7 +11,6 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -1114,16 +1113,11 @@ DatabaseCleaner.Callback { public void setConfig(TransportId t, TransportConfig config) throws DbException { - boolean changed = false; transportLock.writeLock().lock(); try { T txn = db.startTransaction(); try { - TransportConfig old = db.getConfig(txn, t); - if(!config.equals(old)) { - db.setConfig(txn, t, config); - changed = true; - } + db.setConfig(txn, t, config); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -1132,8 +1126,6 @@ DatabaseCleaner.Callback { } finally { transportLock.writeLock().unlock(); } - // Call the listeners outside the lock - if(changed) callListeners(new TransportsUpdatedEvent()); } public void setConnectionWindow(ContactId c, TransportId t, @@ -1160,16 +1152,12 @@ DatabaseCleaner.Callback { public void setLocalProperties(TransportId t, TransportProperties properties) throws DbException { - boolean changed = false; + boolean changed; transportLock.writeLock().lock(); try { T txn = db.startTransaction(); try { - TransportProperties old = db.getLocalTransports(txn).get(t); - if(!properties.equals(old)) { - db.setLocalProperties(txn, t, properties); - changed = true; - } + changed = db.setLocalProperties(txn, t, properties); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -1278,19 +1266,16 @@ DatabaseCleaner.Callback { public void setVisibility(GroupId g, Collection<ContactId> visible) throws DbException { - Collection<ContactId> then, now; + Collection<ContactId> affected; contactLock.readLock().lock(); try { subscriptionLock.writeLock().lock(); try { T txn = db.startTransaction(); try { - // Get the contacts to which the group used to be visible - then = new HashSet<ContactId>(db.getVisibility(txn, g)); // Don't try to make the group visible to ex-contacts - now = new HashSet<ContactId>(visible); - now.retainAll(new HashSet<ContactId>(db.getContacts(txn))); - db.setVisibility(txn, g, now); + visible.retainAll((db.getContacts(txn))); + affected = db.setVisibility(txn, g, visible); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -1302,22 +1287,19 @@ DatabaseCleaner.Callback { } finally { contactLock.readLock().unlock(); } - // Work out which contacts were affected by the change - Collection<ContactId> affected = new ArrayList<ContactId>(); - for(ContactId c : then) if(!now.contains(c)) affected.add(c); - for(ContactId c : now) if(!then.contains(c)) affected.add(c); // Call the listeners outside the lock - callListeners(new SubscriptionsUpdatedEvent(affected)); + if(!affected.isEmpty()) + callListeners(new SubscriptionsUpdatedEvent(affected)); } public void subscribe(Group g) throws DbException { if(LOG.isLoggable(Level.FINE)) LOG.fine("Subscribing to " + g); - boolean added; subscriptionLock.writeLock().lock(); try { T txn = db.startTransaction(); try { - added = db.addSubscription(txn, g); + if(!db.containsSubscription(txn, g.getId())) + db.addSubscription(txn, g); db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -1326,14 +1308,12 @@ DatabaseCleaner.Callback { } finally { subscriptionLock.writeLock().unlock(); } - // Call the listeners outside the lock - if(added) callListeners(new SubscriptionsUpdatedEvent()); } public void unsubscribe(GroupId g) throws DbException { if(LOG.isLoggable(Level.FINE)) LOG.fine("Unsubscribing from " + g); - boolean removed; - Collection<ContactId> affected; + boolean removed = false; + Collection<ContactId> affected = null; contactLock.readLock().lock(); try { messageLock.writeLock().lock(); @@ -1344,8 +1324,10 @@ DatabaseCleaner.Callback { try { T txn = db.startTransaction(); try { - affected = db.getVisibility(txn, g); - removed = db.removeSubscription(txn, g); + if(db.containsSubscription(txn, g)) { + affected = db.removeSubscription(txn, g); + removed = true; + } db.commitTransaction(txn); } catch(DbException e) { db.abortTransaction(txn); @@ -1364,7 +1346,8 @@ DatabaseCleaner.Callback { contactLock.readLock().unlock(); } // Call the listeners outside the lock - if(removed) callListeners(new SubscriptionsUpdatedEvent(affected)); + if(removed && !affected.isEmpty()) + callListeners(new SubscriptionsUpdatedEvent(affected)); } public void checkFreeSpaceAndClean() throws DbException { diff --git a/components/net/sf/briar/db/JdbcDatabase.java b/components/net/sf/briar/db/JdbcDatabase.java index 15a28e3cf9..6bd7cb3e8e 100644 --- a/components/net/sf/briar/db/JdbcDatabase.java +++ b/components/net/sf/briar/db/JdbcDatabase.java @@ -12,7 +12,9 @@ import java.sql.Statement; import java.sql.Types; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.Map; import java.util.Map.Entry; @@ -207,6 +209,7 @@ abstract class JdbcDatabase implements Database<Connection> { + " (contactId INT NOT NULL," + " sent BIGINT NOT NULL," + " received BIGINT NOT NULL," + + " modified BIGINT NOT NULL," + " PRIMARY KEY (contactId)," + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; @@ -216,6 +219,7 @@ abstract class JdbcDatabase implements Database<Connection> { + " (contactId INT NOT NULL," + " sent BIGINT NOT NULL," + " received BIGINT NOT NULL," + + " modified BIGINT NOT NULL," + " PRIMARY KEY (contactId)," + " FOREIGN KEY (contactId) REFERENCES contacts (contactId)" + " ON DELETE CASCADE)"; @@ -507,23 +511,25 @@ abstract class JdbcDatabase implements Database<Connection> { ps.close(); // Initialise the subscription timestamps sql = "INSERT INTO subscriptionTimestamps" - + " (contactId, sent, received)" - + " VALUES (?, ?, ?)"; + + " (contactId, sent, received, modified)" + + " VALUES (?, ?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); ps.setLong(2, 0L); ps.setLong(3, 0L); + ps.setLong(4, 1L); affected = ps.executeUpdate(); if(affected != 1) throw new DbStateException(); ps.close(); // Initialise the transport timestamps sql = "INSERT INTO transportTimestamps" - + " (contactId, sent, received)" - + " VALUES (?, ?, ?)"; + + " (contactId, sent, received, modified)" + + " VALUES (?, ?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); ps.setLong(2, 0L); ps.setLong(3, 0L); + ps.setLong(4, 1L); affected = ps.executeUpdate(); if(affected != 1) throw new DbStateException(); ps.close(); @@ -652,20 +658,10 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public boolean addSubscription(Connection txn, Group g) throws DbException { + public void addSubscription(Connection txn, Group g) throws DbException { PreparedStatement ps = null; - ResultSet rs = null; try { - String sql = "SELECT NULL FROM subscriptions WHERE groupId = ?"; - ps = txn.prepareStatement(sql); - ps.setBytes(1, g.getId().getBytes()); - rs = ps.executeQuery(); - boolean found = rs.next(); - if(rs.next()) throw new DbStateException(); - rs.close(); - ps.close(); - if(found) return false; - sql = "INSERT INTO subscriptions" + String sql = "INSERT INTO subscriptions" + " (groupId, groupName, groupKey, start)" + " VALUES (?, ?, ?, ?)"; ps = txn.prepareStatement(sql); @@ -676,7 +672,6 @@ abstract class JdbcDatabase implements Database<Connection> { int affected = ps.executeUpdate(); if(affected != 1) throw new DbStateException(); ps.close(); - return true; } catch(SQLException e) { tryToClose(ps); throw new DbException(e); @@ -1765,18 +1760,30 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public boolean removeSubscription(Connection txn, GroupId g) + public Collection<ContactId> removeSubscription(Connection txn, GroupId g) throws DbException { PreparedStatement ps = null; + ResultSet rs = null; try { - String sql = "DELETE FROM subscriptions WHERE groupId = ?"; + // Retrieve the contacts to which the subscription is visible + String sql = "SELECT contactId FROM visibilities WHERE groupId = ?"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, g.getBytes()); + rs = ps.executeQuery(); + Collection<ContactId> visible = new ArrayList<ContactId>(); + while(rs.next()) visible.add(new ContactId(rs.getInt(1))); + rs.close(); + ps.close(); + // Delete the subscription + sql = "DELETE FROM subscriptions WHERE groupId = ?"; ps = txn.prepareStatement(sql); ps.setBytes(1, g.getBytes()); int affected = ps.executeUpdate(); - if(affected > 1) throw new DbStateException(); + if(affected != 1) throw new DbStateException(); ps.close(); - return affected > 0; + return visible; } catch(SQLException e) { + tryToClose(rs); tryToClose(ps); throw new DbException(e); } @@ -1784,31 +1791,26 @@ abstract class JdbcDatabase implements Database<Connection> { public void setConfig(Connection txn, TransportId t, TransportConfig config) throws DbException { - setTransportDetails(txn, t, config, "transportConfig"); - } - - private void setTransportDetails(Connection txn, TransportId t, - Map<String, String> details, String table) throws DbException { PreparedStatement ps = null; try { - // Delete any existing details for the given transport - String sql = "DELETE FROM " + table + " WHERE transportId = ?"; + // Delete any existing config for the given transport + String sql = "DELETE FROM transportConfig WHERE transportId = ?"; ps = txn.prepareStatement(sql); ps.setInt(1, t.getInt()); ps.executeUpdate(); ps.close(); - // Store the new details - sql = "INSERT INTO " + table + " (transportId, key, value)" - + " VALUES (?, ?, ?)"; + // Store the new config + sql = "INSERT INTO transportConfig (transportId, key, value)" + + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setInt(1, t.getInt()); - for(Entry<String, String> e : details.entrySet()) { + for(Entry<String, String> e : config.entrySet()) { ps.setString(2, e.getKey()); ps.setString(3, e.getValue()); ps.addBatch(); } int[] batchAffected = ps.executeBatch(); - if(batchAffected.length != details.size()) + if(batchAffected.length != config.size()) throw new DbStateException(); for(int i = 0; i < batchAffected.length; i++) { if(batchAffected[i] != 1) throw new DbStateException(); @@ -1868,9 +1870,58 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void setLocalProperties(Connection txn, TransportId t, + public boolean setLocalProperties(Connection txn, TransportId t, TransportProperties properties) throws DbException { - setTransportDetails(txn, t, properties, "transports"); + PreparedStatement ps = null; + ResultSet rs = null; + try { + // Retrieve any existing properties for the given transport + String sql = "SELECT key, value FROM transports" + + " WHERE transportId = ?"; + ps = txn.prepareStatement(sql); + ps.setInt(1, t.getInt()); + rs = ps.executeQuery(); + TransportProperties old = new TransportProperties(); + while(rs.next()) old.put(rs.getString(1), rs.getString(2)); + rs.close(); + ps.close(); + // If the properties haven't changed, return + if(old.equals(properties)) return false; + // Delete any existing properties for the given transport + sql = "DELETE FROM transports WHERE transportId = ?"; + ps = txn.prepareStatement(sql); + ps.setInt(1, t.getInt()); + ps.executeUpdate(); + ps.close(); + // Store the new properties + sql = "INSERT INTO transports (transportId, key, value)" + + " VALUES (?, ?, ?)"; + ps = txn.prepareStatement(sql); + ps.setInt(1, t.getInt()); + for(Entry<String, String> e : properties.entrySet()) { + ps.setString(2, e.getKey()); + ps.setString(3, e.getValue()); + ps.addBatch(); + } + int[] batchAffected = ps.executeBatch(); + if(batchAffected.length != properties.size()) + throw new DbStateException(); + for(int i = 0; i < batchAffected.length; i++) { + if(batchAffected[i] != 1) throw new DbStateException(); + } + ps.close(); + // Update the transport timestamps of all contacts + sql = "UPDATE transportTimestamps set modified = ?"; + ps = txn.prepareStatement(sql); + ps.setLong(1, System.currentTimeMillis()); + ps.executeUpdate(); + ps.close(); + return true; + } catch(SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } } public Rating setRating(Connection txn, AuthorId a, Rating r) @@ -2179,17 +2230,29 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public void setVisibility(Connection txn, GroupId g, + public Collection<ContactId> setVisibility(Connection txn, GroupId g, Collection<ContactId> visible) throws DbException { PreparedStatement ps = null; + ResultSet rs = null; try { + // Retrieve any existing visibilities + String sql = "SELECT contactId FROM visibilities WHERE groupId = ?"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, g.getBytes()); + rs = ps.executeQuery(); + Collection<ContactId> then = new HashSet<ContactId>(); + while(rs.next()) then.add(new ContactId(rs.getInt(1))); + rs.close(); + ps.close(); + // If the visibilities haven't changed, return + Collection<ContactId> now = new HashSet<ContactId>(visible); + if(then.equals(now)) return Collections.emptyList(); // Delete any existing visibilities - String sql = "DELETE FROM visibilities WHERE groupId = ?"; + sql = "DELETE FROM visibilities where groupId = ?"; ps = txn.prepareStatement(sql); ps.setBytes(1, g.getBytes()); ps.executeUpdate(); ps.close(); - if(visible.isEmpty()) return; // Store the new visibilities sql = "INSERT INTO visibilities (groupId, contactId)" + " VALUES (?, ?)"; @@ -2205,7 +2268,29 @@ abstract class JdbcDatabase implements Database<Connection> { for(int i = 0; i < batchAffected.length; i++) { if(batchAffected[i] != 1) throw new DbStateException(); } + ps.close(); + // Update the subscription timestamps of any affected contacts + Collection<ContactId> affected = new ArrayList<ContactId>(); + for(ContactId c : then) if(!now.contains(c)) affected.add(c); + for(ContactId c : now) if(!then.contains(c)) affected.add(c); + sql = "UPDATE subscriptionTimestamps SET modified = ?" + + " WHERE contactId = ?"; + ps = txn.prepareStatement(sql); + ps.setLong(1, System.currentTimeMillis()); + for(ContactId c : affected) { + ps.setInt(2, c.getInt()); + ps.addBatch(); + } + batchAffected = ps.executeBatch(); + if(batchAffected.length != affected.size()) + throw new DbStateException(); + for(int i = 0; i < batchAffected.length; i++) { + if(batchAffected[i] > 1) throw new DbStateException(); + } + ps.close(); + return affected; } catch(SQLException e) { + tryToClose(rs); tryToClose(ps); throw new DbException(e); } diff --git a/test/net/sf/briar/db/DatabaseComponentTest.java b/test/net/sf/briar/db/DatabaseComponentTest.java index 15b1b74014..bb8cfa73ac 100644 --- a/test/net/sf/briar/db/DatabaseComponentTest.java +++ b/test/net/sf/briar/db/DatabaseComponentTest.java @@ -10,7 +10,6 @@ import junit.framework.TestCase; import net.sf.briar.TestUtils; import net.sf.briar.api.ContactId; import net.sf.briar.api.Rating; -import net.sf.briar.api.TransportConfig; import net.sf.briar.api.TransportId; import net.sf.briar.api.TransportProperties; import net.sf.briar.api.db.DatabaseComponent; @@ -20,7 +19,6 @@ import net.sf.briar.api.db.event.ContactAddedEvent; import net.sf.briar.api.db.event.ContactRemovedEvent; import net.sf.briar.api.db.event.DatabaseListener; import net.sf.briar.api.db.event.MessagesAddedEvent; -import net.sf.briar.api.db.event.SubscriptionsUpdatedEvent; import net.sf.briar.api.db.event.TransportsUpdatedEvent; import net.sf.briar.api.protocol.Ack; import net.sf.briar.api.protocol.AuthorId; @@ -134,27 +132,26 @@ public abstract class DatabaseComponentTest extends TestCase { oneOf(database).getRemoteProperties(txn, transportId); will(returnValue(remoteProperties)); // subscribe(group) + oneOf(group).getId(); + will(returnValue(groupId)); + oneOf(database).containsSubscription(txn, groupId); + will(returnValue(false)); oneOf(database).addSubscription(txn, group); - will(returnValue(true)); - oneOf(listener).eventOccurred(with(any( - SubscriptionsUpdatedEvent.class))); // subscribe(group) again - oneOf(database).addSubscription(txn, group); - will(returnValue(false)); + oneOf(group).getId(); + will(returnValue(groupId)); + oneOf(database).containsSubscription(txn, groupId); + will(returnValue(true)); // getSubscriptions() oneOf(database).getSubscriptions(txn); will(returnValue(Collections.singletonList(groupId))); // unsubscribe(groupId) - oneOf(database).getVisibility(txn, groupId); - will(returnValue(Collections.<ContactId>emptySet())); - oneOf(database).removeSubscription(txn, groupId); + oneOf(database).containsSubscription(txn, groupId); will(returnValue(true)); - oneOf(listener).eventOccurred(with(any( - SubscriptionsUpdatedEvent.class))); - // unsubscribe(groupId) again - oneOf(database).getVisibility(txn, groupId); - will(returnValue(Collections.<ContactId>emptySet())); oneOf(database).removeSubscription(txn, groupId); + will(returnValue(Collections.<ContactId>emptyList())); + // unsubscribe(groupId) again + oneOf(database).containsSubscription(txn, groupId); will(returnValue(false)); // setConnectionWindow(contactId, 123, connectionWindow) oneOf(database).containsContact(txn, contactId); @@ -1278,8 +1275,6 @@ public abstract class DatabaseComponentTest extends TestCase { throws Exception { final TransportProperties properties = new TransportProperties(Collections.singletonMap("bar", "baz")); - final TransportProperties properties1 = - new TransportProperties(Collections.singletonMap("baz", "bam")); Mockery context = new Mockery(); @SuppressWarnings("unchecked") final Database<Object> database = context.mock(Database.class); @@ -1288,11 +1283,8 @@ public abstract class DatabaseComponentTest extends TestCase { context.checking(new Expectations() {{ oneOf(database).startTransaction(); will(returnValue(txn)); - oneOf(database).getLocalTransports(txn); - will(returnValue(Collections.singletonMap(transportId, - properties))); - oneOf(database).setLocalProperties(txn, transportId, - properties1); + oneOf(database).setLocalProperties(txn, transportId, properties); + will(returnValue(true)); oneOf(database).commitTransaction(txn); oneOf(listener).eventOccurred(with(any( TransportsUpdatedEvent.class))); @@ -1300,7 +1292,7 @@ public abstract class DatabaseComponentTest extends TestCase { DatabaseComponent db = createDatabaseComponent(database, cleaner); db.addListener(listener); - db.setLocalProperties(transportId, properties1); + db.setLocalProperties(transportId, properties); context.assertIsSatisfied(); } @@ -1318,9 +1310,8 @@ public abstract class DatabaseComponentTest extends TestCase { context.checking(new Expectations() {{ oneOf(database).startTransaction(); will(returnValue(txn)); - oneOf(database).getLocalTransports(txn); - will(returnValue(Collections.singletonMap(transportId, - properties))); + oneOf(database).setLocalProperties(txn, transportId, properties); + will(returnValue(false)); oneOf(database).commitTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, cleaner); @@ -1331,60 +1322,6 @@ public abstract class DatabaseComponentTest extends TestCase { context.assertIsSatisfied(); } - @Test - public void testTransportConfigChangedCallsListeners() throws Exception { - final TransportConfig config = - new TransportConfig(Collections.singletonMap("bar", "baz")); - final TransportConfig config1 = - new TransportConfig(Collections.singletonMap("baz", "bam")); - Mockery context = new Mockery(); - @SuppressWarnings("unchecked") - final Database<Object> database = context.mock(Database.class); - final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); - final DatabaseListener listener = context.mock(DatabaseListener.class); - context.checking(new Expectations() {{ - oneOf(database).startTransaction(); - will(returnValue(txn)); - oneOf(database).getConfig(txn, transportId); - will(returnValue(config)); - oneOf(database).setConfig(txn, transportId, config1); - oneOf(database).commitTransaction(txn); - oneOf(listener).eventOccurred(with(any( - TransportsUpdatedEvent.class))); - }}); - DatabaseComponent db = createDatabaseComponent(database, cleaner); - - db.addListener(listener); - db.setConfig(transportId, config1); - - context.assertIsSatisfied(); - } - - @Test - public void testTransportConfigUnchangedDoesNotCallListeners() - throws Exception { - final TransportConfig config = - new TransportConfig(Collections.singletonMap("bar", "baz")); - Mockery context = new Mockery(); - @SuppressWarnings("unchecked") - final Database<Object> database = context.mock(Database.class); - final DatabaseCleaner cleaner = context.mock(DatabaseCleaner.class); - final DatabaseListener listener = context.mock(DatabaseListener.class); - context.checking(new Expectations() {{ - oneOf(database).startTransaction(); - will(returnValue(txn)); - oneOf(database).getConfig(txn, transportId); - will(returnValue(config)); - oneOf(database).commitTransaction(txn); - }}); - DatabaseComponent db = createDatabaseComponent(database, cleaner); - - db.addListener(listener); - db.setConfig(transportId, config); - - context.assertIsSatisfied(); - } - @Test public void testSetSeen() throws Exception { Mockery context = new Mockery(); -- GitLab