001: /*
002:
003: Derby - Class org.apache.derbyTesting.unitTests.services.T_DaemonService
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derbyTesting.unitTests.services;
023:
024: import org.apache.derbyTesting.unitTests.harness.T_Fail;
025: import org.apache.derbyTesting.unitTests.harness.T_MultiThreadedIterations;
026: import org.apache.derby.iapi.services.context.ContextService;
027: import org.apache.derby.iapi.services.monitor.Monitor;
028: import org.apache.derby.iapi.error.StandardException;
029: import org.apache.derby.iapi.services.daemon.*;
030:
031: import java.util.Random;
032: import java.util.Vector;
033:
034: /**
035: This test exercices the DaemonFactory and DaemonService implementation
036: */
037: public class T_DaemonService extends T_MultiThreadedIterations {
038: private static DaemonService testDaemon;
039: private static Random random;
040:
041: /*
042: * fields for testing serviceable, one per test object
043: */
044: private Vector serviceRecord; // a vectory of T_Serviceable
045:
046: public T_DaemonService() {
047: super ();
048: serviceRecord = new Vector(9, 1);
049: random = new Random();
050: }
051:
052: /*
053: ** Methods required by T_Generic
054: */
055:
056: protected String getModuleToTestProtocolName() {
057: return org.apache.derby.iapi.reference.Module.DaemonFactory;
058: }
059:
060: /**
061: ** Methods required by T_MultiIterations
062: ** @exception T_Fail unexpected behaviour from the API
063: */
064: protected void setupTest() throws T_Fail {
065:
066: DaemonFactory daemonFactory;
067: try {
068: daemonFactory = (DaemonFactory) Monitor
069: .startSystemModule(org.apache.derby.iapi.reference.Module.DaemonFactory);
070: } catch (StandardException mse) {
071: throw T_Fail.exceptionFail(mse);
072: }
073: if (daemonFactory == null)
074: throw T_Fail
075: .testFailMsg("cannot find daemon factory "
076: + org.apache.derby.iapi.reference.Module.DaemonFactory);
077:
078: try {
079: testDaemon = daemonFactory.createNewDaemon("testDaemon");
080: } catch (StandardException se) {
081: throw T_Fail.exceptionFail(se);
082: }
083: if (testDaemon == null)
084: throw T_Fail
085: .testFailMsg("cannot create new Daemon Service");
086:
087: }
088:
089: /**
090: ** Methods required by T_MultiThreadedIterations
091: ** @exception T_Fail unexpected behaviour from the API
092: */
093: protected void joinSetupTest() throws T_Fail {
094: if (testDaemon == null)
095: throw T_Fail.testFailMsg("test deamon not set");
096: }
097:
098: protected T_MultiThreadedIterations newTestObject() {
099: return new T_DaemonService(); // clone myself
100: }
101:
102: /**
103: @exception T_Fail - test failed
104: */
105: protected void runTestSet() throws T_Fail {
106: // we don't want t_checkStatus() to hang because of
107: // unsubscribed records from a previous, failed iteration
108: // (DERBY-989)
109: serviceRecord.clear();
110:
111: try {
112: /* test basic DaemonService interface */
113: T01(testDaemon); // basic subscription
114: T02(testDaemon); // basic enqueue
115: T03(testDaemon); // mixture of everything
116:
117: t_checkStatus(testDaemon); // make sure all serviceables I created got serviced
118: } catch (StandardException se) {
119: throw T_Fail.exceptionFail(se);
120: }
121:
122: }
123:
124: /*
125: * tests
126: */
127:
128: /* test 1 - basic subscription */
129: private void T01(DaemonService daemon) throws T_Fail,
130: StandardException {
131: // add a couple of subscriptions to the deamon
132: T_Serviceable s1 = new T_Serviceable(false); // not on demand
133: serviceRecord.addElement(s1);
134: int clientNumber1 = daemon.subscribe(s1, false);
135: s1.setClientNumber(clientNumber1);
136:
137: T_Serviceable s2 = new T_Serviceable(true); // on demand only
138: serviceRecord.addElement(s2);
139: int clientNumber2 = daemon.subscribe(s2, true);
140: s2.setClientNumber(clientNumber2);
141:
142: daemon.serviceNow(clientNumber2); // s2 should be serviced exactly once
143:
144: s2.t_wait(1); // wait for s2 to be serviced
145:
146: randomSleep();
147:
148: // don't demand service, let daemon service it by itself
149: s1.t_wait(1); // wait for s1 to be serviced
150:
151: s2.t_check(1); // s2 should be serviced exactly once
152:
153: PASS("T01");
154:
155: randomSleep();
156: }
157:
158: /* test 1 - basic enqueue */
159: private void T02(DaemonService daemon) throws T_Fail,
160: StandardException {
161: int requeue = 10;
162:
163: T_Serviceable e1 = new T_Serviceable(1); // service now and don't requeue
164: serviceRecord.addElement(e1);
165: daemon.enqueue(e1, true);
166:
167: T_Serviceable e2 = new T_Serviceable(requeue); // service now and requeue
168: serviceRecord.addElement(e2);
169: daemon.enqueue(e2, true);
170:
171: T_Serviceable e3 = new T_Serviceable(1); // don't requeue
172: serviceRecord.addElement(e3);
173: daemon.enqueue(e3, false);
174:
175: T_Serviceable e4 = new T_Serviceable(requeue); // requeue
176: serviceRecord.addElement(e4);
177: daemon.enqueue(e4, false);
178:
179: randomSleep();
180:
181: e1.t_wait(1); // make sure they are all serviced at least once
182: e2.t_wait(1);
183: e3.t_wait(1);
184: e4.t_wait(1);
185:
186: e2.t_wait(requeue); // e2 and e4 are requeued
187: e4.t_wait(requeue); // e2 and e4 are requeued
188:
189: // meanwhile, e1 and e3 should not be service more than once
190: e1.t_check(1);
191: e3.t_check(1);
192:
193: PASS("T02");
194:
195: randomSleep();
196: }
197:
198: /* test 4 - mixture */
199: private void T03(DaemonService daemon) throws T_Fail,
200: StandardException {
201: T_Serviceable s1 = new T_Serviceable(false); // unsubscribe this laster
202: serviceRecord.addElement(s1);
203: int sub1 = daemon.subscribe(s1, false);
204:
205: T_Serviceable e1 = new T_Serviceable(1);
206: serviceRecord.addElement(e1);
207: daemon.enqueue(e1, false); // enqueue the same thing 5 times
208: daemon.enqueue(e1, false);
209: daemon.enqueue(e1, false);
210: daemon.enqueue(e1, false);
211: daemon.enqueue(e1, false);
212:
213: T_Serviceable s2 = new T_Serviceable(false); // not on demand
214: serviceRecord.addElement(s2);
215: int sub2 = daemon.subscribe(s2, false);
216: int realsub2 = daemon.subscribe(s2, false);
217: s2.setClientNumber(realsub2);
218:
219: daemon.unsubscribe(sub1);
220: daemon.unsubscribe(sub2); // it has another subscriptions
221:
222: int save;
223: synchronized (s1) {
224: save = s1.timesServiced;
225: }
226: daemon.serviceNow(sub1); // should be silently igored
227:
228: randomSleep();
229:
230: e1.t_wait(5); // it is enqueued 5 times, it should be serviced 5 times
231:
232: daemon.serviceNow(sub1); // should be silently igored
233:
234: s2.t_wait(3); // wait long enough for it to be serviced at least 3 times
235:
236: daemon.serviceNow(sub1); // should be silently igored
237:
238: synchronized (s1) {
239: // DERBY-989: The client should not be serviced after it
240: // unsubscribes. However, it might have been in the
241: // process of being serviced when unsubscribe() was
242: // called. Therefore, performWork() can run even after the
243: // save variable was initialized, but only once.
244: int diff = s1.timesServiced - save;
245: // Check that the client has not been serviced more than
246: // once after it unsubscribed.
247: T_Fail.T_ASSERT((diff == 0 || diff == 1),
248: "unsubscribed continue to get serviced");
249:
250: // unsubscribed can subscribe again
251: s1.timesServiced = 0;
252: }
253:
254: sub1 = daemon.subscribe(s1, false); // resubscribe
255: s1.setClientNumber(sub1);
256: daemon.serviceNow(sub1);
257: s1.t_wait(1);
258:
259: // e1 should not be serviced for > 5 times
260: e1.t_check(5);
261:
262: PASS("T03");
263: randomSleep();
264:
265: }
266:
267: private void t_checkStatus(DaemonService daemon) throws T_Fail {
268: for (int i = 0; i < serviceRecord.size(); i++) {
269: T_Serviceable check = (T_Serviceable) serviceRecord
270: .elementAt(i);
271: if (check != null) {
272: if (check.subscribed) {
273: if (check.onDemandOnly)
274: check.t_check(1);
275: else
276: check.t_wait(10); // sooner or later, it will be serviced this many times
277:
278: daemon.unsubscribe(check.getClientNumber());
279: } else // enqueued
280: {
281: check.t_wait(check.timesRequeue);
282: }
283: }
284: }
285: PASS("T_CheckStatus");
286: }
287:
288: private void randomSleep() throws StandardException {
289: // randomly sleep for a bit if this is a multi-threaded test to make it more interesting
290: if (getNumThreads() > 1) {
291: int nap = random.nextInt() % 100;
292: if (nap < 0)
293: nap = -nap;
294: try {
295: Thread.sleep(nap);
296: } catch (InterruptedException ie) {
297: throw StandardException.interrupt(ie);
298: }
299: }
300: }
301:
302: }
|