Package org.waveprotocol.box.server.robots.operations

Source Code of org.waveprotocol.box.server.robots.operations.BlipOperationServicesTest

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.waveprotocol.box.server.robots.operations;

import com.google.wave.api.BlipData;
import com.google.wave.api.Element;
import com.google.wave.api.ElementType;
import com.google.wave.api.InvalidRequestException;
import com.google.wave.api.JsonRpcResponse;
import com.google.wave.api.OperationRequest;
import com.google.wave.api.OperationType;
import com.google.wave.api.JsonRpcConstant.ParamsProperty;
import com.google.wave.api.OperationRequest.Parameter;
import com.google.wave.api.data.ApiView;

import org.waveprotocol.box.server.robots.OperationContext;
import org.waveprotocol.box.server.robots.OperationContextImpl;
import org.waveprotocol.box.server.robots.RobotsTestBase;
import org.waveprotocol.box.server.robots.testing.OperationServiceHelper;
import org.waveprotocol.box.server.robots.util.ConversationUtil;
import org.waveprotocol.wave.model.conversation.ConversationBlip;
import org.waveprotocol.wave.model.conversation.ObservableConversation;
import org.waveprotocol.wave.model.conversation.ObservableConversationBlip;
import org.waveprotocol.wave.model.conversation.ObservableConversationThread;
import org.waveprotocol.wave.model.conversation.ConversationBlip.LocatedReplyThread;
import org.waveprotocol.wave.model.document.Doc;
import org.waveprotocol.wave.model.document.Document;
import org.waveprotocol.wave.model.document.operation.DocInitialization;
import org.waveprotocol.wave.model.document.operation.impl.DocInitializationBuilder;
import org.waveprotocol.wave.model.document.util.DocHelper;
import org.waveprotocol.wave.model.document.util.LineContainers;
import org.waveprotocol.wave.model.document.util.Point;
import org.waveprotocol.wave.model.wave.opbased.OpBasedWavelet;

import java.util.Iterator;

/**
* Unit tests for {@link BlipOperationServices}.
*
* @author ljvderijk@google.com (Lennard de Rijk)
*/
public class BlipOperationServicesTest extends RobotsTestBase {

  private static final String TEMP_BLIP_ID = OperationContext.TEMP_ID_MARKER + "blip1";
  private static final String NEW_BLIP_CONTENT = "Hello World";

  private BlipOperationServices service;
  private OperationServiceHelper helper;
  private BlipData blipData;

  @Override
  protected void setUp() {
    service = BlipOperationServices.create();
    helper = new OperationServiceHelper(WAVELET_NAME, ALEX);
    // BlipData constructor is broken, it doesn't set the blipId passed in the
    // constructor
    blipData = new BlipData(s(WAVE_ID), s(WAVELET_ID), TEMP_BLIP_ID, NEW_BLIP_CONTENT);
    blipData.setBlipId(TEMP_BLIP_ID);
  }

  public void testContinueThread() throws Exception {
    OperationContextImpl context = helper.getContext();
    ObservableConversation conversation =
        context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    // Append a random blip to check that we actually append to the end of this
    // thread.
    conversation.getRootThread().appendBlip();

    // Append to continue the thread of the root blip
    String rootBlipId = ConversationUtil.getRootBlipId(conversation);
    OperationRequest operation = operationRequest(OperationType.BLIP_CONTINUE_THREAD,
        rootBlipId, Parameter.of(ParamsProperty.BLIP_DATA, blipData));

    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse(response.isError());

    ConversationBlip newBlip = checkAndGetNewBlip(context, conversation, response);

    Iterator<? extends ObservableConversationBlip> it =
        conversation.getRootThread().getBlips().iterator();
    it.next(); // skip, root
    it.next(); // skip, first reply
    assertEquals("New blip should be the third blip in the root thread", newBlip, it.next());
  }

  public void testCreateChild() throws Exception {
    OperationContextImpl context = helper.getContext();
    ObservableConversation conversation =
        context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    // Append a random blip to check that we actually make a new child blip
    conversation.getRootThread().appendBlip();

    // Create a child to the rootblip
    String rootBlipId = ConversationUtil.getRootBlipId(conversation);
    OperationRequest operation = operationRequest(OperationType.BLIP_CREATE_CHILD, rootBlipId,
        Parameter.of(ParamsProperty.BLIP_DATA, blipData));

    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse(response.isError());

    ConversationBlip newBlip = checkAndGetNewBlip(context, conversation, response);

    Iterator<? extends ObservableConversationThread> it =
        conversation.getRootThread().getFirstBlip().getReplyThreads().iterator();
    assertEquals("New blip should be the first blip in the first reply thread",
        it.next().getFirstBlip(), newBlip);
  }

