/*
*
*
* Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 only, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License version 2 for more details (a copy is
* included at /legal/license.txt).
*
* You should have received a copy of the GNU General Public License
* version 2 along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 or visit www.sun.com if you need additional
* information or have any questions.
*/
package com.sun.midp.content;
import com.sun.midp.i3test.TestCase;
import java.util.Random;
import com.sun.midp.content.InvocationStore;
import com.sun.midp.content.InvocationImpl;
import javax.microedition.content.Invocation;
/**
* A test thread to pound on the InvocationStore.
*/
class InvocStoreStress implements Runnable {
/** The thread that is running this Stress case. */
Thread thread;
/** The application ID consumed by this thread. */
int appID;
/** The classname consumed by this thread. */
String classname;
/** The number of applicationIDs to target. */
int nappIDs;
/** The number of content handlers per applicationID. */
int nclassnames;
/** Flag to stop this thread. */
boolean stopping;
/** The maximum number of iterations. */
int maxInvokes = 5;
/** Number of invocations queued by this test. */
int numInvokes;
/** Number of responses to invocations. */
int numResponses;
/** The TestCase to handle the assertions. */
TestCase testcase;
/** The random number generator. */
Random random;
/** Counters for received responses. */
int[] scorecard = new int[maxInvokes];
/** Number of terminations pending to be received; zero = done. */
int numTerminations;
/** The application to stress. */
AppProxy appl;
/**
* Construct a new test thread with parameters.
* @param appNdx index of this application's id
* @param handlerNdx index of this application's classname
* @param nappids number of applications ids to generate
* @param nclassnames number of classnames to generate
* @param testcase to use for asserts
*/
InvocStoreStress(int appNdx, int handlerNdx, int nappids, int nclassnames,
TestCase testcase, AppProxy appl ) {
this.appID = getAppID(appNdx);
this.classname = getClassname(handlerNdx);
this.nappIDs = nappids;
this.nclassnames = nclassnames;
this.testcase = testcase;
this.appl = appl;
random = new Random(47); // To get a consistent start for tests
}
/**
* Stop this thread and cleanup.
*/
void stop() {
stopping = true;
}
/**
* Run the test.
*/
public void run() {
try {
if (thread == null) {
thread = Thread.currentThread();
numTerminations = nappIDs * nclassnames;
// Start a thread for the responder side
new Thread(this).start();
doInvoker();
} else {
doResponder();
}
} catch (Throwable t) {
testcase.assertNull("Unexpected exception", t);
t.printStackTrace();
}
}
/**
* Generate new requests as needed and tally the response.
* The final invoke is the termination request/response.
*/
void doInvoker() {
InvocationImpl request = new InvocationImpl();
while (numTerminations > 0) {
int rand = nextRandom(10);
if (numInvokes < maxInvokes &&
(numResponses == numInvokes || (rand < 5))) {
// produce a new INIT request for a random app, class
int targetid = nextRandom(nappIDs);
int targetcn = nextRandom(nclassnames);
request.suiteId = getAppID(targetid);
request.classname = getClassname(targetcn);
request.invokingSuiteId = appID;
request.invokingClassname = classname;
request.responseRequired = true;
request.ID = Integer.toString(numInvokes);
request.status = Invocation.INIT;
int wait = nextRandom(500);
sleep(wait);
InvocationStore.put(request);
++numInvokes;
println("invoke: +" + wait + " ", request);
}
// Consume a response; block until some
InvocationImpl response = new InvocationImpl();
response = InvocationStore.getResponse(response,
appID, classname, true);
if (response != null) {
if (response.status == Invocation.OK) {
testcase.assertEquals(appID +
" verify target appID",
appID, response.suiteId);
testcase.assertEquals(appID +
" verify target classname",
classname, response.classname);
println("response", response);
if ("terminate".equals(response.action)) {
numTerminations--;
} else {
// Keep track of responses
scorecard[Integer.parseInt(response.ID)] += 1;
++numResponses;
/*
* If just finished receiving the max responses;
* send the terminations
*/
if (numResponses == maxInvokes) {
sendAll(Invocation.INIT, "terminate");
}
}
} else {
testcase.assertNull(appID + " illegal response:",
response);
}
}
}
sleep(2000L);
do {
request = InvocationStore.getResponse(new InvocationImpl(),
appID, classname, false);
} while (request != null);
// Terminate responder thread
stop();
// Verify that every invocation received a response.
testcase.assertEquals(appID + " verify each invoke got a response",
numInvokes, numResponses);
for (int i = 0; i < maxInvokes; i++) {
testcase.assertEquals(appID + " verify received a response " + i,
1, scorecard[i]);
}
}
/**
* Handle and respond to any response that comes back.
*/
void doResponder() {
InvocationImpl request;
while (!stopping) {
// consume any request and send a response
request = InvocationStore.getRequest(appID, classname, true);
if (request != null) {
testcase.assertEquals("verify only ACTIVE requests",
Invocation.ACTIVE, request.status);
testcase.assertTrue("verify responseRequired",
request.responseRequired);
// An ACTIVE request; send a reply
request.status = Invocation.OK;
InvocationStore.setStatus(request);
println("reply: ", request);
}
}
}
/**
* Send a request to every other consumer.
* @param status a status to send
* @param action an action string to send
*/
void sendAll(int status, String action) {
InvocationImpl request = new InvocationImpl();
request.invokingSuiteId = appID;
request.invokingClassname = classname;
request.status = status;
request.action = action;
request.ID = Integer.toString(numInvokes);
for (int i = 0; i < nappIDs; i++) {
for (int j = 0; j < nclassnames; j++) {
request.suiteId = getAppID(i);
request.classname = getClassname(j);
InvocationStore.put(request);
println("sending terminate", request);
}
}
}
/**
* Sleep a bit.
* @param millis millseconds to sleep
*/
void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ie) {
}
}
/**
* Generate the application ID for app(n).
* @param n the index of the applicationid.
* @return the string application id.
*/
int getAppID(int n) {
return n + 1000;
}
/**
* Generate the classname for content handler (n).
* @param n the index of the content handler.
* @return the string classname
*/
String getClassname(int n) {
return "class-".concat(Integer.toString(n));
}
/**
* Print the interesting fields of an Invocation.
* @param msg a message to print before the invocation
* @param invoc an Invocation
*/
void println(String msg, InvocationImpl invoc) {
if (false) {
System.out.println(appID + " " + msg +
": status = " + invoc.status +
", tid: " + invoc.tid +
", target " + invoc.suiteId +
", action = " + invoc.action);
}
}
/**
* Generate the next random number between 0 (inclusive)
* and max (exclusive).
* @param n limit numbers from 0 to n-1.
* @return a random number
*/
private int nextRandom(int n) {
int val = random.nextInt() % n;
if (val < 0) {
val = -val;
}
return val;
}
}
|