|
22 | 22 | import android.database.sqlite.SQLiteDatabase;
|
23 | 23 | import android.database.sqlite.SQLiteOpenHelper;
|
24 | 24 | import com.google.firebase.firestore.model.DatabaseId;
|
| 25 | +import com.google.firebase.firestore.model.ResourcePath; |
| 26 | +import com.google.firebase.firestore.proto.WriteBatch; |
| 27 | +import com.google.firebase.firestore.remote.RemoteSerializer; |
| 28 | +import com.google.firestore.v1beta1.Document; |
| 29 | +import com.google.firestore.v1beta1.Write; |
25 | 30 | import org.junit.After;
|
26 | 31 | import org.junit.Before;
|
27 | 32 | import org.junit.Test;
|
@@ -51,7 +56,9 @@ public void onCreate(SQLiteDatabase db) {}
|
51 | 56 | public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
|
52 | 57 | };
|
53 | 58 | db = opener.getWritableDatabase();
|
54 |
| - schema = new SQLiteSchema(db); |
| 59 | + schema = |
| 60 | + new SQLiteSchema( |
| 61 | + db, new LocalSerializer(new RemoteSerializer(DatabaseId.forProject("projectId")))); |
55 | 62 | }
|
56 | 63 |
|
57 | 64 | @After
|
@@ -123,6 +130,130 @@ public void testDatabaseName() {
|
123 | 130 | "[DEFAULT]", DatabaseId.forDatabase("my-project", "my-database")));
|
124 | 131 | }
|
125 | 132 |
|
| 133 | + @Test |
| 134 | + public void dropsHeldWriteAcks() { |
| 135 | + // This test creates a database with schema version 4 that has two users, |
| 136 | + // both of which have acknowledged mutations that haven't yet been removed |
| 137 | + // from IndexedDb ("heldWriteAcks"). Schema version 5 removes heldWriteAcks, |
| 138 | + // and as such these mutations are deleted. |
| 139 | + schema.runMigrations(0, 5); |
| 140 | + |
| 141 | + Write testWriteFoo = |
| 142 | + Write.newBuilder() |
| 143 | + .setUpdate( |
| 144 | + Document.newBuilder() |
| 145 | + .setName("projects/projectId/databases/(default)/documents/docs/foo")) |
| 146 | + .build(); |
| 147 | + Write testWriteBar = |
| 148 | + Write.newBuilder() |
| 149 | + .setUpdate( |
| 150 | + Document.newBuilder() |
| 151 | + .setName("projects/projectId/databases/(default)/documents/docs/bar")) |
| 152 | + .build(); |
| 153 | + Write testWriteBaz = |
| 154 | + Write.newBuilder() |
| 155 | + .setUpdate( |
| 156 | + Document.newBuilder() |
| 157 | + .setName("projects/projectId/databases/(default)/documents/docs/baz")) |
| 158 | + .build(); |
| 159 | + Write testWritePending = |
| 160 | + Write.newBuilder() |
| 161 | + .setUpdate( |
| 162 | + Document.newBuilder() |
| 163 | + .setName("projects/projectId/databases/(default)/documents/docs/pending")) |
| 164 | + .build(); |
| 165 | + |
| 166 | + // User 'foo' has two acknowledged mutations and one that is pending. |
| 167 | + db.execSQL( |
| 168 | + "INSERT INTO mutations (uid, batch_id, mutations) VALUES (?,?,?)", |
| 169 | + new Object[] { |
| 170 | + "userA", |
| 171 | + 1, |
| 172 | + WriteBatch.newBuilder().setBatchId(1).addWrites(testWriteFoo).build().toByteArray() |
| 173 | + }); |
| 174 | + db.execSQL( |
| 175 | + "INSERT INTO mutations (uid, batch_id, mutations) VALUES (?,?,?)", |
| 176 | + new Object[] { |
| 177 | + "userA", |
| 178 | + 2, |
| 179 | + WriteBatch.newBuilder().setBatchId(2).addWrites(testWriteFoo).build().toByteArray() |
| 180 | + }); |
| 181 | + db.execSQL( |
| 182 | + "INSERT INTO mutations (uid, batch_id, mutations) VALUES (?,?,?)", |
| 183 | + new Object[] { |
| 184 | + "userA", |
| 185 | + 5, |
| 186 | + WriteBatch.newBuilder().setBatchId(5).addWrites(testWritePending).build().toByteArray() |
| 187 | + }); |
| 188 | + |
| 189 | + // User 'bar' has one acknowledged mutation and one that is pending. |
| 190 | + db.execSQL( |
| 191 | + "INSERT INTO mutations (uid, batch_id, mutations) VALUES (?,?,?)", |
| 192 | + new Object[] { |
| 193 | + "userB", |
| 194 | + 3, |
| 195 | + WriteBatch.newBuilder() |
| 196 | + .setBatchId(3) |
| 197 | + .addWrites(testWriteBar) |
| 198 | + .addWrites(testWriteBaz) |
| 199 | + .build() |
| 200 | + .toByteArray() |
| 201 | + }); |
| 202 | + db.execSQL( |
| 203 | + "INSERT INTO mutations (uid, batch_id, mutations) VALUES (?,?,?)", |
| 204 | + new Object[] { |
| 205 | + "userB", |
| 206 | + 4, |
| 207 | + WriteBatch.newBuilder().setBatchId(1).addWrites(testWritePending).build().toByteArray() |
| 208 | + }); |
| 209 | + |
| 210 | + // Create the document indices |
| 211 | + db.execSQL( |
| 212 | + "INSERT INTO document_mutations (uid, path, batch_id) VALUES (?, ?, ?)", |
| 213 | + new Object[] {"userA", EncodedPath.encode(ResourcePath.fromString("docs/foo")), 1}); |
| 214 | + db.execSQL( |
| 215 | + "INSERT INTO document_mutations (uid, path, batch_id) VALUES (?, ?, ?)", |
| 216 | + new Object[] {"userA", EncodedPath.encode(ResourcePath.fromString("docs/foo")), 2}); |
| 217 | + db.execSQL( |
| 218 | + "INSERT INTO document_mutations (uid, path, batch_id) VALUES (?, ?, ?)", |
| 219 | + new Object[] {"userA", EncodedPath.encode(ResourcePath.fromString("docs/pending")), 5}); |
| 220 | + db.execSQL( |
| 221 | + "INSERT INTO document_mutations (uid, path, batch_id) VALUES (?, ?, ?)", |
| 222 | + new Object[] {"userB", EncodedPath.encode(ResourcePath.fromString("docs/bar")), 3}); |
| 223 | + db.execSQL( |
| 224 | + "INSERT INTO document_mutations (uid, path, batch_id) VALUES (?, ?, ?)", |
| 225 | + new Object[] {"userB", EncodedPath.encode(ResourcePath.fromString("docs/baz")), 3}); |
| 226 | + db.execSQL( |
| 227 | + "INSERT INTO document_mutations (uid, path, batch_id) VALUES (?, ?, ?)", |
| 228 | + new Object[] {"userB", EncodedPath.encode(ResourcePath.fromString("docs/pending")), 4}); |
| 229 | + |
| 230 | + // Populate the mutation queues' metadata |
| 231 | + db.execSQL( |
| 232 | + "INSERT INTO mutation_queues (uid, last_acknowledged_batch_id) VALUES (?, ?)", |
| 233 | + new Object[] {"userA", 2}); |
| 234 | + db.execSQL( |
| 235 | + "INSERT INTO mutation_queues (uid, last_acknowledged_batch_id) VALUES (?, ?)", |
| 236 | + new Object[] {"userB", 3}); |
| 237 | + db.execSQL( |
| 238 | + "INSERT INTO mutation_queues (uid, last_acknowledged_batch_id) VALUES (?, ?)", |
| 239 | + new Object[] {"userC", -1}); |
| 240 | + |
| 241 | + schema.runMigrations(5, 6); |
| 242 | + |
| 243 | + // Verify that all but the two pending mutations have been cleared |
| 244 | + // by the migration. |
| 245 | + new SQLitePersistence.Query(db, "SELECT COUNT(*) FROM mutations") |
| 246 | + .first(value -> assertEquals(2, value.getInt(0))); |
| 247 | + |
| 248 | + // Verify that we still have two index entries for the pending documents |
| 249 | + new SQLitePersistence.Query(db, "SELECT COUNT(*) FROM document_mutations") |
| 250 | + .first(value -> assertEquals(2, value.getInt(0))); |
| 251 | + |
| 252 | + // Verify that we still have one metadata entry for each existing queue |
| 253 | + new SQLitePersistence.Query(db, "SELECT COUNT(*) FROM mutation_queues") |
| 254 | + .first(value -> assertEquals(3, value.getInt(0))); |
| 255 | + } |
| 256 | + |
126 | 257 | private void assertNoResultsForQuery(String query, String[] args) {
|
127 | 258 | Cursor cursor = null;
|
128 | 259 | try {
|
|
0 commit comments