Package net.sf.katta.client

Source Code of net.sf.katta.client.NodeInteractionTest$TestNodeExecutor$Call

/**
* Copyright 2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.sf.katta.client;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import net.sf.katta.AbstractTest;

import org.apache.hadoop.ipc.VersionedProtocol;
import org.junit.Before;
import org.junit.Test;

/**
* Test for {@link NodeInteraction}.
*/
public class NodeInteractionTest extends AbstractTest {

  private TestProxyProvider _pp;
  private WorkQueueTest.TestShardManager _sm;
  private TestNodeExecutor _ne;
  private Map<String, List<String>> _map;

  @Before
  public void setUp() throws Exception {
    _pp = new TestProxyProvider();
    _sm = new WorkQueueTest.TestShardManager(_pp, 8, 3);
    _ne = new TestNodeExecutor();
    _map = _sm.createNode2ShardsMap(_sm.allShards());
  }

  @Test
  public void testNormalCall() throws Exception {
    Method method = ITestServer.class.getMethod("testMethod", String.class, String[].class);
    Object[] args = new Object[] { "foo", null };
    ClientResult<String> r = new ClientResult<String>(null, _sm.allShards());
    Runnable ni = new NodeInteraction<String>(method, args, 1, "n1", _map, 1, 3, _sm, _ne, r);
    assertEquals("NodeInteraction: call testMethod on n1", ni.toString());
    ni.run();
    assertEquals("ClientResult: 1 results, 0 errors, 3/8 shards", r.toString());
    assertEquals("n1:foo:[s2, s1, s3]", _pp.toString());
    assertEquals("", _ne.toString());
  }

  @Test
  public void testNormalCallNoShardsParam() throws Exception {
    Method method = ITestServer.class.getMethod("testMethodNoShards", String.class);
    Object[] args = new Object[] { "foo" };
    ClientResult<String> r = new ClientResult<String>(null, _sm.allShards());
    Runnable ni = new NodeInteraction<String>(method, args, -1, "n1", _map, 1, 3, _sm, _ne, r);
    assertEquals("NodeInteraction: call testMethodNoShards on n1", ni.toString());
    ni.run();
    assertEquals("ClientResult: 1 results, 0 errors, 3/8 shards", r.toString());
    assertEquals("n1:foo:null", _pp.toString());
    assertEquals("", _ne.toString());
  }

