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.object.handshakemanager;
006:
007: import com.tc.async.impl.NullSink;
008: import com.tc.cluster.Cluster;
009: import com.tc.exception.ImplementMe;
010: import com.tc.logging.TCLogging;
011: import com.tc.net.protocol.tcm.TestChannelIDProvider;
012: import com.tc.object.ClientIDProvider;
013: import com.tc.object.ClientIDProviderImpl;
014: import com.tc.object.NullPauseListener;
015: import com.tc.object.ObjectID;
016: import com.tc.object.RemoteObjectManager;
017: import com.tc.object.TestClientObjectManager;
018: import com.tc.object.dna.api.DNA;
019: import com.tc.object.gtx.TestClientGlobalTransactionManager;
020: import com.tc.object.lockmanager.api.ClientLockManager;
021: import com.tc.object.lockmanager.api.LockContext;
022: import com.tc.object.lockmanager.api.LockID;
023: import com.tc.object.lockmanager.api.LockLevel;
024: import com.tc.object.lockmanager.api.LockRequest;
025: import com.tc.object.lockmanager.api.Notify;
026: import com.tc.object.lockmanager.api.ThreadID;
027: import com.tc.object.lockmanager.api.WaitContext;
028: import com.tc.object.lockmanager.api.WaitListener;
029: import com.tc.object.lockmanager.api.WaitLockRequest;
030: import com.tc.object.lockmanager.impl.GlobalLockInfo;
031: import com.tc.object.msg.ClientHandshakeMessage;
032: import com.tc.object.msg.ClientHandshakeMessageFactory;
033: import com.tc.object.msg.TestClientHandshakeMessage;
034: import com.tc.object.session.NullSessionManager;
035: import com.tc.object.session.SessionID;
036: import com.tc.object.tx.TestRemoteTransactionManager;
037: import com.tc.object.tx.TransactionID;
038: import com.tc.object.tx.WaitInvocation;
039: import com.tc.properties.TCPropertiesImpl;
040: import com.tc.test.TCTestCase;
041: import com.tc.util.SequenceID;
042: import com.tc.util.concurrent.NoExceptionLinkedQueue;
043: import com.tc.util.sequence.BatchSequence;
044: import com.tc.util.sequence.BatchSequenceProvider;
045: import com.tc.util.sequence.BatchSequenceReceiver;
046:
047: import java.util.ArrayList;
048: import java.util.Collection;
049: import java.util.Collections;
050: import java.util.HashSet;
051: import java.util.LinkedList;
052: import java.util.List;
053: import java.util.Set;
054:
055: public class ClientHandshakeManagerTest extends TCTestCase {
056: private static final String clientVersion = "x.y.z";
057: private TestClientObjectManager objectManager;
058: private TestClientLockManager lockManager;
059: private ClientIDProvider cip;
060: private ClientHandshakeManager mgr;
061: private TestClientHandshakeMessageFactory chmf;
062: private TestRemoteObjectManager remoteObjectManager;
063: private TestRemoteTransactionManager rtxManager;
064: private TestClientGlobalTransactionManager gtxManager;
065:
066: public void setUp() throws Exception {
067: objectManager = new TestClientObjectManager();
068: remoteObjectManager = new TestRemoteObjectManager();
069: lockManager = new TestClientLockManager();
070: rtxManager = new TestRemoteTransactionManager();
071: gtxManager = new TestClientGlobalTransactionManager();
072: cip = new ClientIDProviderImpl(new TestChannelIDProvider());
073: chmf = new TestClientHandshakeMessageFactory();
074: mgr = new ClientHandshakeManager(TCLogging
075: .getLogger(ClientHandshakeManager.class), cip, chmf,
076: objectManager, remoteObjectManager, lockManager,
077: rtxManager, gtxManager, new ArrayList(),
078: new NullSink(), new NullSessionManager(),
079: new NullPauseListener(), new BatchSequence(
080: new TestSequenceProvider(), 100),
081: new Cluster(), clientVersion);
082: assertNotNull(gtxManager.pauseCalls.poll(0));
083: assertNull(gtxManager.pauseCalls.poll(0));
084: newMessage();
085: }
086:
087: private void newMessage() {
088: chmf.message = new TestClientHandshakeMessage();
089: }
090:
091: public void tests() {
092:
093: Collection sequenceIDs = new ArrayList();
094: sequenceIDs.add(new SequenceID(1001));
095: gtxManager.transactionSequenceIDs = sequenceIDs;
096:
097: Set objectIds = new HashSet();
098: for (int i = 0; i < 10; i++) {
099: ObjectID id = new ObjectID(i);
100: objectIds.add(id);
101: objectManager.objects.put(id, new Object());
102: }
103:
104: WaitLockRequest waitLockRequest = new WaitLockRequest(
105: new LockID("1"), new ThreadID(1), LockLevel.WRITE,
106: new WaitInvocation());
107: lockManager.outstandingWaitLockRequests.add(waitLockRequest);
108:
109: LockRequest lockRequest = new LockRequest(new LockID("2"),
110: new ThreadID(2), LockLevel.WRITE);
111: lockManager.outstandingLockAwards.add(lockRequest);
112:
113: assertTrue(lockManager.requestOutstandingContexts.isEmpty());
114: assertTrue(chmf.newMessageQueue.isEmpty());
115:
116: new Thread(new Runnable() {
117: public void run() {
118: mgr.initiateHandshake();
119: }
120: }).start();
121:
122: // make sure that the lock manager was paused and unpaused.
123: // assertEquals(1, lockManager.pauseContexts.size());
124: lockManager.pauseContexts.take();
125:
126: TestClientHandshakeMessage sentMessage = (TestClientHandshakeMessage) chmf.newMessageQueue
127: .take();
128: assertTrue(chmf.newMessageQueue.isEmpty());
129:
130: // make sure that the manager called send on the message...
131: sentMessage.sendCalls.take();
132: assertTrue(sentMessage.sendCalls.isEmpty());
133:
134: // make sure the transaction sequence is retrieved and added to the message.
135: assertNotNull(gtxManager.getTransactionSequenceIDsCalls.poll(0));
136: assertNull(gtxManager.getTransactionSequenceIDsCalls.poll(0));
137: assertEquals(gtxManager.transactionSequenceIDs,
138: sentMessage.setTransactionSequenceIDsCalls.poll(0));
139:
140: // make sure that the manager set the expected object ids on the message...
141: assertEquals(objectIds, sentMessage.clientObjectIds);
142:
143: // make sure that the manager called addAllOutstandingWaitersTo on the lock
144: // manager.
145: lockManager.addAllOutstandingWaitersToContexts.take();
146: assertTrue(lockManager.addAllOutstandingWaitersToContexts
147: .isEmpty());
148:
149: List waitContexts = new ArrayList(sentMessage.waitContexts);
150: assertEquals(1, waitContexts.size());
151: WaitContext wctxt = (WaitContext) waitContexts.get(0);
152: assertEquals(waitLockRequest.lockID(), wctxt.getLockID());
153: assertEquals(waitLockRequest.threadID(), wctxt.getThreadID());
154: assertEquals(waitLockRequest.getWaitInvocation(), wctxt
155: .getWaitInvocation());
156:
157: // make sure that the manager called addAllOutstandingLocksTo on the lock
158: // manager.
159: lockManager.addAllOutstandingLocksToContexts.take();
160: assertTrue(lockManager.addAllOutstandingLocksToContexts
161: .isEmpty());
162: List lockContexts = new ArrayList(sentMessage.lockContexts);
163: assertEquals(1, lockContexts.size());
164: LockContext lctxt = (LockContext) lockContexts.get(0);
165: assertEquals(lockRequest.lockID(), lctxt.getLockID());
166: assertEquals(lockRequest.threadID(), lctxt.getThreadID());
167: assertEquals(lockRequest.lockLevel(), lctxt.getLockLevel());
168:
169: // make sure that the manager called requestOutstanding() on the lock
170: // manager.
171: // assertEquals(1, lockManager.requestOutstandingContexts.size());
172: lockManager.requestOutstandingContexts.take();
173: assertTrue(lockManager.requestOutstandingContexts.isEmpty());
174:
175: // make sure the lock manager isn't unpaused until after the ACK arrives
176: assertTrue(lockManager.unpauseContexts.isEmpty());
177: assertTrue(gtxManager.resendOutstandingCalls.isEmpty());
178:
179: // make sure RuntimeException is thrown iff client/server versions don't match and version checking is enabled
180: try {
181: mgr.acknowledgeHandshake(0, 0, false, "1", new String[] {},
182: clientVersion + "a.b.c");
183: if (checkVersionMatchEnabled()) {
184: fail();
185: }
186: } catch (RuntimeException e) {
187: if (!checkVersionMatchEnabled()) {
188: fail();
189: }
190: }
191:
192: // now ack for real
193: mgr.acknowledgeHandshake(0, 0, false, "1", new String[] {},
194: clientVersion);
195:
196: // make sure the remote object manager was told to requestOutstanding()
197: remoteObjectManager.requestOutstandingContexts.take();
198: assertTrue(remoteObjectManager.requestOutstandingContexts
199: .isEmpty());
200:
201: assertNotNull(lockManager.unpauseContexts.poll(1));
202: assertNotNull(gtxManager.resendOutstandingCalls.poll(1));
203: }
204:
205: private boolean checkVersionMatchEnabled() {
206: return TCPropertiesImpl.getProperties().getBoolean(
207: "l1.connect.versionMatchCheck.enabled");
208: }
209:
210: private static class TestRemoteObjectManager implements
211: RemoteObjectManager {
212:
213: public final NoExceptionLinkedQueue requestOutstandingContexts = new NoExceptionLinkedQueue();
214:
215: public DNA retrieve(ObjectID id) {
216: throw new ImplementMe();
217: }
218:
219: public ObjectID retrieveRootID(String name) {
220: throw new ImplementMe();
221: }
222:
223: public void addRoot(String name, ObjectID id) {
224: throw new ImplementMe();
225: }
226:
227: public void removed(ObjectID id) {
228: throw new ImplementMe();
229: }
230:
231: public void requestOutstanding() {
232: requestOutstandingContexts.put(new Object());
233: }
234:
235: public void pause() {
236: return;
237: }
238:
239: public void unpause() {
240: return;
241: }
242:
243: public void starting() {
244: return;
245: }
246:
247: public void addAllObjects(SessionID sessionID, long batchID,
248: Collection dnas) {
249: throw new ImplementMe();
250:
251: }
252:
253: public void clear() {
254: return;
255: }
256:
257: public DNA retrieve(ObjectID id, int depth) {
258: throw new ImplementMe();
259: }
260:
261: public void objectsNotFoundFor(SessionID sessionID,
262: long batchID, Set missingObjectIDs) {
263: throw new ImplementMe();
264: }
265:
266: public DNA retrieveWithParentContext(ObjectID id,
267: ObjectID parentContext) {
268: throw new ImplementMe();
269: }
270:
271: }
272:
273: private static class TestClientHandshakeMessageFactory implements
274: ClientHandshakeMessageFactory {
275:
276: public TestClientHandshakeMessage message;
277: public final NoExceptionLinkedQueue newMessageQueue = new NoExceptionLinkedQueue();
278:
279: public ClientHandshakeMessage newClientHandshakeMessage() {
280: newMessageQueue.put(message);
281: return message;
282: }
283:
284: }
285:
286: private static class TestClientLockManager implements
287: ClientLockManager {
288:
289: public List outstandingLockAwards = new LinkedList();
290: public List outstandingWaitLockRequests = new LinkedList();
291:
292: public NoExceptionLinkedQueue requestOutstandingContexts = new NoExceptionLinkedQueue();
293: public NoExceptionLinkedQueue addAllOutstandingWaitersToContexts = new NoExceptionLinkedQueue();
294: public NoExceptionLinkedQueue addAllOutstandingLocksToContexts = new NoExceptionLinkedQueue();
295: public NoExceptionLinkedQueue pauseContexts = new NoExceptionLinkedQueue();
296: public NoExceptionLinkedQueue unpauseContexts = new NoExceptionLinkedQueue();
297:
298: public void lock(LockID id, ThreadID threadID, int type) {
299: return;
300: }
301:
302: public void unlock(LockID id, ThreadID threadID) {
303: return;
304: }
305:
306: public void awardLock(SessionID sessionID, LockID id,
307: ThreadID threadID, int type) {
308: return;
309: }
310:
311: public LockID lockIDFor(String id) {
312: return null;
313: }
314:
315: public void wait(LockID lockID, ThreadID threadID,
316: WaitInvocation call, Object waitObject,
317: WaitListener listener) {
318: return;
319: }
320:
321: public Notify notify(LockID lockID, ThreadID threadID,
322: boolean all) {
323: return Notify.NULL;
324: }
325:
326: public Collection addAllPendingLockRequestsTo(Collection c) {
327: requestOutstandingContexts.put(new Object());
328: return c;
329: }
330:
331: public void pause() {
332: pauseContexts.put(new Object());
333: }
334:
335: public void starting() {
336: return;
337: }
338:
339: public void unpause() {
340: unpauseContexts.put(new Object());
341: }
342:
343: public boolean isStarting() {
344: return false;
345: }
346:
347: public Collection addAllWaitersTo(Collection c) {
348: this .addAllOutstandingWaitersToContexts.put(c);
349: c.addAll(this .outstandingWaitLockRequests);
350: return c;
351: }
352:
353: public Collection addAllHeldLocksTo(Collection c) {
354: this .addAllOutstandingLocksToContexts.put(c);
355: c.addAll(this .outstandingLockAwards);
356: return c;
357: }
358:
359: public void notified(LockID lockID, ThreadID threadID) {
360: return;
361: }
362:
363: public void recall(LockID lockID, ThreadID id, int level) {
364: return;
365: }
366:
367: public void waitTimedOut(LockID lockID, ThreadID threadID) {
368: return;
369: }
370:
371: public void runGC() {
372: return;
373: }
374:
375: public int queueLength(LockID lockID, ThreadID threadID) {
376: throw new ImplementMe();
377: }
378:
379: public int localHeldCount(LockID lockID, int lockLevel,
380: ThreadID threadID) {
381: throw new ImplementMe();
382: }
383:
384: public boolean isLocked(LockID lockID, ThreadID threadID,
385: int lockLevel) {
386: throw new ImplementMe();
387: }
388:
389: public boolean haveLock(LockID lockID, TransactionID requesterID) {
390: throw new ImplementMe();
391: }
392:
393: public void queryLockCommit(ThreadID threadID,
394: GlobalLockInfo globalLockInfo) {
395: throw new ImplementMe();
396:
397: }
398:
399: public int waitLength(LockID lockID, ThreadID threadID) {
400: throw new ImplementMe();
401: }
402:
403: public boolean tryLock(LockID id, ThreadID threadID,
404: WaitInvocation timeout, int type) {
405: throw new ImplementMe();
406: }
407:
408: public Collection addAllPendingTryLockRequestsTo(Collection c) {
409: return Collections.EMPTY_LIST;
410: }
411:
412: public void cannotAwardLock(SessionID sessionID, LockID id,
413: ThreadID threadID, int type) {
414: throw new ImplementMe();
415: }
416:
417: public void enableStat(LockID lockID, int lockStackTraceDepth,
418: int lockStatCollectFrequency) {
419: throw new ImplementMe();
420: }
421:
422: public void disableStat(LockID lockID) {
423: throw new ImplementMe();
424: }
425: }
426:
427: public class TestSequenceProvider implements BatchSequenceProvider {
428:
429: long sequence = 1;
430:
431: public synchronized void requestBatch(
432: BatchSequenceReceiver receiver, int size) {
433: receiver.setNextBatch(sequence, sequence + size);
434: sequence += size;
435: }
436:
437: }
438:
439: }
|