001: /*
002: * All content copyright (c) 2003-2006 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tc.objectserver.lockmanager.impl;
006:
007: import com.tc.exception.ImplementMe;
008: import com.tc.net.groups.ClientID;
009: import com.tc.net.groups.NodeID;
010: import com.tc.net.protocol.tcm.ChannelID;
011: import com.tc.net.protocol.tcm.MessageChannel;
012: import com.tc.net.protocol.tcm.MockMessageChannel;
013: import com.tc.object.lockmanager.api.LockID;
014: import com.tc.object.msg.BatchTransactionAcknowledgeMessage;
015: import com.tc.object.net.DSOChannelManager;
016: import com.tc.object.net.DSOChannelManagerEventListener;
017: import com.tc.objectserver.lockmanager.api.LockAwardContext;
018: import com.tc.util.TCAssertionError;
019:
020: import java.util.Collection;
021: import java.util.HashMap;
022: import java.util.Map;
023: import java.util.Set;
024:
025: import junit.framework.TestCase;
026:
027: public class LockTimerTest extends TestCase {
028:
029: private LockTimer timer;
030: private LockAwardContext lockAwardContext;
031: private MockChannelManager channelManager;
032: private MockMessageChannel channel;
033: private ClientID clientID;
034: private int timeout;
035:
036: protected void setUp() throws Exception {
037: super .setUp();
038: ChannelID channelId = new ChannelID(101);
039: this .clientID = new ClientID(channelId);
040: this .channel = new MockMessageChannel(channelId);
041: this .channelManager = new MockChannelManager();
042: this .channelManager.addChannel(this .channel);
043:
044: this .timer = new LockTimer(this .channelManager);
045: this .lockAwardContext = new LockAwardContext() {
046:
047: public LockID getLockID() {
048: throw new ImplementMe();
049: }
050:
051: public NodeID getNodeID() {
052: return clientID;
053: }
054:
055: public long getTimeout() {
056: return timeout;
057: }
058:
059: };
060: }
061:
062: public void testNotifyAddPending() throws Exception {
063: this .timeout = 1000;
064:
065: // check that pending count is greater than zero.
066: try {
067: this .timer.notifyAddPending(0, this .lockAwardContext);
068: fail("Should have thrown an assertion error.");
069: } catch (TCAssertionError e) {
070: // expected
071: }
072:
073: // adding a pending with a pending count greater than one
074: this .timer.notifyAddPending(2, this .lockAwardContext);
075: checkTimerDoesNotFire();
076:
077: // adding a pending with a pending count of one should schedule the timeout.
078: this .timer.notifyAddPending(1, this .lockAwardContext);
079: checkTimerFires();
080: }
081:
082: public void testNotifyAward() throws Exception {
083: this .timeout = 1000;
084:
085: // the pending count must be >= 0;
086: try {
087: this .timer.notifyAward(-1, this .lockAwardContext);
088: fail("Should have thrown an assertion error.");
089: } catch (TCAssertionError e) {
090: // expected
091: }
092:
093: // if the pending count is 0, then the timeout should not get scheduled.
094: this .timer.notifyAward(0, this .lockAwardContext);
095: checkTimerDoesNotFire();
096:
097: // if the pending count is > 0, then the timeout SHOULD get scheduled.
098: this .timer.notifyAward(1, this .lockAwardContext);
099: checkTimerFires();
100:
101: this .timer.notifyAward(100, this .lockAwardContext);
102: checkTimerFires();
103: }
104:
105: public void testNotifyRevoke() throws Exception {
106: this .timeout = 1000;
107:
108: // if the award context is revoked without the timer having been scheduled, we should throw an assertion
109: // error
110: try {
111: this .timer.notifyRevoke(this .lockAwardContext);
112: fail("Expected an assertion error.");
113: } catch (TCAssertionError e) {
114: // expected
115: }
116:
117: // if the award context is added without any pending and then revoked, there should be no assertion fired.
118: this .timer.notifyAward(0, this .lockAwardContext);
119: this .timer.notifyRevoke(this .lockAwardContext);
120:
121: // if the award context is revoked after being awarded, the timer should not fire
122: this .timer.notifyAward(1, this .lockAwardContext);
123: checkTimerFires();
124: this .timer.notifyAward(1, this .lockAwardContext);
125: Thread.sleep(timeout / 4);
126: this .timer.notifyRevoke(this .lockAwardContext);
127: checkTimerDoesNotFire();
128:
129: // if a different award context is revoked, the original one should still fire.
130: this .timer.notifyAward(1, this .lockAwardContext);
131:
132: LockAwardContext newContext = new LockAwardContext() {
133:
134: public LockID getLockID() {
135: throw new ImplementMe();
136: }
137:
138: public NodeID getNodeID() {
139: return new ClientID(new ChannelID(234709381274908237L));
140: }
141:
142: public long getTimeout() {
143: return 1001;
144: }
145: };
146: this .timer.notifyAward(1, newContext);
147: this .timer.notifyRevoke(newContext);
148:
149: checkTimerFires();
150: }
151:
152: public void testStartTimerForLock() throws Exception {
153: this .timeout = 2000;
154: // max time over the timeout to allow for the test to pass.
155: long excessThreshold = 800;
156: long start = System.currentTimeMillis();
157: this .timer.startTimerForLock(this .lockAwardContext);
158:
159: checkTimerFires();
160:
161: long elapsed = this .channel.getLastClosedCallTimestamp()
162: - start;
163:
164: // make sure that it didn't happen in less time than the lock timeout.
165: assertTrue("elapsed time (" + elapsed
166: + " ms.) not greater than or equal to the timeout ("
167: + timeout + " ms.)", elapsed >= timeout);
168: // make sure that it didn't happen in greater time than the lock timeout + the excess threshold.
169: assertTrue(
170: "elapsed time ("
171: + elapsed
172: + " ms.) not less than or equal to the timeout plus excess threshold ("
173: + (timeout + excessThreshold) + " ms.)",
174: elapsed <= (timeout + excessThreshold));
175:
176: }
177:
178: public void testCancel() throws Exception {
179: timeout = 2000;
180:
181: this .timer.startTimerForLock(this .lockAwardContext);
182: // make sure the timer actually fires.
183: checkTimerFires();
184:
185: // reschedule
186: this .timer.startTimerForLock(this .lockAwardContext);
187:
188: // wait a bit...
189: Thread.sleep(timeout / 4);
190: // cancel the timer...
191: LockAwardContext cancelled = this .timer
192: .cancel(this .lockAwardContext);
193:
194: // we should never see the close call.
195: checkTimerDoesNotFire();
196:
197: assertEquals("Unexpected return value from cancel.",
198: this .lockAwardContext, cancelled);
199:
200: cancelled = this .timer.cancel(this .lockAwardContext);
201: assertTrue(
202: "Return value from a cancel that doesn't cancel anything should be null but is: "
203: + cancelled, cancelled == null);
204: }
205:
206: private void checkTimerDoesNotFire() throws InterruptedException {
207: assertTrue(timeout > 0);
208: assertFalse(this .channel.waitForCloseCall(timeout + 1000));
209: }
210:
211: private void checkTimerFires() throws InterruptedException {
212: assertTrue(timeout > 0);
213: assertTrue(this .channel.waitForCloseCall(timeout + 1000));
214: }
215:
216: public static class MockChannelManager implements DSOChannelManager {
217:
218: private Map channels = new HashMap();
219:
220: public void addChannel(MessageChannel channel) {
221: synchronized (channels) {
222: this .channels.put(new ClientID(channel.getChannelID()),
223: channel);
224: }
225: }
226:
227: public MessageChannel getActiveChannel(NodeID id) {
228: synchronized (channels) {
229: return (MessageChannel) this .channels.get(id);
230: }
231: }
232:
233: public MessageChannel[] getActiveChannels() {
234: throw new ImplementMe();
235: }
236:
237: public boolean isActiveID(NodeID nodeID) {
238: throw new ImplementMe();
239: }
240:
241: public void closeAll(Collection channelIDs) {
242: throw new ImplementMe();
243: }
244:
245: public String getChannelAddress(NodeID nid) {
246: return null;
247: }
248:
249: public BatchTransactionAcknowledgeMessage newBatchTransactionAcknowledgeMessage(
250: NodeID nid) {
251: throw new ImplementMe();
252: }
253:
254: public Set getAllActiveClientIDs() {
255: throw new ImplementMe();
256: }
257:
258: public void addEventListener(
259: DSOChannelManagerEventListener listener) {
260: throw new ImplementMe();
261: }
262:
263: public void makeChannelActive(ClientID clientID, long startIDs,
264: long endIDs, boolean persistent) {
265: throw new ImplementMe();
266: }
267:
268: public Set getAllClientIDs() {
269: throw new ImplementMe();
270: }
271:
272: public void makeChannelActiveNoAck(MessageChannel channel) {
273: throw new ImplementMe();
274: }
275:
276: public ClientID getClientIDFor(ChannelID channelID) {
277: return new ClientID(channelID);
278: }
279:
280: }
281:
282: }
|