001: /*
002: * All content copyright (c) 2003-2007 Terracotta, Inc., except as may otherwise be noted in a separate copyright
003: * notice. All rights reserved.
004: */
005: package com.tctest;
006:
007: import EDU.oswego.cs.dl.util.concurrent.CyclicBarrier;
008:
009: import com.tc.management.JMXConnectorProxy;
010: import com.tc.management.beans.L2MBeanNames;
011: import com.tc.management.beans.TCServerInfoMBean;
012: import com.tc.net.proxy.TCPProxy;
013: import com.tc.object.config.ConfigVisitor;
014: import com.tc.object.config.DSOClientConfigHelper;
015: import com.tc.object.config.TransparencyClassSpec;
016: import com.tc.objectserver.control.ServerControl;
017: import com.tc.simulator.app.ApplicationConfig;
018: import com.tc.simulator.listener.ListenerProvider;
019: import com.tc.util.Assert;
020: import com.tc.util.TCAssertionError;
021: import com.tctest.runner.AbstractErrorCatchingTransparentApp;
022:
023: import java.io.IOException;
024: import java.util.Random;
025:
026: import javax.management.MBeanServerConnection;
027: import javax.management.MBeanServerInvocationHandler;
028: import javax.management.remote.JMXConnector;
029:
030: public class ResolveTwoActiveServersTestApp extends
031: AbstractErrorCatchingTransparentApp {
032: private String[] myArrayTestRoot;
033: final private String[] stringAry = { "hee", "hoo", "haa",
034: "terracotta", "google", "yahoo", "apple" };
035: final private static long runtime = 1000 * 200;
036: private final CyclicBarrier barrier = new CyclicBarrier(
037: getParticipantCount());
038:
039: private final ServerControl[] serverControls;
040: private final TCPProxy[] proxies;
041: private final JMXConnector[] jmxConnectors;
042:
043: public ResolveTwoActiveServersTestApp(String appId,
044: ApplicationConfig cfg, ListenerProvider listenerProvider) {
045: super (appId, cfg, listenerProvider);
046:
047: myArrayTestRoot = new String[] { "hee", "hoo", "haa",
048: "terracotta", "google", "yahoo", "apple" };
049:
050: proxies = cfg.getProxies();
051: serverControls = cfg.getServerControls();
052: Assert.assertNotNull(proxies);
053: Assert.assertNotNull(serverControls);
054: Assert.assertEquals(serverControls.length, 2);
055:
056: jmxConnectors = new JMXConnector[2];
057: }
058:
059: public void runTest() throws Exception {
060: final boolean isMasterNode = barrier.barrier() == 0;
061:
062: println("Starting app work thread...");
063:
064: Thread t = new Thread(new Runnable() {
065: public void run() {
066: doWork();
067: }
068: });
069: t.setName("app-work");
070: t.start();
071:
072: println("App work thread started.");
073:
074: Thread.sleep(5 * 1000);
075:
076: if (isMasterNode) {
077: createJMXConnectors();
078: ensureActiveServer(0);
079: ensurePassiveServer(1);
080: disconnectServers();
081: ensureActiveServer(0);
082: ensureActiveServer(1);
083: connectServers();
084: ensureActiveServer(0);
085: ensureDeadServer(1);
086: }
087:
088: barrier.barrier();
089:
090: println("Waiting for app work thread to finish...");
091: t.join();
092:
093: cleanUp();
094: }
095:
096: public void cleanUp() throws IOException {
097: for (int i = 0; i < proxies.length; i++) {
098: proxies[i].stop();
099: }
100:
101: for (int i = 0; i < jmxConnectors.length; i++) {
102: jmxConnectors[i].close();
103: }
104: }
105:
106: private void connectServers() throws IOException {
107: for (int i = 0; i < proxies.length; i++) {
108: proxies[i].start();
109: }
110: }
111:
112: private void disconnectServers() throws IOException {
113: for (int i = 0; i < proxies.length; i++) {
114: proxies[i].fastStop();
115: }
116:
117: MBeanServerConnection mBeanServer = jmxConnectors[1]
118: .getMBeanServerConnection();
119: TCServerInfoMBean m = (TCServerInfoMBean) MBeanServerInvocationHandler
120: .newProxyInstance(mBeanServer,
121: L2MBeanNames.TC_SERVER_INFO,
122: TCServerInfoMBean.class, true);
123: while (true) {
124: if (m.isActive()) {
125: break;
126: }
127: }
128: }
129:
130: private void ensureDeadServer(int index) throws Exception {
131: if (serverControls[index].isRunning()) {
132: throw new Exception(
133: "Server control is still running when it should not be!");
134: }
135: try {
136: ensureActiveServer(index);
137: throw new Exception(
138: "The server is active when it should not even be running!");
139: } catch (IOException e) {
140: // expected
141: } catch (TCAssertionError tce) {
142: throw new Exception(
143: "The server is passive/started when it should not even be running!");
144: }
145: }
146:
147: private void ensurePassiveServer(int index) throws IOException {
148: TCServerInfoMBean m = getJmxServer(index);
149: Assert.assertTrue(m.isPassiveStandby());
150: }
151:
152: private void ensureActiveServer(int index) throws IOException {
153: MBeanServerConnection mBeanServer = jmxConnectors[index]
154: .getMBeanServerConnection();
155: TCServerInfoMBean m = (TCServerInfoMBean) MBeanServerInvocationHandler
156: .newProxyInstance(mBeanServer,
157: L2MBeanNames.TC_SERVER_INFO,
158: TCServerInfoMBean.class, true);
159: Assert.assertTrue(m.isActive());
160: }
161:
162: private TCServerInfoMBean getJmxServer(int index)
163: throws IOException {
164: MBeanServerConnection mBeanServer = jmxConnectors[index]
165: .getMBeanServerConnection();
166: return (TCServerInfoMBean) MBeanServerInvocationHandler
167: .newProxyInstance(mBeanServer,
168: L2MBeanNames.TC_SERVER_INFO,
169: TCServerInfoMBean.class, true);
170: }
171:
172: private void createJMXConnectors() {
173: for (int i = 0; i < serverControls.length; i++) {
174: jmxConnectors[i] = new JMXConnectorProxy("localhost",
175: serverControls[i].getAdminPort());
176: }
177: }
178:
179: private void println(String s) {
180: System.out.println(s);
181: }
182:
183: // app work related code
184: private void doWork() {
185: Random rand = new Random();
186: long end = System.currentTimeMillis() + runtime;
187: try {
188: while (end > System.currentTimeMillis()) {
189: synchronized (myArrayTestRoot) {
190: int idx = rand.nextInt(myArrayTestRoot.length);
191: // System.out.println(myArrayTestRoot[rand.nextInt(myArrayTestRoot.length)]);
192: Assert.assertTrue(myArrayTestRoot[idx]
193: .equals(stringAry[idx]));
194: }
195: Thread.sleep((int) (Math.random() * 10));
196: }
197: } catch (Exception e) {
198: e.printStackTrace();
199: }
200:
201: arrayIndexTestCase();
202:
203: testNullArrayAccess();
204: }
205:
206: private void testNullArrayAccess() {
207: Object[] o = null;
208:
209: try {
210: if (o[3] == null) {
211: throw new AssertionError();
212: }
213: } catch (NullPointerException npe) {
214: // expecte
215: }
216: }
217:
218: private void arrayIndexTestCase() {
219: // We had a bug where ArrayIndexOutOfBoundsException failed to release a monitor, this is the test case for it
220: try {
221: for (int i = 0; true; i++) {
222: Object o = myArrayTestRoot[i];
223:
224: // silence warning about unread local variable
225: if (o == null) {
226: continue;
227: }
228: }
229: } catch (ArrayIndexOutOfBoundsException aioobe) {
230: //
231: }
232:
233: try {
234: Object o = myArrayTestRoot[-1];
235: if (true || o == o) {
236: throw new AssertionError();
237: }
238: } catch (ArrayIndexOutOfBoundsException aioobe) {
239: //
240: }
241:
242: }
243:
244: public void setArray(String[] blah) {
245: myArrayTestRoot = blah;
246: }
247:
248: public static void visitL1DSOConfig(ConfigVisitor visitor,
249: DSOClientConfigHelper config) {
250: String testClass = ArrayTestApp.class.getName();
251: TransparencyClassSpec spec = config.getOrCreateSpec(testClass);
252:
253: String methodExpression = "* " + testClass + "*.*(..)";
254: config.addWriteAutolock(methodExpression);
255: spec.addRoot("myArrayTestRoot", "myArrayTestRoot");
256:
257: }
258: }
|