001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package com.sun.midp.content;
028:
029: import com.sun.midp.i3test.TestCase;
030:
031: import java.util.Random;
032:
033: import com.sun.midp.content.InvocationStore;
034: import com.sun.midp.content.InvocationImpl;
035:
036: import javax.microedition.content.Invocation;
037:
038: /**
039: * A test thread to pound on the InvocationStore.
040: */
041: class InvocStoreStress implements Runnable {
042: /** The thread that is running this Stress case. */
043: Thread thread;
044: /** The application ID consumed by this thread. */
045: int appID;
046: /** The classname consumed by this thread. */
047: String classname;
048: /** The number of applicationIDs to target. */
049: int nappIDs;
050: /** The number of content handlers per applicationID. */
051: int nclassnames;
052: /** Flag to stop this thread. */
053: boolean stopping;
054: /** The maximum number of iterations. */
055: int maxInvokes = 5;
056: /** Number of invocations queued by this test. */
057: int numInvokes;
058: /** Number of responses to invocations. */
059: int numResponses;
060: /** The TestCase to handle the assertions. */
061: TestCase testcase;
062: /** The random number generator. */
063: Random random;
064: /** Counters for received responses. */
065: int[] scorecard = new int[maxInvokes];
066: /** Number of terminations pending to be received; zero = done. */
067: int numTerminations;
068: /** The application to stress. */
069: AppProxy appl;
070:
071: /**
072: * Construct a new test thread with parameters.
073: * @param appNdx index of this application's id
074: * @param handlerNdx index of this application's classname
075: * @param nappids number of applications ids to generate
076: * @param nclassnames number of classnames to generate
077: * @param testcase to use for asserts
078: */
079: InvocStoreStress(int appNdx, int handlerNdx, int nappids,
080: int nclassnames, TestCase testcase, AppProxy appl) {
081: this .appID = getAppID(appNdx);
082: this .classname = getClassname(handlerNdx);
083: this .nappIDs = nappids;
084: this .nclassnames = nclassnames;
085: this .testcase = testcase;
086: this .appl = appl;
087: random = new Random(47); // To get a consistent start for tests
088: }
089:
090: /**
091: * Stop this thread and cleanup.
092: */
093: void stop() {
094: stopping = true;
095: }
096:
097: /**
098: * Run the test.
099: */
100: public void run() {
101: try {
102: if (thread == null) {
103: thread = Thread.currentThread();
104: numTerminations = nappIDs * nclassnames;
105: // Start a thread for the responder side
106: new Thread(this ).start();
107: doInvoker();
108: } else {
109: doResponder();
110: }
111: } catch (Throwable t) {
112: testcase.assertNull("Unexpected exception", t);
113: t.printStackTrace();
114: }
115: }
116:
117: /**
118: * Generate new requests as needed and tally the response.
119: * The final invoke is the termination request/response.
120: */
121: void doInvoker() {
122: InvocationImpl request = new InvocationImpl();
123: while (numTerminations > 0) {
124: int rand = nextRandom(10);
125: if (numInvokes < maxInvokes
126: && (numResponses == numInvokes || (rand < 5))) {
127: // produce a new INIT request for a random app, class
128: int targetid = nextRandom(nappIDs);
129: int targetcn = nextRandom(nclassnames);
130: request.suiteId = getAppID(targetid);
131: request.classname = getClassname(targetcn);
132: request.invokingSuiteId = appID;
133: request.invokingClassname = classname;
134: request.responseRequired = true;
135: request.ID = Integer.toString(numInvokes);
136: request.status = Invocation.INIT;
137: int wait = nextRandom(500);
138: sleep(wait);
139: InvocationStore.put(request);
140: ++numInvokes;
141: println("invoke: +" + wait + " ", request);
142: }
143:
144: // Consume a response; block until some
145: InvocationImpl response = new InvocationImpl();
146: response = InvocationStore.getResponse(response, appID,
147: classname, true);
148: if (response != null) {
149: if (response.status == Invocation.OK) {
150: testcase.assertEquals(appID
151: + " verify target appID", appID,
152: response.suiteId);
153: testcase.assertEquals(appID
154: + " verify target classname", classname,
155: response.classname);
156: println("response", response);
157:
158: if ("terminate".equals(response.action)) {
159: numTerminations--;
160: } else {
161: // Keep track of responses
162: scorecard[Integer.parseInt(response.ID)] += 1;
163: ++numResponses;
164:
165: /*
166: * If just finished receiving the max responses;
167: * send the terminations
168: */
169: if (numResponses == maxInvokes) {
170: sendAll(Invocation.INIT, "terminate");
171: }
172: }
173: } else {
174: testcase.assertNull(appID + " illegal response:",
175: response);
176: }
177: }
178: }
179:
180: sleep(2000L);
181: do {
182: request = InvocationStore.getResponse(new InvocationImpl(),
183: appID, classname, false);
184: } while (request != null);
185:
186: // Terminate responder thread
187: stop();
188:
189: // Verify that every invocation received a response.
190: testcase.assertEquals(appID
191: + " verify each invoke got a response", numInvokes,
192: numResponses);
193: for (int i = 0; i < maxInvokes; i++) {
194: testcase.assertEquals(appID
195: + " verify received a response " + i, 1,
196: scorecard[i]);
197: }
198: }
199:
200: /**
201: * Handle and respond to any response that comes back.
202: */
203: void doResponder() {
204: InvocationImpl request;
205: while (!stopping) {
206:
207: // consume any request and send a response
208: request = InvocationStore
209: .getRequest(appID, classname, true);
210: if (request != null) {
211: testcase.assertEquals("verify only ACTIVE requests",
212: Invocation.ACTIVE, request.status);
213: testcase.assertTrue("verify responseRequired",
214: request.responseRequired);
215:
216: // An ACTIVE request; send a reply
217: request.status = Invocation.OK;
218: InvocationStore.setStatus(request);
219: println("reply: ", request);
220: }
221: }
222: }
223:
224: /**
225: * Send a request to every other consumer.
226: * @param status a status to send
227: * @param action an action string to send
228: */
229: void sendAll(int status, String action) {
230: InvocationImpl request = new InvocationImpl();
231: request.invokingSuiteId = appID;
232: request.invokingClassname = classname;
233: request.status = status;
234: request.action = action;
235: request.ID = Integer.toString(numInvokes);
236:
237: for (int i = 0; i < nappIDs; i++) {
238: for (int j = 0; j < nclassnames; j++) {
239: request.suiteId = getAppID(i);
240: request.classname = getClassname(j);
241: InvocationStore.put(request);
242: println("sending terminate", request);
243: }
244: }
245: }
246:
247: /**
248: * Sleep a bit.
249: * @param millis millseconds to sleep
250: */
251: void sleep(long millis) {
252: try {
253: Thread.sleep(millis);
254: } catch (InterruptedException ie) {
255: }
256: }
257:
258: /**
259: * Generate the application ID for app(n).
260: * @param n the index of the applicationid.
261: * @return the string application id.
262: */
263: int getAppID(int n) {
264: return n + 1000;
265: }
266:
267: /**
268: * Generate the classname for content handler (n).
269: * @param n the index of the content handler.
270: * @return the string classname
271: */
272: String getClassname(int n) {
273: return "class-".concat(Integer.toString(n));
274: }
275:
276: /**
277: * Print the interesting fields of an Invocation.
278: * @param msg a message to print before the invocation
279: * @param invoc an Invocation
280: */
281: void println(String msg, InvocationImpl invoc) {
282: if (false) {
283: System.out.println(appID + " " + msg + ": status = "
284: + invoc.status + ", tid: " + invoc.tid
285: + ", target " + invoc.suiteId + ", action = "
286: + invoc.action);
287: }
288: }
289:
290: /**
291: * Generate the next random number between 0 (inclusive)
292: * and max (exclusive).
293: * @param n limit numbers from 0 to n-1.
294: * @return a random number
295: */
296: private int nextRandom(int n) {
297: int val = random.nextInt() % n;
298: if (val < 0) {
299: val = -val;
300: }
301: return val;
302: }
303:
304: }
|