  @Test
  public void testRetries() throws Exception {
    Method method = ITestServer.class.getMethod("failingMethod", String.class, String[].class);
    int maxTryCount = 3;
    Object[] args = new Object[] { "foo", null };
    /*
     * First try to call node n1 with shards s1, s2, s3. TryCount = 1. Node
     * fails.
     */
    ClientResult<String> r = new ClientResult<String>(null, _sm.allShards());
    assertEquals(3, _map.get("n1").size());
    assertTrue(_map.get("n1").contains("s1"));
    assertTrue(_map.get("n1").contains("s2"));
    assertTrue(_map.get("n1").contains("s3"));
    Runnable ni = new NodeInteraction<String>(method, args, 1, "n1", _map, 1, maxTryCount, _sm, _ne, r);
    assertEquals("NodeInteraction: call failingMethod on n1", ni.toString());
    ni.run();
    assertEquals("ClientResult: 0 results, 0 errors, 0/8 shards", r.toString());
    assertEquals("n1:null:null", _pp.toString());
    assertEquals("n3:2:{n3=[s3], n8=[s2, s1]}, n8:2:{n3=[s3], n8=[s2, s1]}", _ne.toString());
    List<NodeInteractionTest.TestNodeExecutor.Call> retriesA = _ne.calls;
    /*
     * Now simulate running the 2 retries. TryCount = 2. Node n3 with shard s3.
     * Node fails.
     */
    _ne = new TestNodeExecutor();
    NodeInteractionTest.TestNodeExecutor.Call call = retriesA.get(0);
    assertEquals("n3", call.node);
    assertEquals(1, call.nodeShardMap.get(call.node).size());
    assertTrue(call.nodeShardMap.get(call.node).contains("s3"));
    r = new ClientResult<String>(null, _sm.allShards());
    ni = new NodeInteraction<String>(method, args, 1, call.node, call.nodeShardMap, 2, maxTryCount, _sm, _ne, r);
    ni.run();
    assertEquals("ClientResult: 0 results, 0 errors, 0/8 shards", r.toString());
    assertEquals("n1:null:null, n3:null:null", _pp.toString());
    assertEquals("n2:3:{n2=[s3]}", _ne.toString());
    NodeInteractionTest.TestNodeExecutor.Call retryB1 = _ne.calls.get(0);
    /*
     * Second retry. TryCount = 2. Node n8 with shards s1, s2. Node fails.
     */
    _ne = new TestNodeExecutor();
    call = retriesA.get(1);
    assertEquals("n8", call.node);
    assertEquals(2, call.nodeShardMap.get(call.node).size());
    assertTrue(call.nodeShardMap.get(call.node).contains("s1"));
    assertTrue(call.nodeShardMap.get(call.node).contains("s2"));
    r = new ClientResult<String>(null, _sm.allShards());
    ni = new NodeInteraction<String>(method, args, 1, call.node, call.nodeShardMap, 2, maxTryCount, _sm, _ne, r);
    ni.run();
    assertEquals("ClientResult: 0 results, 0 errors, 0/8 shards", r.toString());
    assertEquals("n1:null:null, n3:null:null, n8:null:null", _pp.toString());
    assertEquals("n2:3:{n2=[s2], n7=[s1]}, n7:3:{n2=[s2], n7=[s1]}", _ne.toString());
    List<NodeInteractionTest.TestNodeExecutor.Call> retriesB2 = _ne.calls;
    /*
     * Third round of retries. TryCount = 3. No further retry attempts. Node n2
     * with shard s3. Node fails.
     */
    _ne = new TestNodeExecutor();
    assertEquals("n2", retryB1.node);
    assertEquals(1, retryB1.nodeShardMap.get(retryB1.node).size());
    assertTrue(retryB1.nodeShardMap.get(retryB1.node).contains("s3"));
    r = new ClientResult<String>(null, _sm.allShards());
    ni = new NodeInteraction<String>(method, args, 1, retryB1.node, retryB1.nodeShardMap, 3, maxTryCount, _sm, _ne, r);
    ni.run();
    assertEquals("ClientResult: 0 results, 1 errors, 1/8 shards", r.toString());
    assertEquals("n1:null:null, n2:null:null, n3:null:null, n8:null:null", _pp.toString());
    assertEquals("", _ne.toString());
    /*
     * Node n2 with shard s2. TryCount = 3. Node fails.
     */
    _ne = new TestNodeExecutor();
    call = retriesB2.get(0);
    assertEquals("n2", call.node);
    assertEquals(1, call.nodeShardMap.get(call.node).size());
    assertTrue(call.nodeShardMap.get(call.node).contains("s2"));
    r = new ClientResult<String>(null, _sm.allShards());
    ni = new NodeInteraction<String>(method, args, 1, call.node, call.nodeShardMap, 3, maxTryCount, _sm, _ne, r);
    ni.run();
    assertEquals("ClientResult: 0 results, 1 errors, 1/8 shards", r.toString());
    assertEquals("n1:null:null, n2:null:null, n3:null:null, n8:null:null", _pp.toString());
    assertEquals("", _ne.toString());
    /*
     * Node n7 with shard s1. TryCount = 3. Node fails.
     */
    _ne = new TestNodeExecutor();
    call = retriesB2.get(1);
    assertEquals("n7", call.node);
    assertEquals(1, call.nodeShardMap.get(call.node).size());
    assertTrue(call.nodeShardMap.get(call.node).contains("s1"));
    r = new ClientResult<String>(null, _sm.allShards());
    ni = new NodeInteraction<String>(method, args, 1, call.node, call.nodeShardMap, 3, maxTryCount, _sm, _ne, r);
    ni.run();
    assertEquals("ClientResult: 0 results, 1 errors, 1/8 shards", r.toString());
    assertEquals("n1:null:null, n2:null:null, n3:null:null, n7:null:null, n8:null:null", _pp.toString());
    assertEquals("", _ne.toString());
  }

