Skip to content

Commit fb5cecb

Browse files
committed
write an integration test for eventuall list synchronity #16
1 parent ca82dd7 commit fb5cecb

File tree

3 files changed

+212
-1
lines changed

3 files changed

+212
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,182 @@
1+
/**
2+
* This file is part of SynchronizeFX.
3+
*
4+
* Copyright (C) 2013-2014 Saxonia Systems AG
5+
*
6+
* SynchronizeFX is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* SynchronizeFX is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with SynchronizeFX. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
package de.saxsys.synchronizefx.core.metamodel.concurrency;
21+
22+
import javafx.beans.property.ListProperty;
23+
import javafx.beans.property.SimpleListProperty;
24+
import javafx.collections.FXCollections;
25+
26+
import de.saxsys.synchronizefx.core.inmemorypeers.InMemoryClient;
27+
import de.saxsys.synchronizefx.core.inmemorypeers.InMemoryServer;
28+
import de.saxsys.synchronizefx.core.metamodel.executors.ReparingListPropertyCommandExecutorTest;
29+
30+
import org.junit.Before;
31+
import org.junit.Ignore;
32+
import org.junit.Test;
33+
34+
import static org.assertj.core.api.Assertions.assertThat;
35+
36+
/**
37+
* Checks that concurrent modifications on a list property are eventually consistent.
38+
*
39+
* <p>
40+
* This test checks if all classes necessary for list synchronization work correctly together. An exhaustive test for
41+
* all corner cases is done in {@link ReparingListPropertyCommandExecutorTest}.
42+
* </p>
43+
*
44+
* @author Raik Bieniek
45+
*/
46+
@Ignore("not implemented yet")
47+
public class ConcurrentModificationListPropertyIT {
48+
49+
/**
50+
* The time to wait for consistency in milliseconds.
51+
*/
52+
private static final int WAIT_FOR_CONSITENCY_TIME = 100;
53+
54+
private InMemoryServer<ExemplaryModel> server;
55+
56+
private InMemoryClient<ExemplaryModel> client1;
57+
private InMemoryClient<ExemplaryModel> client2;
58+
59+
/**
60+
* Sets up the test model and all peers.
61+
*/
62+
@Before
63+
public void setUpPeersAndTestData() {
64+
final ExemplaryModel model = new ExemplaryModel();
65+
model.exemplaryProperty.add("initial 1");
66+
model.exemplaryProperty.add("initial 2");
67+
68+
server = new InMemoryServer<>(model);
69+
client1 = new InMemoryClient<>(server);
70+
client2 = new InMemoryClient<>(server);
71+
72+
server.startSynchronizeFxServer();
73+
client1.startSynchronizeFxClient();
74+
client2.startSynchronizeFxClient();
75+
}
76+
77+
/**
78+
* Two clients adding elements to the same list should eventually result in correct ordered list on all clients.
79+
*/
80+
@Test
81+
public void concurrentAddsShouldEventuallyBeInCorrectOrder() {
82+
client1.executeInClientThread(new Runnable() {
83+
@Override
84+
public void run() {
85+
// before "initial 1"
86+
client1.getModel().exemplaryProperty.add(0, "client 1 change");
87+
}
88+
});
89+
90+
client2.executeInClientThread(new Runnable() {
91+
@Override
92+
public void run() {
93+
// before "initial 2"
94+
client2.getModel().exemplaryProperty.add(1, "client 2 change");
95+
}
96+
});
97+
98+
waitForConsistency();
99+
100+
assertThat(server.getModel()).isEqualTo(client1.getModel()).isEqualTo(client2.getModel());
101+
assertThat(server.getModel().exemplaryProperty).containsExactly("client 1 change", "initial 1",
102+
"client 2 change", "initial 2");
103+
}
104+
105+
/**
106+
* Two clients removing the same element concurrently should eventually result in synchronous lists.
107+
*/
108+
@Test
109+
public void concurrentlyRemovingTheSameElementShouldWork() {
110+
client1.executeInClientThread(new Runnable() {
111+
@Override
112+
public void run() {
113+
// remove "initial 2"
114+
client1.getModel().exemplaryProperty.remove(1);
115+
}
116+
});
117+
118+
client2.executeInClientThread(new Runnable() {
119+
@Override
120+
public void run() {
121+
// remove "initial 2"
122+
client1.getModel().exemplaryProperty.remove(1);
123+
}
124+
});
125+
126+
waitForConsistency();
127+
128+
assertThat(server.getModel()).isEqualTo(client1.getModel()).isEqualTo(client2.getModel());
129+
assertThat(server.getModel().exemplaryProperty).containsExactly("initial 1");
130+
}
131+
132+
private void waitForConsistency() {
133+
try {
134+
Thread.sleep(WAIT_FOR_CONSITENCY_TIME);
135+
} catch (final InterruptedException e) {
136+
throw new RuntimeException("Could not wait for consistency. ", e);
137+
}
138+
}
139+
140+
/**
141+
* An exemplary model that is used in the tests.
142+
*/
143+
public static final class ExemplaryModel {
144+
private final ListProperty<String> exemplaryProperty = new SimpleListProperty<>(
145+
FXCollections.<String> observableArrayList());
146+
147+
@Override
148+
public int hashCode() {
149+
final int prime = 31;
150+
int result = 1;
151+
result = prime * result + ((exemplaryProperty == null) ? 0 : exemplaryProperty.hashCode());
152+
return result;
153+
}
154+
155+
@Override
156+
public boolean equals(final Object obj) {
157+
if (this == obj) {
158+
return true;
159+
}
160+
if (obj == null) {
161+
return false;
162+
}
163+
if (getClass() != obj.getClass()) {
164+
return false;
165+
}
166+
ExemplaryModel other = (ExemplaryModel) obj;
167+
if (exemplaryProperty == null) {
168+
if (other.exemplaryProperty != null) {
169+
return false;
170+
}
171+
} else if (!exemplaryProperty.equals(other.exemplaryProperty)) {
172+
return false;
173+
}
174+
return true;
175+
}
176+
177+
@Override
178+
public String toString() {
179+
return "ExemplaryModel [exemplaryProperty=" + exemplaryProperty + "]";
180+
}
181+
}
182+
}

synchronizefx-core/src/test/java/de/saxsys/synchronizefx/core/metamodel/concurrency/ConcurrentModificationSingleValuePropertyIT.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
/**
3434
* Checks that concurrent modifications on a single value property are eventually consistent.
3535
*
36-
* @author Raik Bieniek <[email protected]>
36+
* @author Raik Bieniek
3737
*/
3838
public class ConcurrentModificationSingleValuePropertyIT {
3939

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* This file is part of SynchronizeFX.
3+
*
4+
* Copyright (C) 2013-2014 Saxonia Systems AG
5+
*
6+
* SynchronizeFX is free software: you can redistribute it and/or modify
7+
* it under the terms of the GNU General Public License as published by
8+
* the Free Software Foundation, either version 3 of the License, or
9+
* (at your option) any later version.
10+
*
11+
* SynchronizeFX is distributed in the hope that it will be useful,
12+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14+
* GNU General Public License for more details.
15+
*
16+
* You should have received a copy of the GNU General Public License
17+
* along with SynchronizeFX. If not, see <http://www.gnu.org/licenses/>.
18+
*/
19+
20+
package de.saxsys.synchronizefx.core.metamodel.executors;
21+
22+
/**
23+
* Just a placeholder for now which is referenced in JavaDoc.
24+
*
25+
* @author Raik Bieniek
26+
*/
27+
public class ReparingListPropertyCommandExecutorTest {
28+
29+
}

0 commit comments

Comments
 (0)