Skip to content
This repository was archived by the owner on Mar 11, 2022. It is now read-only.

Commit cb7bd1e

Browse files
authored
Merge pull request #385 from cloudant/missing-open-revs
Handle missing revisions correctly.
2 parents 5a65171 + 9b01371 commit cb7bd1e

File tree

4 files changed

+102
-1
lines changed

4 files changed

+102
-1
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Unreleased
22
- [FIXED] Incorrect message output from parameter `null` or empty checks.
3+
- [FIXED] Issue where replications would error if the server returned missing revisions.
34
- [UPGRADED] Upgraded to version 2.7.0 of the `cloudant-http` library.
45

56
# 1.1.2 (2016-10-20)

cloudant-sync-datastore-core/src/main/java/com/cloudant/mazha/CouchClient.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
*
44
* Copyright (C) 2011 Ahmed Yehia (ahmed.yehia.m@gmail.com)
55
*
6+
* Copyright © 2016 IBM Corp. All rights reserved.
7+
*
68
* Licensed under the Apache License, Version 2.0 (the "License");
79
* you may not use this file except in compliance with the License.
810
* You may obtain a copy of the License at
@@ -409,6 +411,9 @@ public List<OpenRevision> getDocWithOpenRevisions(String id, Collection<String>
409411

410412
Map<String, Object> options = new HashMap<String, Object>();
411413
options.put("revs", true);
414+
// by adding latest we should never receive a "missing" response from the server. A descendant
415+
// of the revision requested will be returned even if it has been deleted.
416+
options.put("latest", true);
412417
// only pull attachments inline if we're configured to
413418
if (pullAttachmentsInline) {
414419
options.put("attachments", true);

cloudant-sync-datastore-core/src/main/java/com/cloudant/sync/replication/CouchClientWrapper.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
/**
22
* Copyright (c) 2013 Cloudant, Inc. All rights reserved.
33
*
4+
* Copyright © 2016 IBM Corp. All rights reserved.
5+
*
46
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
57
* except in compliance with the License. You may obtain a copy of the License at
68
*
@@ -48,7 +50,7 @@ public class CouchClientWrapper implements CouchDB {
4850
private final static String LOG_TAG = "CouchClientWrapper";
4951
private static final Logger logger = Logger.getLogger(CouchClientWrapper.class.getCanonicalName());
5052

51-
final CouchClient couchClient;
53+
CouchClient couchClient;
5254

5355
public CouchClientWrapper(CouchClient client) {
5456
Misc.checkNotNull(client, "Couch client");
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright © 2016 IBM Corp. All rights reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5+
* except in compliance with the License. You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software distributed under the
10+
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
11+
* either express or implied. See the License for the specific language governing permissions
12+
* and limitations under the License.
13+
*/
14+
15+
package com.cloudant.sync.replication;
16+
17+
18+
import static org.mockito.Matchers.anyInt;
19+
import static org.mockito.Matchers.anyMapOf;
20+
import static org.mockito.Matchers.anyString;
21+
import static org.mockito.Mockito.doAnswer;
22+
import static org.mockito.Mockito.spy;
23+
24+
import com.cloudant.mazha.ChangesResult;
25+
import com.cloudant.mazha.CouchClient;
26+
import com.cloudant.sync.datastore.DocumentRevision;
27+
import com.cloudant.sync.datastore.DocumentRevisionTree;
28+
29+
import org.junit.Assert;
30+
import org.junit.Before;
31+
import org.junit.Test;
32+
import org.mockito.Matchers;
33+
import org.mockito.invocation.InvocationOnMock;
34+
import org.mockito.stubbing.Answer;
35+
36+
37+
public class MissingRevsReplicationTest extends ReplicationTestBase {
38+
39+
private CouchClient clientMock;
40+
41+
@Before
42+
public void setupMocks() throws Exception {
43+
// Partially mock the remote and replace it for our test
44+
clientMock = spy(remoteDb.couchClient);
45+
remoteDb.couchClient = clientMock;
46+
couchClient = clientMock;
47+
}
48+
49+
@Override
50+
protected PullStrategy getPullStrategy() {
51+
PullStrategy s = super.getPullStrategy();
52+
s.sourceDb = remoteDb;
53+
return s;
54+
}
55+
56+
@Test
57+
public void testReplicationWithMissingRevision() throws Exception {
58+
// Create doc
59+
Bar a = BarUtils.createBar(remoteDb, "testdoc", "alpha", 1);
60+
// Update doc
61+
final Bar b = BarUtils.updateBar(remoteDb, "testdoc", "beta", 2);
62+
63+
Bar c = BarUtils.updateBar(remoteDb, "testdoc", "gamma", 3);
64+
// We have 3 remote revisions
65+
66+
doAnswer(new Answer<ChangesResult>() {
67+
68+
@Override
69+
public ChangesResult answer(InvocationOnMock invocation) throws Throwable {
70+
@SuppressWarnings("unchecked")
71+
ChangesResult changesResult = (ChangesResult) invocation.callRealMethod();
72+
73+
// modify the changes feed so that it returns a revision that isn't a leaf revision.
74+
changesResult.getResults().get(0).getChanges().get(0).setRev(b.getRevision());
75+
return changesResult;
76+
77+
}
78+
}).when(clientMock).changes(anyString(), anyMapOf(String.class, String.class), Matchers.anyObject(), anyInt());
79+
80+
// Do the pull replication
81+
pull();
82+
// Validate the document was created at the correct rev
83+
DocumentRevision rev = datastore.getDocument("testdoc");
84+
Assert.assertNotNull("The document should be present", rev);
85+
Assert.assertEquals("The local revision should be the third generation",
86+
c.getRevision(),
87+
rev.getRevision());
88+
// Validate that there are 3 revisions.
89+
DocumentRevisionTree tree = datastore.getAllRevisionsOfDocument("testdoc");
90+
Assert.assertEquals("The 3rd generation current revision should have depth 2", 2, tree.depth
91+
(tree.getCurrentRevision().getSequence()));
92+
}
93+
}

0 commit comments

Comments
 (0)