  @Test
  public void testMaxRetries() throws Exception {
    Method method = ITestServer.class.getMethod("failingMethod", String.class, String[].class);
    int maxTryCount = 2;
    Object[] args = new Object[] { "foo", null };
    /*
     * First try to call node n1 with shards s1, s2, s3. TryCount = 1. Node
     * fails.
     */
    ClientResult<String> r = new ClientResult<String>(null, _sm.allShards());
    assertEquals(3, _map.get("n1").size());
    assertTrue(_map.get("n1").contains("s1"));
    assertTrue(_map.get("n1").contains("s2"));
    assertTrue(_map.get("n1").contains("s3"));
    Runnable ni = new NodeInteraction<String>(method, args, 1, "n1", _map, 1, maxTryCount, _sm, _ne, r);
    assertEquals("NodeInteraction: call failingMethod on n1", ni.toString());
    ni.run();
    assertEquals("ClientResult: 0 results, 0 errors, 0/8 shards", r.toString());
    assertEquals("n1:null:null", _pp.toString());
    assertEquals("n3:2:{n3=[s3], n8=[s2, s1]}, n8:2:{n3=[s3], n8=[s2, s1]}", _ne.toString());
    List<NodeInteractionTest.TestNodeExecutor.Call> retriesA = _ne.calls;
    /*
     * Now simulate running the 2 retries. TryCount = 2. Node n3 with shard s3.
     * Node fails.
     */
    _ne = new TestNodeExecutor();
    NodeInteractionTest.TestNodeExecutor.Call call = retriesA.get(0);
    assertEquals("n3", call.node);
    assertEquals(1, call.nodeShardMap.get(call.node).size());
    assertTrue(call.nodeShardMap.get(call.node).contains("s3"));
    r = new ClientResult<String>(null, _sm.allShards());
    ni = new NodeInteraction<String>(method, args, 1, call.node, call.nodeShardMap, 2, maxTryCount, _sm, _ne, r);
    ni.run();
    assertEquals("ClientResult: 0 results, 1 errors, 1/8 shards", r.toString());
    assertEquals("n1:null:null, n3:null:null", _pp.toString());
    assertEquals("", _ne.toString());
  }

  @Test
  public void testRetriesUserClosedResult() throws Exception {
    Method method = TestServer.class.getMethod("failingMethod", String.class, String[].class);
    Object[] args = new Object[] { "foo", null };
    /*
     * Close the result object. Then try to call node n1 with shards s1, s2, s3.
     * TryCount = 1. Node fails. No retries should be attempted.
     */
    ClientResult<String> r = new ClientResult<String>(null, _sm.allShards());
    r.close();
    assertEquals(3, _map.get("n1").size());
    assertTrue(_map.get("n1").contains("s1"));
    assertTrue(_map.get("n1").contains("s2"));
    assertTrue(_map.get("n1").contains("s3"));
    Runnable ni = new NodeInteraction<String>(method, args, 1, "n1", _map, 1, 3, _sm, _ne, r);
    assertEquals("NodeInteraction: call failingMethod on n1", ni.toString());
    ni.run();
    assertEquals("ClientResult: 0 results, 0 errors, 0/8 shards (closed)", r.toString());
    assertEquals("n1:null:null", _pp.toString());
    assertEquals("", _ne.toString());
  }

  @Test
  public void testRetriesPolicyFailure() throws Exception {
    _sm.setShardMapsFail(true);
    Method method = ITestServer.class.getMethod("failingMethod", String.class, String[].class);
    Object[] args = new Object[] { "foo", null };
    /*
     * Try to call node n1 with shards s1, s2, s3. TryCount = 1. Node fails.
     * When attempting to create retry node shard map, policy will throw an
     * exception. Give up on retries and log error.
     */
    ClientResult<String> r = new ClientResult<String>(null, _sm.allShards());
    assertEquals(3, _map.get("n1").size());
    assertTrue(_map.get("n1").contains("s1"));
    assertTrue(_map.get("n1").contains("s2"));
    assertTrue(_map.get("n1").contains("s3"));
    Runnable ni = new NodeInteraction<String>(method, args, 1, "n1", _map, 1, 3, _sm, _ne, r);
    assertEquals("NodeInteraction: call failingMethod on n1", ni.toString());
    ni.run();
    assertEquals("ClientResult: 0 results, 1 errors, 3/8 shards", r.toString());
    assertEquals("net.sf.katta.client.ShardAccessException: Shard 'Test error' is currently not reachable", r
            .getErrors().iterator().next().toString());
    assertEquals("n1:null:null", _pp.toString());
    assertEquals("", _ne.toString());
  }

  @Test
  public void testNoProxy() throws Exception {
    _pp.returnNullFor("n1");
    Method method = ITestServer.class.getMethod("testMethod", String.class, String[].class);
    Object[] args = new Object[] { "foo", null };
    ClientResult<String> r = new ClientResult<String>(null, _sm.allShards());
    Runnable ni = new NodeInteraction<String>(method, args, 1, "n1", _map, 1, 3, _sm, _ne, r);
    assertEquals("NodeInteraction: call testMethod on n1", ni.toString());
    ni.run();
    assertEquals(2, _ne.calls.size());
    // assertEquals("ClientResult: 0 results, 1 errors, 3/8 shards",
    // r.toString());
    assertEquals("", _pp.toString());
    // assertEquals("[net.sf.katta.util.KattaException: No proxy for node: n1]",
    // r.getErrors().toString());
  }

