blob: a5aa9d1e7b44243546437f4fc74f02b1915862a1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 2017 Oracle. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0, which accompanies this distribution
* and is available at https://www.eclipse.org/legal/epl-2.0/.
*
* Contributors:
* Oracle - initial API and implementation
******************************************************************************/
package org.eclipse.jpt.common.utility.tests.internal.reference;
import org.eclipse.jpt.common.utility.internal.predicate.PredicateTools;
import org.eclipse.jpt.common.utility.internal.reference.SimpleObjectReference;
import org.eclipse.jpt.common.utility.internal.reference.SynchronizedObject;
import org.eclipse.jpt.common.utility.reference.ModifiableObjectReference;
import org.eclipse.jpt.common.utility.tests.internal.MultiThreadedTestCase;
import org.eclipse.jpt.common.utility.tests.internal.TestTools;
@SuppressWarnings("nls")
public class SynchronizedObjectTests
extends MultiThreadedTestCase
{
private volatile SynchronizedObject<Object> so;
volatile boolean timeoutOccurred;
volatile Object value = new Object();
volatile long startTime;
volatile long endTime;
volatile Object soValue;
public SynchronizedObjectTests(String name) {
super(name);
}
@Override
protected void setUp() throws Exception {
super.setUp();
this.so = new SynchronizedObject<>();
this.timeoutOccurred = false;
this.startTime = 0;
this.endTime = 0;
this.soValue = null;
}
public void testCtorObjectObject() throws Exception {
String v = "foo";
String mutex = "lock";
this.so = new SynchronizedObject<>(v, mutex);
assertEquals(v, this.so.getValue());
assertEquals(mutex, this.so.getMutex());
}
public void testAccessors() throws Exception {
this.so.setValue(null);
assertNull(this.so.getValue());
assertFalse(this.so.isNotNull());
assertTrue(this.so.isNull());
this.so.setValue(this.value);
assertEquals(this.value, this.so.getValue());
assertTrue(this.so.isNotNull());
assertFalse(this.so.isNull());
this.so.setNull();
assertNull(this.so.getValue());
assertFalse(this.so.isNotNull());
assertTrue(this.so.isNull());
assertSame(this.so, this.so.getMutex());
}
public void testValueEqualsObject() throws Exception {
String v = "foo";
this.so.setValue(null);
assertTrue(this.so.valueEquals(null));
assertFalse(this.so.valueEquals(v));
this.so.setValue(v);
assertTrue(this.so.valueEquals(v));
assertFalse(this.so.valueEquals(null));
}
public void testValueNotEqualObject() throws Exception {
String v = "foo";
this.so.setValue(null);
assertFalse(this.so.valueNotEqual(null));
assertTrue(this.so.valueNotEqual(v));
this.so.setValue(v);
assertFalse(this.so.valueNotEqual(v));
assertTrue(this.so.valueNotEqual(null));
}
public void testIsObject() throws Exception {
String v = "foo";
this.so.setValue(null);
assertTrue(this.so.is(null));
assertFalse(this.so.is(v));
this.so.setValue(v);
assertTrue(this.so.is(v));
assertFalse(this.so.is(null));
assertFalse(this.so.is(new String(v)));
}
public void testIsNotObject() throws Exception {
String v = "foo";
this.so.setValue(null);
assertFalse(this.so.isNot(null));
assertTrue(this.so.isNot(v));
this.so.setValue(v);
assertFalse(this.so.isNot(v));
assertTrue(this.so.isNot(null));
assertTrue(this.so.isNot(new String(v)));
}
public void testIsMemberOfPredicate() throws Exception {
String v = "foo";
this.so.setValue(null);
assertTrue(this.so.isMemberOf(PredicateTools.isNull()));
assertFalse(this.so.isMemberOf(PredicateTools.isNotNull()));
this.so.setValue(v);
assertFalse(this.so.isMemberOf(PredicateTools.isNull()));
assertTrue(this.so.isMemberOf(PredicateTools.isNotNull()));
}
public void testIsNotMemberOfPredicate() throws Exception {
String v = "foo";
this.so.setValue(null);
assertFalse(this.so.isNotMemberOf(PredicateTools.isNull()));
assertTrue(this.so.isNotMemberOf(PredicateTools.isNotNull()));
this.so.setValue(v);
assertTrue(this.so.isNotMemberOf(PredicateTools.isNull()));
assertFalse(this.so.isNotMemberOf(PredicateTools.isNotNull()));
}
public void testCommit() throws Exception {
String v1 = "foo";
this.so.setValue(null);
assertTrue(this.so.commit(v1, null));
assertEquals(v1, this.so.getValue());
assertFalse(this.so.commit(v1, null));
assertEquals(v1, this.so.getValue());
String v2 = "bar";
assertTrue(this.so.commit(v2, v1));
assertEquals(v2, this.so.getValue());
assertFalse(this.so.commit(v2, v1));
assertEquals(v2, this.so.getValue());
}
public void testSwapRef() throws Exception {
this.so.setValue(null);
ModifiableObjectReference<Object> temp = this.so;
assertEquals(null, this.so.swap(temp));
ModifiableObjectReference<Object> ref = new SimpleObjectReference<>("foo");
assertEquals("foo", this.so.swap(ref));
assertEquals("foo", this.so.getValue());
assertEquals(null, ref.getValue());
this.so.setValue("foo");
ref.setValue("foo");
assertEquals("foo", this.so.swap(ref));
assertEquals("foo", this.so.getValue());
assertEquals("foo", ref.getValue());
}
public void testSwapSyncObject() throws Exception {
this.so.setValue(null);
assertEquals(null, this.so.swap(this.so));
ModifiableObjectReference<Object> ref = new SynchronizedObject<>("foo");
assertEquals("foo", this.so.swap(ref));
assertEquals("foo", this.so.getValue());
assertEquals(null, ref.getValue());
this.so.setValue("foo");
ref.setValue("foo");
assertEquals("foo", this.so.swap(ref));
assertEquals("foo", this.so.getValue());
assertEquals("foo", ref.getValue());
ref.setValue("bar");
assertEquals("foo", ref.swap(this.so));
assertEquals("bar", this.so.getValue());
assertEquals("foo", ref.getValue());
}
public void testSwapSyncInt2() throws Exception {
this.so.setValue(null);
assertEquals(null, this.so.swap(this.so));
SynchronizedObject<Object> ref = new SynchronizedObject<>("foo");
assertEquals("foo", this.so.swap(ref));
assertEquals("foo", this.so.getValue());
assertEquals(null, ref.getValue());
this.so.setValue("foo");
ref.setValue("foo");
assertEquals("foo", this.so.swap(ref));
assertEquals("foo", this.so.getValue());
assertEquals("foo", ref.getValue());
}
/**
* t2 will wait indefinitely until t1 sets the value to null
*/
public void testWaitUntilNull() throws Exception {
this.verifyWaitUntilNull(-1); // explicit indefinite wait
// no timeout occurs...
assertFalse(this.timeoutOccurred);
// ...and the value should be set to null by t2
assertNull(this.so.getValue());
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
//assertTrue("t2 finished a bit early (expected value should be > " + TICK + "): " + time, time > TICK);
}
/**
* t2 will wait indefinitely until t1 sets the value to null
*/
public void testWaitUntilNull2() throws Exception {
this.verifyWaitUntilNull(0); // 0 = indefinite wait
// no timeout occurs...
assertFalse(this.timeoutOccurred);
// ...and the value should be set to null by t2
assertNull(this.so.getValue());
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
//assertTrue("t2 finished a bit early (expected value should be > " + TICK + "): " + time, time > TICK);
}
/**
* t2 will time out waiting for t1 to set the value to null
*/
public void testWaitUntilNullTimeout() throws Exception {
this.verifyWaitUntilNull(TICK);
// timeout occurs...
assertTrue(this.timeoutOccurred);
// ...and the value will eventually be set to null by t1
assertNull(this.so.getValue());
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
assertTrue("t2 finished a bit late (expected value should be < " + THREE_TICKS + "): " + time, time < THREE_TICKS);
}
/**
* t2 will NOT time out waiting for t1 to set the value to null
*/
public void testWaitUntilNullTimeout2() throws Exception {
this.verifyWaitUntilNull(THREE_TICKS);
// no timeout occurs...
assertFalse(this.timeoutOccurred);
// ...and the value should be set to null by t2
assertNull(this.so.getValue());
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
//assertTrue("t2 finished a bit early (expected value should be >= " + TWO_TICKS + "): " + time, time >= TWO_TICKS);
}
private void verifyWaitUntilNull(long t2Timeout) throws Exception {
this.executeThreads(this.buildSetNullCommand(), this.buildWaitUntilNullCommand(t2Timeout));
}
private Command buildWaitUntilNullCommand(final long timeout) {
return new Command() {
public void execute(SynchronizedObject<Object> sObject) throws InterruptedException {
SynchronizedObjectTests.this.startTime = System.currentTimeMillis();
SynchronizedObjectTests.this.timeoutOccurred = this.timeoutOccurred(sObject);
SynchronizedObjectTests.this.endTime = System.currentTimeMillis();
}
private boolean timeoutOccurred(SynchronizedObject<Object> sObject) throws InterruptedException {
if (timeout < 0) {
sObject.waitUntilNull();
return false;
}
return ! sObject.waitUntilNull(timeout);
}
};
}
public void testWaitUntilNotPredicate() throws Exception {
this.so.setValue(this.value);
this.so.waitUntilNot(PredicateTools.isNull());
assertEquals(this.value, this.so.getValue());
}
public void testWaitUntilValueEqualsObject() throws Exception {
String v1 = "foo";
this.so.setValue(v1);
String v2 = new String(v1);
this.so.waitUntilValueEquals(v2);
assertEquals(v2, this.so.getValue());
}
public void testWaitUntilValueNotEqualObject() throws Exception {
String v = "foo";
this.so.setValue(v);
this.so.waitUntilValueNotEqual(null);
assertEquals(v, this.so.getValue());
}
public void testWaitUntilValueIsObject() throws Exception {
String v1 = "foo";
this.so.setValue(v1);
this.so.waitUntilValueIs(v1);
assertEquals(v1, this.so.getValue());
}
public void testWaitUntilValueIsNotObject() throws Exception {
String v1 = "foo";
this.so.setValue(v1);
String v2 = new String(v1);
this.so.waitUntilValueIsNot(v2);
assertSame(v1, this.so.getValue());
assertNotSame(v2, this.so.getValue());
}
public void testWaitUntilNotNull() throws Exception {
String v1 = "foo";
this.so.setValue(v1);
this.so.waitUntilNotNull();
assertEquals(v1, this.so.getValue());
}
public void testWaitToSetValueObject() throws Exception {
this.so.setValue(null);
assertNull(this.so.waitToSetValue(this.value));
assertEquals(this.value, this.so.getValue());
}
public void testWaitToSetNull() throws Exception {
this.so.setValue(this.value);
assertEquals(this.value, this.so.waitToSetNull());
assertNull(this.so.getValue());
}
public void testWaitToCommit() throws Exception {
this.so.setValue(this.value);
assertEquals(this.value, this.so.waitToCommit("foo", this.value));
assertEquals("foo", this.so.getValue());
}
/**
* t2 will wait indefinitely until t1 sets the value to null;
* then t2 will set the value to an object
*/
public void testWaitToSetValue() throws Exception {
this.verifyWaitToSetValue(-1); // explicit indefinite wait
// no timeout occurs...
assertFalse(this.timeoutOccurred);
// ...and the value should be set to an object by t2
assertTrue(this.so.isNotNull());
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
// assertTrue("t2 finished a bit early (expected value should be > " + TICK + "): " + time, time > TICK);
}
/**
* t2 will wait indefinitely until t1 sets the value to null;
* then t2 will set the value to an object
*/
public void testWaitToSetValue2() throws Exception {
this.verifyWaitToSetValue(0); // 0 = indefinite wait
// no timeout occurs...
assertFalse(this.timeoutOccurred);
// ...and the value should be set to an object by t2
assertTrue(this.so.isNotNull());
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
// assertTrue("t2 finished a bit early (expected value should be > " + TICK + "): " + time, time > TICK);
}
/**
* t2 will time out waiting for t1 to set the value to null
*/
public void testWaitToSetValueTimeout() throws Exception {
this.verifyWaitToSetValue(TICK);
// timeout occurs...
assertTrue(this.timeoutOccurred);
// ...and the value will eventually be set to null by t1
assertTrue(this.so.isNull());
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
assertTrue("t2 finished a bit late (expected value should be < " + THREE_TICKS + "): " + time, time < THREE_TICKS);
}
/**
* t2 will NOT time out waiting for t1 to set the value to null
*/
public void testWaitToSetValueTimeout2() throws Exception {
this.verifyWaitToSetValue(THREE_TICKS);
// no timeout occurs...
assertFalse(this.timeoutOccurred);
// ...and the value should be set to a value by t2
assertFalse(this.so.isNull());
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
// assertTrue("t2 finished a bit early (expected value should be >= " + TWO_TICKS + "): " + time, time >= TWO_TICKS);
}
private void verifyWaitToSetValue(long t2Timeout) throws Exception {
this.executeThreads(this.buildSetNullCommand(), this.buildWaitToSetValueCommand(t2Timeout));
}
private Command buildWaitToSetValueCommand(final long timeout) {
return new Command() {
public void execute(SynchronizedObject<Object> sObject) throws InterruptedException {
SynchronizedObjectTests.this.startTime = System.currentTimeMillis();
SynchronizedObjectTests.this.timeoutOccurred = this.timeoutOccurred(sObject);
SynchronizedObjectTests.this.endTime = System.currentTimeMillis();
}
private boolean timeoutOccurred(SynchronizedObject<Object> sObject) throws InterruptedException {
if (timeout < 0) {
sObject.waitToSetValue(SynchronizedObjectTests.this.value);
return false;
}
return ! sObject.waitToSetValue(SynchronizedObjectTests.this.value, timeout);
}
};
}
/**
* t2 will wait until t1 is finished "initializing" the value;
* then t2 will get the newly-initialized value ("foo")
*/
public void testExecute() throws Exception {
this.so.setValue(null);
Runnable r1 = this.buildRunnable(this.buildInitializeValueCommand(), this.so, 0);
// give t1 a head start of 100 ms
Runnable r2 = this.buildRunnable(this.buildGetValueCommand(), this.so, TICK);
Thread t1 = this.buildThread(r1);
Thread t2 = this.buildThread(r2);
t1.start();
t2.start();
t1.join();
t2.join();
assertEquals("foo", this.so.getValue());
assertEquals("foo", this.soValue);
// make a reasonable guess about how long t2 took
long time = this.calculateElapsedTime();
// assertTrue("t2 finished a bit early (expected value should be > " + TWO_TICKS + "): " + time, time > TWO_TICKS);
}
private void executeThreads(Command t1Command, Command t2Command) throws Exception {
this.so.setValue(this.value);
Runnable r1 = this.buildRunnable(t1Command, this.so, TWO_TICKS);
Runnable r2 = this.buildRunnable(t2Command, this.so, 0);
Thread t1 = this.buildThread(r1);
Thread t2 = this.buildThread(r2);
t1.start();
t2.start();
t1.join();
t2.join();
}
private Command buildSetNullCommand() {
return new Command() {
public void execute(SynchronizedObject<Object> sObject) {
sObject.setNull();
}
};
}
private Command buildInitializeValueCommand() {
return new Command() {
public void execute(final SynchronizedObject<Object> sObject) throws InterruptedException {
sObject.execute(
new org.eclipse.jpt.common.utility.command.Command() {
public void execute() {
// pretend to perform some long initialization process
try {
Thread.sleep(5 * TICK);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
sObject.setValue("foo");
}
}
);
}
};
}
private Command buildGetValueCommand() {
return new Command() {
public void execute(SynchronizedObject<Object> sObject) throws InterruptedException {
SynchronizedObjectTests.this.startTime = System.currentTimeMillis();
SynchronizedObjectTests.this.soValue = sObject.getValue();
SynchronizedObjectTests.this.endTime = System.currentTimeMillis();
}
};
}
private Runnable buildRunnable(final Command command, final SynchronizedObject<Object> sObject, final long sleep) {
return new TestRunnable() {
@Override
protected void run_() throws InterruptedException {
if (sleep != 0) {
Thread.sleep(sleep);
}
command.execute(sObject);
}
};
}
private long calculateElapsedTime() {
return this.endTime - this.startTime;
}
public void testWaitUntilNotPredicateTimeout() throws Exception {
this.so.setValue(this.value);
this.so.waitUntilNot(PredicateTools.isNull(), TWO_TICKS);
assertEquals(this.value, this.so.getValue());
}
public void testWaitUntilValueEqualsObjectTimeout() throws Exception {
String v1 = "foo";
this.so.setValue(v1);
String v2 = new String(v1);
this.so.waitUntilValueEquals(v2, TWO_TICKS);
assertEquals(v2, this.so.getValue());
}
public void testWaitUntilValueNotEqualObjectTimeout() throws Exception {
String v = "foo";
this.so.setValue(v);
this.so.waitUntilValueNotEqual(null, TWO_TICKS);
assertEquals(v, this.so.getValue());
}
public void testWaitUntilValueIsObjectTimeout() throws Exception {
String v1 = "foo";
this.so.setValue(v1);
this.so.waitUntilValueIs(v1, TWO_TICKS);
assertEquals(v1, this.so.getValue());
}
public void testWaitUntilValueIsNotObjectTimeout() throws Exception {
String v1 = "foo";
this.so.setValue(v1);
String v2 = new String(v1);
this.so.waitUntilValueIsNot(v2, TWO_TICKS);
assertSame(v1, this.so.getValue());
assertNotSame(v2, this.so.getValue());
}
public void testWaitUntilNotNullTimeout() throws Exception {
String v1 = "foo";
this.so.setValue(v1);
this.so.waitUntilNotNull(TWO_TICKS);
assertEquals(v1, this.so.getValue());
}
public void testWaitToSetValueObjectTimeout() throws Exception {
this.so.setValue(null);
assertTrue(this.so.waitToSetValue(this.value, TWO_TICKS));
assertEquals(this.value, this.so.getValue());
}
public void testWaitToSetNullTimeout() throws Exception {
this.so.setValue(this.value);
assertTrue(this.so.waitToSetNull(TWO_TICKS));
assertNull(this.so.getValue());
}
public void testWaitToCommitTimeout() throws Exception {
this.so.setValue(this.value);
assertTrue(this.so.waitToCommit("foo", this.value, TWO_TICKS));
assertEquals("foo", this.so.getValue());
}
// ********** Command interface **********
private interface Command {
void execute(SynchronizedObject<Object> so) throws InterruptedException;
}
// ********** standard methods **********
public void testEquals() {
SynchronizedObject<Object> so2 = new SynchronizedObject<>();
assertTrue(this.so.equals(this.so));
assertFalse(this.so.equals(so2));
}
public void testHashCode() {
assertEquals(this.so.hashCode(), this.so.hashCode());
}
public void testClone() {
this.so.setValue(null);
SynchronizedObject<Object> clone = this.so.clone();
assertNull(clone.getValue());
assertNotSame(clone, this.so);
this.so.setValue("foo");
clone = this.so.clone();
assertEquals("foo", clone.getValue());
assertNotSame(clone, this.so);
}
public void testSerialization() throws Exception {
this.so.setValue("foo");
SynchronizedObject<Object> clone = TestTools.serialize(this.so);
assertNotSame(this.so, clone);
assertEquals("foo", clone.getValue());
}
public void testToString() {
assertEquals("[null]", this.so.toString());
this.so.setValue("foo");
assertEquals("[foo]", this.so.toString());
}
}