  public void testAppendBlip() throws Exception {
    OperationRequest operation = operationRequest(OperationType.WAVELET_APPEND_BLIP,
        Parameter.of(ParamsProperty.BLIP_DATA, blipData));

    OperationContextImpl context = helper.getContext();
    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse(response.isError());

    ObservableConversation conversation =
        context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();
    ConversationBlip newBlip = checkAndGetNewBlip(context, conversation, response);

    Iterator<? extends ObservableConversationBlip> it =
        conversation.getRootThread().getBlips().iterator();
    it.next(); // skip, root
    assertEquals("New blip should be the second blip in the root thread", newBlip, it.next());
  }

  public void testAppendBadMarkup() throws Exception {
    // Set markup with different end tag.
    String markup = "<custom>"+NEW_BLIP_CONTENT+"</diffcustom>";

    OperationContextImpl context = helper.getContext();
    ObservableConversation conversation =
        context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    // Append the custom markup to the newly created blip.
    ConversationBlip markupBlip = conversation.getRootThread().appendBlip();

    OperationRequest operation = operationRequest(OperationType.DOCUMENT_APPEND_MARKUP,
        markupBlip.getId(), Parameter.of(ParamsProperty.CONTENT, markup));

    try {
      service.execute(operation, context, ALEX);

      fail("Bad Markup should have generated error in service execution.");
    } catch(IllegalArgumentException e) {
      // Good.
    }
  }

  public void testAppendCustomMarkup() throws Exception {
    String markup = "<custom>this is custom markup</custom>";

    OperationContextImpl context = helper.getContext();
    ObservableConversation conversation =
        context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    // Append the custom markup to the newly created blip.
    ConversationBlip markupBlip = conversation.getRootThread().appendBlip();

    OperationRequest operation = operationRequest(OperationType.DOCUMENT_APPEND_MARKUP,
        markupBlip.getId(), Parameter.of(ParamsProperty.CONTENT, markup));

    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse("CustomMarkup generated error in service execution.", response.isError());

    // The xml in new blip should match custom markup.
    String actualContent = markupBlip.getContent().toXmlString();
    assertTrue("Expected the new blip to contain the custom markup as specified in the " +
        "operation. actualcontent: " + actualContent, actualContent.contains(markup));
  }

  /**
   * Validates the behavior when a caller invokes the DOCUMENT_APPEND_MARKUP
   * without actually passing in xml markup (so just the text).  The behavior
   * should be to create a default wave line element, so the scenario is:
   *
   * input: "Hello World"
   * output: <line></line>Hello World
   */
  public void testAppendLineMarkup() throws Exception {
    // Just insert text. should create <line></line>Text.
    String markup = NEW_BLIP_CONTENT;

    OperationContextImpl context = helper.getContext();
    ObservableConversation conversation =
        context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    // Append the text markup to the newly created blip.
    DocInitialization blipInitContent = new DocInitializationBuilder().build();
    ConversationBlip markupBlip = conversation.getRootThread().appendBlip(blipInitContent);

    OperationRequest operation = operationRequest(OperationType.DOCUMENT_APPEND_MARKUP,
        markupBlip.getId(), Parameter.of(ParamsProperty.CONTENT, markup));

    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse("LineMarkup generated error in service execution.", response.isError());

    // The output should now include the default <line/> element.
    String lineContent = markupBlip.getContent().toXmlString();
    assertTrue("Expected the blip to append the default wave <line/> element. " +
        "actual content: " + lineContent, lineContent.contains("<line/>"+markup));
  }

  public void testAppendInlineBlip() throws Exception {
    OperationContextImpl context = helper.getContext();
    ObservableConversation conversation =
        context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    // Append the inline blip to the root blip
    String rootBlipId = ConversationUtil.getRootBlipId(conversation);
    OperationRequest operation = operationRequest(OperationType.DOCUMENT_APPEND_INLINE_BLIP,
        rootBlipId, Parameter.of(ParamsProperty.BLIP_DATA, blipData));

    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse(response.isError());

    ConversationBlip newBlip = checkAndGetNewBlip(context, conversation, response);

    Iterator<? extends LocatedReplyThread<? extends ObservableConversationThread>> it =
        conversation.getRootThread().getFirstBlip().locateReplyThreads().iterator();
    LocatedReplyThread<? extends ObservableConversationThread> inlineReplyThread = it.next();

    // The inline reply thread should be located just after the last line
    // element
    Document doc = conversation.getRootThread().getFirstBlip().getContent();
    Doc.E lastLine = DocHelper.getLastElementWithTagName(doc, LineContainers.LINE_TAGNAME);
    int lastLineLocation = doc.getLocation(Point.after(doc, lastLine));
    assertEquals("The inline reply was not located just after the last line element",
        lastLineLocation, inlineReplyThread.getLocation());
  }