  @Test
  public void testDefensiveArgCopy() throws Exception {
    Method method = ITestServer.class.getMethod("testMethod", String.class, String[].class);
    Object[] args = new Object[] { "OK", null };
    ClientResult<String> r = new ClientResult<String>(null, _sm.allShards());
    Runnable ni = new NodeInteraction<String>(method, args, 1, "n1", _map, 1, 3, _sm, _ne, r);
    assertEquals("NodeInteraction: call testMethod on n1", ni.toString());
    args[0] = "FAIL";
    ni.run();
    assertEquals("ClientResult: 1 results, 0 errors, 3/8 shards", r.toString());
    assertEquals("n1:OK:[s2, s1, s3]", _pp.toString());
    assertEquals("", _ne.toString());
  }

  protected static class TestNodeExecutor implements INodeExecutor {

    protected class Call {
      protected String node;
      protected Map<String, List<String>> nodeShardMap;
      protected int tryCount;

      @Override
      public String toString() {
        return node + ":" + tryCount + ":" + nodeShardMap;
      }
    }

    protected List<Call> calls = new ArrayList<Call>();

    public void execute(String node, Map<String, List<String>> nodeShardMap, int tryCount, int maxTryCount) {
      Call call = new Call();
      call.node = node;
      call.nodeShardMap = nodeShardMap;
      call.tryCount = tryCount;
      calls.add(call);
    }

    @Override
    public String toString() {
      StringBuilder sb = new StringBuilder();
      String sep = "";
      for (Call call : calls) {
        sb.append(sep);
        sb.append(call.toString());
        sep = ", ";
      }
      return sb.toString();
    }
  }

  public interface ITestServer extends VersionedProtocol {
    public String testMethod(String param, String[] shards);

    public String testMethodNoShards(String param);

    public String failingMethod(String param, String[] shards);
  }

  private static class TestServer implements ITestServer, InvocationHandler {

    private String _node;
    private String _param;
    private String[] _shards;

    public TestServer(String node) {
      this._node = node;
    }

    public String testMethod(String param, String[] shards) {
      this._param = param;
      this._shards = shards;
      return "bar";
    }

    public String testMethodNoShards(String param) {
      this._param = param;
      this._shards = null;
      return "bar";
    }

    public String failingMethod(String param, String[] shards) {
      throw new RuntimeException("test exception");
    }

    @Override
    public String toString() {
      return _node + ":" + _param + ":" + (_shards != null ? Arrays.asList(_shards).toString() : "null");
    }

    public long getProtocolVersion(String arg0, long arg1) {
      return 0;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
      String name = method.getName();
      if (name.equals("testMethod")) {
        return testMethod((String) args[0], (String[]) args[1]);
      } else if (name.equals("testMethodNoShards")) {
        return testMethodNoShards((String) args[0]);
      } else if (name.equals("failingMethod")) {
        return failingMethod((String) args[0], (String[]) args[1]);
      } else if (name.equals("toString")) {
        return toString();
      } else {
        throw new RuntimeException("No method '" + name + "' in TestServer");
      }
    }
  }

  public static class TestProxyProvider implements WorkQueueTest.ProxyProvider {

    private Map<String, VersionedProtocol> proxyCache = new HashMap<String, VersionedProtocol>();
    private Map<String, TestServer> serverCache = new HashMap<String, TestServer>();
    private Set<String> returnNullNodes = new HashSet<String>();

    public VersionedProtocol getProxy(String node) {
      if (returnNullNodes.contains(node)) {
        return null;
      }
      VersionedProtocol vp = proxyCache.get(node);
      if (vp != null) {
        return vp;
      }
      TestServer ts = new TestServer(node);
      serverCache.put(node, ts);
      vp = (VersionedProtocol) Proxy.newProxyInstance(this.getClass().getClassLoader(),
              new Class[] { ITestServer.class }, ts);
      proxyCache.put(node, vp);
      return vp;
    }

    public TestServer getServer(String node) {
      return serverCache.get(node);
    }

    protected void returnNullFor(String node) {
      proxyCache.remove(node);
      returnNullNodes.add(node);
    }

    @Override
    public String toString() {
      List<String> nodes = new ArrayList<String>(serverCache.keySet());
      Collections.sort(nodes);
      StringBuilder sb = new StringBuilder();
      String sep = "";
      for (String node : nodes) {
        sb.append(sep);
        sb.append(serverCache.get(node));
        sep = ", ";
      }
      return sb.toString();
    }

  }

}
TOP

Related Classes of net.sf.katta.client.NodeInteractionTest$TestNodeExecutor$Call

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.