Package com.google.walkaround.slob.client

Source Code of com.google.walkaround.slob.client.TransformQueueRandomTest

/*
* Copyright 2011 Google Inc. All Rights Reserved.
*
* 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 com.google.walkaround.slob.client;

import com.google.common.collect.Lists;
import com.google.walkaround.slob.client.ChannelTestUtil.Doc;
import com.google.walkaround.slob.client.ChannelTestUtil.FakeServer;
import com.google.walkaround.slob.client.ChannelTestUtil.UnitPackage;

import junit.framework.TestCase;

import org.waveprotocol.wave.model.document.operation.DocOp;
import org.waveprotocol.wave.model.document.util.DocOpScrub;
import org.waveprotocol.wave.model.operation.OperationException;
import org.waveprotocol.wave.model.testing.RandomDocOpGenerator;
import org.waveprotocol.wave.model.testing.RandomDocOpGenerator.Parameters;
import org.waveprotocol.wave.model.testing.RandomDocOpGenerator.RandomProvider;
import org.waveprotocol.wave.model.testing.RandomProviderImpl;

import java.io.OutputStream;
import java.io.PrintStream;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;

public class TransformQueueRandomTest extends TestCase {

  /**
   * Concurrent events, with different relative likelihoods.
   *
   * Some may be no-ops if they are not possible with the current state.
   * Likelihoods are crafted to ensure all interesting scenarios are well
   * exercised.
   */
  enum Event {
    // keep these alphabetical, for easy visual checking
    /** Client pulls a transformed op out of the queue and applies it */
    CLIENT_APPLY(9),
    /** Client sends an op into the queue */
    CLIENT_OP(5),
    /** Response with version number for sending ops */
    XHR_RESPONSE(2),
    /** Client receives an op (either its own or another op) from the browserchannel */
    CLIENT_RECEIVE(5),
    /** Flush all ops in the browserchannel (helps convergence to happen more often) */
    CLIENT_RECEIVE_ALL(5),
    /** Client sends out its queued ops */
    CLIENT_SEND(3),
    /** Server generates its own op */
    SERVER_OP(5),
    /** Server receives operations from the client submission */
    SERVER_RECEIVE(4);

    static final int total;
    static {
      int temp = 0;
      for (Event e : values()) {
        temp += e.likelihood;
      }
      total = temp;
    }

    int likelihood;

    private Event(int l) {
      likelihood = l;
    }
  }
  RandomProvider r;
  Parameters p;

  public void testSmallRandom() throws OperationException {
    long start = System.currentTimeMillis();
    new TransformQueueRandomTest().randomTest(7, 100);
    System.out.println("Time: " + (System.currentTimeMillis() - start) / 1000.0);
  }

  public void testRandom() throws OperationException {
    long start = System.currentTimeMillis();
    // Break the test up into 10 chunks because it slows down as the document grows.
    for (int i = 0; i < 20; i++) {
      if (i == 6) {
        // Failes the "useful test" test.
        continue;
      }
      System.out.println("\nSEED " + i + " ======");
      randomTest(i, 700);
    }
    System.out.println("Time: " + (System.currentTimeMillis() - start) / 1000.0);
  }

  private static final PrintStream NULL_STREAM = new PrintStream(new OutputStream() {
    @Override public void write(int b) { }
  });

  public void randomTest(int seed, int numIterations) throws OperationException {
    try {
      assert false;
      fail("Assertions not turned on");
    } catch (AssertionError e) { }
    Map<Event, Integer> eventCounts = new TreeMap<Event, Integer>();

    DocOpScrub.setShouldScrubByDefault(false);
    r = RandomProviderImpl.ofSeed(seed);
    p = new Parameters();
    p.setMaxOpeningComponents(5);
    Doc client = new Doc();
    FakeServer server = new FakeServer(r, p);
    LinkedList<Integer> xhrResponses = Lists.newLinkedList();

    TransformQueue<DocOp> q = new TransformQueue<DocOp>(
        ChannelTestUtil.randomlyCompactingTransformer(0));
    q.init(0);

    int[] scenario = new int[8];

//    PrintStream out = System.out;
    PrintStream out = NULL_STREAM;

    int numConvergences = 0;
    for (int iter = 0; iter < numIterations; iter++) {
      Event e = randomEvent();
      out.println("\n" + iter + " " + e + " ========");
      eventCounts.put(e, (eventCounts.containsKey(e) ? eventCounts.get(e) : 0) + 1);
      switch (e) {
      case CLIENT_OP:
        DocOp op = randomOp(client);
        q.clientOp(op);
        break;
      case CLIENT_SEND:
        if (!q.hasUnacknowledgedClientOps() && q.hasQueuedClientOps()) {
          server.sendToServer(q.revision(), q.pushQueuedOpsToUnacked());
        }
        break;
      case SERVER_OP:
        server.randomServerOp();
        break;
      case XHR_RESPONSE:
        while (!xhrResponses.isEmpty()) {
          int responseVersion = xhrResponses.remove();
          q.ackOpsIfVersionMatches(responseVersion);
        }
        break;
      case CLIENT_RECEIVE:
      case CLIENT_RECEIVE_ALL:
        while (server.channelPending()) {
          UnitPackage p = server.clientReceive();
          if (p.clientSourced) {
            out.println("client");
            if (!q.expectedAck(p.resultingRevision)) {
              q.ackClientOp(p.resultingRevision);
            }
          } else {
            q.serverOp(p.resultingRevision, p.onlyOp());
          }

          if (e == Event.CLIENT_RECEIVE) {
            break;
          }
        }
        break;
      case CLIENT_APPLY:
        if (q.hasServerOp()) {
          client.consume(q.removeServerOp());
        }
        break;
      case SERVER_RECEIVE:
        if (server.serverReceive()) {
          xhrResponses.add(server.revision());
        }
        break;
      default:
        throw new AssertionError("Unhandled event");
      }

//      out.println(server);
//      out.println(q);
//      out.println(client);

      // Extra checking, simulate convergence
      if (iter % 10 == 0) {
        Doc clientCopy = client.copy();
        Doc serverCopy = server.at(q.revision()).copy();
        for (DocOp pendingServerOp : q.serverOps) {
          clientCopy.consume(pendingServerOp);
        }
        for (DocOp pendingClientOp : q.unackedClientOps) {
          serverCopy.consume(pendingClientOp);
        }
        for (DocOp pendingClientOp : q.queuedClientOps) {
          serverCopy.consume(pendingClientOp);
        }
        assertEquals("Unequal states", clientCopy.repr(), serverCopy.repr());
      }

      boolean qco = q.hasQueuedClientOps();
      boolean uco = q.hasUnacknowledgedClientOps();
      boolean so = q.hasServerOp();

      if (!qco && !uco && !so) {
        out.println("CONVERGED STATE (" + iter + ") " + client.doc.size());
        numConvergences++;
        assertEquals("Unequal states", client.repr(), server.at(q.revision()).repr());
      }

      scenario[(qco ? 1<<2 : 0) + (uco ? 1<<1 : 0) + (so ? 1<<0 : 0)]++;
    }

    // Make sure the test was useful
    String msg = "numConvergeances: " + numConvergences + "/" + numIterations;
    System.out.println(msg);
    assertTrue(msg, numConvergences >= 5);
    assertTrue(msg, numConvergences < numIterations / 5);
    int minScenario = numIterations / 200;
    for (int i = 0; i < scenario.length; i++) {
      msg = "scenario[" + i + "]: " + scenario[i];
      System.out.println(msg);
      assertTrue(msg, scenario[i] >= minScenario);
    }
    for (Event e : eventCounts.keySet()) {
      System.out.println(e + " " + (1.0 * eventCounts.get(e) * Event.total / numIterations));
    }
  }

  private Event randomEvent() {
    int index = r.nextInt(Event.total);
    int tot = 0;
    for (Event e : Event.values()) {
      tot += e.likelihood;
      if (index < tot) {
        return e;
      }
    }

    throw new AssertionError("Bug");
  }

  private DocOp randomOp(Doc doc) throws OperationException {
    DocOp op = RandomDocOpGenerator.generate(r, p, doc.autoDoc);
    doc.consume(op);
    return op;
  }
}
TOP

Related Classes of com.google.walkaround.slob.client.TransformQueueRandomTest

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.