  public void testInsertInlineBlip() throws Exception {
    OperationContextImpl context = helper.getContext();
    OpBasedWavelet wavelet = context.openWavelet(WAVE_ID, WAVELET_ID, ALEX);
    ObservableConversation conversation =
        context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    int insertAtApiLocation = 2;
    ApiView apiView =
        new ApiView(conversation.getRootThread().getFirstBlip().getContent(), wavelet);
    int insertAtXmlLocation = apiView.transformToXmlOffset(insertAtApiLocation);

    // Append the inline blip to the root blip
    String rootBlipId = ConversationUtil.getRootBlipId(conversation);
    OperationRequest operation = operationRequest(OperationType.DOCUMENT_INSERT_INLINE_BLIP,
        rootBlipId, Parameter.of(ParamsProperty.BLIP_DATA, blipData),
        Parameter.of(ParamsProperty.INDEX, insertAtApiLocation));

    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse(response.isError());

    ConversationBlip newBlip = checkAndGetNewBlip(context, conversation, response);

    Iterator<? extends LocatedReplyThread<? extends ObservableConversationThread>> it =
        conversation.getRootThread().getFirstBlip().locateReplyThreads().iterator();
    LocatedReplyThread<? extends ObservableConversationThread> inlineReplyThread = it.next();
    assertEquals("The inline reply was not located where specified", insertAtXmlLocation,
        inlineReplyThread.getLocation());
  }

  public void testInsertInlineBlipAfterElement() throws Exception {
    OperationContextImpl context = helper.getContext();
    ObservableConversation conversation =
      context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    // Make an inline blip at a certain location, we will then have the
    // BlipOperationService insert one after that blip.
    ObservableConversationBlip rootBlip = conversation.getRootThread().getFirstBlip();
    Document doc = rootBlip.getContent();
    Doc.E lastLine = DocHelper.getLastElementWithTagName(doc, LineContainers.LINE_TAGNAME);
    int lastLineLocation = doc.getLocation(Point.after(doc, lastLine));
    ObservableConversationBlip firstInlineBlip =
        rootBlip.addReplyThread(lastLineLocation).appendBlip();

    // Append the inline blip to the root blip
    String rootBlipId = ConversationUtil.getRootBlipId(conversation);
    Element inlineBlipElement = new Element(ElementType.INLINE_BLIP);
    inlineBlipElement.setProperty("id", firstInlineBlip.getId());
    OperationRequest operation = operationRequest(
        OperationType.DOCUMENT_INSERT_INLINE_BLIP_AFTER_ELEMENT, rootBlipId,
        Parameter.of(ParamsProperty.BLIP_DATA, blipData),
        Parameter.of(ParamsProperty.ELEMENT, inlineBlipElement));

    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse(response.isError());

    ConversationBlip newBlip = checkAndGetNewBlip(context, conversation, response);

    // The second InlineReplyThread is created by the BlipOperationService, it
    // should be located just after the first one.
    Iterator<? extends LocatedReplyThread<?>> it =
        conversation.getRootThread().getFirstBlip().locateReplyThreads().iterator();
    // Inline blips have a length of 2.
    assertEquals("The inline reply was not located where specified", it.next().getLocation() + 2,
        it.next().getLocation());
  }

  public void testDeleteBlip() throws Exception {
    OperationContextImpl context = helper.getContext();
    ObservableConversation conversation =
      context.openConversation(WAVE_ID, WAVELET_ID, ALEX).getRoot();

    // Delete the root blip
    String rootBlipId = ConversationUtil.getRootBlipId(conversation);
    OperationRequest operation = operationRequest(OperationType.BLIP_DELETE, rootBlipId);

    service.execute(operation, context, ALEX);

    JsonRpcResponse response = context.getResponse(OPERATION_ID);
    assertFalse(response.isError());
    assertNull("Blip should have been deleted", conversation.getBlip(rootBlipId));
  }

  /**
   * Methods that checks that the new blip was actually created and stored in
   * the context. As well as that it checks its contents
   */
  private ConversationBlip checkAndGetNewBlip(
      OperationContextImpl context, ObservableConversation conversation, JsonRpcResponse response)
      throws InvalidRequestException {
    // Retrieve the blip using the context so that the temp blip storage is
    // checked
    ConversationBlip newBlip = context.getBlip(conversation, TEMP_BLIP_ID);
    assertEquals("The response didn't contain the id of the new blip", newBlip.getId(),
        response.getData().get(ParamsProperty.NEW_BLIP_ID));
    String actualContent = newBlip.getContent().toXmlString();
    assertTrue("Expected the new blip to contain the contens as specified in the operation",
        actualContent.contains(NEW_BLIP_CONTENT));
    return newBlip;
  }
}
TOP

Related Classes of org.waveprotocol.box.server.robots.operations.BlipOperationServicesTest

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.