Package org.activiti.engine.test.api.repository.diagram

Source Code of org.activiti.engine.test.api.repository.diagram.ProcessDiagramRetrievalTest$DiagramElementComparator

/* 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 org.activiti.engine.test.api.repository.diagram;

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

import java.io.BufferedOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.activiti.engine.RepositoryService;
import org.activiti.engine.impl.bpmn.diagram.ProcessDiagramLayoutFactory;
import org.activiti.engine.repository.DiagramElement;
import org.activiti.engine.repository.DiagramLayout;
import org.activiti.engine.repository.DiagramNode;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.test.ActivitiRule;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;


/**
* Tests process model and diagram retrieval features of the
* {@link RepositoryService}.
*
* This test generates HTML code containing the positions and dimensions of all
* elements in a BPMN process and compares that to HTML files stored in
* 'src/test/resources/org/activiti/engine/test/api/repository/diagram'.
*
* If the expected HTML code needs to be changed due to changes in
* {@link ProcessDiagramLayoutFactory}, the files can be regenerated by running the
* test while {@link ProcessDiagramRetrievalTest#OVERWRITE_EXPECTED_HTML_FILES}
* is set to true.
*
* @author Falko Menge
*/
@RunWith(Parameterized.class)
public class ProcessDiagramRetrievalTest {
 
  /**
   * Set this to true and run the tests to regenerate the HTML files located in
   * src/test/resources/org/activiti/engine/test/api/repository/diagram, which
   * contain expected values for the HTML code generated by test cases.
   */
  private static final boolean OVERWRITE_EXPECTED_HTML_FILES = false;
 
  @Rule
  public ActivitiRule activitiRule = new ActivitiRule();

  /**
   * Provides a list of parameters for
   * {@link ProcessDiagramRetrievalTest#ProcessDiagramRetrievalTest(String, String, String, String)}
   */
  @Parameters
  public static Collection<Object[]> data() {
    return Arrays.asList(new Object[][] {
            { "testStartEventWithNegativeCoordinates", ".bpmn", ".png", "sid-61D1FC47-8031-4834-A9B4-84158E73F7B9" },
            { "testStartAndEndEventWithNegativeCoordinates", ".bpmn", ".png", "sid-61D1FC47-8031-4834-A9B4-84158E73F7B9" },
            { "testProcessWithTask", ".bpmn", ".png", "sid-1E142B16-AFAF-429E-A441-D1232CFBD560" },
            { "testProcessFromCamundaFoxDesigner", ".bpmn", ".png", "UserTask_1" },
            { "testProcessFromCamundaFoxDesigner", ".bpmn", ".jpg", "UserTask_1" },
            { "testProcessFromActivitiDesigner", ".bpmn20.xml", ".png", "Send_rejection_notification_via_email__3" },
            { "testSequenceFlowOutOfBounds", ".bpmn", ".png", "sid-61D1FC47-8031-4834-A9B4-84158E73F7B9" },
            { "testProcessFromAdonis", ".bpmn", ".png", "_16615" },
            { "testProcessFromIboPrometheus", ".bpmn", ".png", "ibo-5784efbe-35ac-44bc-bcbe-4c18a2f23d5d" },
            { "testProcessFromIboPrometheus", ".bpmn", ".jpg", "ibo-5784efbe-35ac-44bc-bcbe-4c18a2f23d5d" },
            { "testInvoiceProcessCamundaFoxDesigner", ".bpmn20.xml", ".jpg", "Rechnung_freigeben_125" },
            { "testInvoiceProcessSignavio", ".bpmn", ".png", "Freigebenden_zuordnen_143" },
            { "testInvoiceProcessFromBusinessProcessIncubator", ".bpmn", ".png", "Rechnung_kl_ren_148" },
            { "testProcessFromYaoqiang", ".bpmn", ".png", "_3" },
    });
  }
 
  private final String xmlFileName;
  private final String imageFileName;
  private final String highlightedActivityId;
  private RepositoryService repositoryService;
  private String deploymentId;

  private ProcessDefinitionQuery processDefinitionQuery;

  public ProcessDiagramRetrievalTest(String modelName, String xmlFileExtension, String imageFileExtension, String highlightedActivityId) {
    this.xmlFileName = modelName + xmlFileExtension;
    this.imageFileName = modelName + imageFileExtension;
    this.highlightedActivityId = highlightedActivityId;
  }

  @Before
  public void setup() {
    repositoryService = activitiRule.getRepositoryService();
    deploymentId = repositoryService.createDeployment()
      .addClasspathResource("org/activiti/engine/test/api/repository/diagram/" + xmlFileName)
      .addClasspathResource("org/activiti/engine/test/api/repository/diagram/" + imageFileName)
      .deploy()
      .getId();
    processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
  }
 
  @After
  public void teardown() {
    repositoryService.deleteDeployment(deploymentId, true);
  }

  /**
   * Tests {@link RepositoryService#getProcessModel(String)}.
   */
  @Test
  public void testGetProcessModel() throws Exception {
    if (1 == processDefinitionQuery.count()) {
      ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
      InputStream expectedStream = new FileInputStream("src/test/resources/org/activiti/engine/test/api/repository/diagram/" + xmlFileName);
      InputStream actualStream = repositoryService.getProcessModel(processDefinition.getId());
      assertTrue(isEqual(expectedStream, actualStream));
    } else {
      // some test diagrams do not contain executable processes
      // and are therefore ignored by the engine
    }
  }
     

  /**
   * Tests {@link RepositoryService#getProcessDiagram(String)}.
   */
  @Test
  public void testGetProcessDiagram() throws Exception {
    if (1 == processDefinitionQuery.count()) {
      ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
      InputStream expectedStream = new FileInputStream("src/test/resources/org/activiti/engine/test/api/repository/diagram/" + imageFileName);
      InputStream actualStream = repositoryService.getProcessDiagram(processDefinition.getId());
//      writeToFile(repositoryService.getProcessDiagram(processDefinition.getId()),
//              new File("src/test/resources/org/activiti/engine/test/api/repository/diagram/" + imageFileName + ".actual.png"));
      assertTrue(isEqual(expectedStream, actualStream));
    } else {
      // some test diagrams do not contain executable processes
      // and are therefore ignored by the engine
    }
  }
 
  /**
   * Tests {@link RepositoryService#getProcessDiagramLayout(String)} and
   * {@link ProcessDiagramLayoutFactory#getProcessDiagramLayout(InputStream, InputStream)}.
   */
  @Test
  public void testGetProcessDiagramLayout() throws Exception {
    DiagramLayout processDiagramLayout;
    if (1 == processDefinitionQuery.count()) {
      ProcessDefinition processDefinition = processDefinitionQuery.singleResult();
      assertNotNull(processDefinition);
      processDiagramLayout = repositoryService.getProcessDiagramLayout(processDefinition.getId());
    } else {
      // some test diagrams do not contain executable processes
      // and are therefore ignored by the engine
      InputStream bpmnXmlStream = new FileInputStream("src/test/resources/org/activiti/engine/test/api/repository/diagram/" + xmlFileName);
      InputStream imageStream = new FileInputStream("src/test/resources/org/activiti/engine/test/api/repository/diagram/" + imageFileName);
      assertNotNull(bpmnXmlStream);
      assertNotNull(imageStream);
      processDiagramLayout = new ProcessDiagramLayoutFactory().getProcessDiagramLayout(bpmnXmlStream, imageStream);
    }
    assertLayoutCorrect(processDiagramLayout);
  }

  private void assertLayoutCorrect(DiagramLayout processDiagramLayout) throws IOException {
    String html = generateHtmlCode(imageFileName, processDiagramLayout, highlightedActivityId);
   
    File htmlFile = new File("src/test/resources/org/activiti/engine/test/api/repository/diagram/" + imageFileName + ".html");
    if (OVERWRITE_EXPECTED_HTML_FILES) {
      FileUtils.writeStringToFile(htmlFile, html);
      fail("The assertions of this test only work if ProcessDiagramRetrievalTest#OVERWRITE_EXPECTED_HTML_FILES is set to false.");
    }
    assertEquals(FileUtils.readFileToString(htmlFile).replace("\r", ""), html); // remove carriage returns in case the files have been fetched via Git on Windows
  }

  private static String generateHtmlCode(String imageUrl, DiagramLayout processDiagramLayout, String highlightedActivityId) {
    StringBuilder html = new  StringBuilder();
    html.append("<!DOCTYPE html>\n");
    html.append("<html>\n");
    html.append("  <head>\n");
    html.append("    <style type=\"text/css\"><!--\n");
    html.append("      .BPMNElement {\n");
    html.append("        position: absolute;\n");
    html.append("        border: 2px dashed lightBlue;\n");
    html.append("        border-radius: 5px; -moz-border-radius: 5px;\n");
    html.append("      }\n");
    if (highlightedActivityId != null && highlightedActivityId.length() > 0) {
      html.append("      #" + highlightedActivityId + " {border: 2px solid red;}\n");
    }
    html.append("    --></style>");
    html.append("  </head>\n");
    html.append("  <body>\n");
    html.append("    <div style=\"position: relative\">\n");
    html.append("      <img src=\"" + imageUrl + "\" />\n");
   
    List<DiagramNode> nodes = processDiagramLayout.getNodes();
    Collections.sort(nodes, new DiagramElementComparator());
   
    for (DiagramNode node : nodes) {
      html.append("      <div");
      html.append(" class=\"BPMNElement\"");
      html.append(" id=\"" + node.getId() + "\"");
      html.append(" style=\"");
      html.append(" left: " + (int) (node.getX() - 2) + "px;");
      html.append(" top: " + (int) (node.getY() - 2) + "px;");
      html.append(" width: " + node.getWidth().intValue() + "px;");
      html.append(" height: " + node.getHeight().intValue() + "px;\"></div>\n");
    }
    html.append("    </div>\n");
    html.append("  </body>\n");
    html.append("</html>");
    return html.toString();
  }

  private static boolean isEqual(InputStream stream1, InputStream stream2)
          throws IOException {

      ReadableByteChannel channel1 = Channels.newChannel(stream1);
      ReadableByteChannel channel2 = Channels.newChannel(stream2);

      ByteBuffer buffer1 = ByteBuffer.allocateDirect(1024);
      ByteBuffer buffer2 = ByteBuffer.allocateDirect(1024);

      try {
          while (true) {

              int bytesReadFromStream1 = channel1.read(buffer1);
              int bytesReadFromStream2 = channel2.read(buffer2);

              if (bytesReadFromStream1 == -1 || bytesReadFromStream2 == -1) return bytesReadFromStream1 == bytesReadFromStream2;

              buffer1.flip();
              buffer2.flip();

              for (int i = 0; i < Math.min(bytesReadFromStream1, bytesReadFromStream2); i++)
                  if (buffer1.get() != buffer2.get())
                      return false;

              buffer1.compact();
              buffer2.compact();
          }

      } finally {
          if (stream1 != null) stream1.close();
          if (stream2 != null) stream2.close();
      }
  }
 
  /**
   * Might be used for debugging {@link ProcessDiagramRetrievalTest#testGetProcessDiagram()}.
   */
  @SuppressWarnings("unused")
  private static void writeToFile(InputStream is, File file) throws Exception {
    DataOutputStream out = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file)));
    int c;
    while((c = is.read()) != -1) {
      out.writeByte(c);
    }
    is.close();
    out.close();
  }
 
  static class DiagramElementComparator implements Comparator<DiagramElement> {
   
    public int compare(DiagramElement a, DiagramElement b) {
      return a.getId().compareTo(b.getId());
    }
   
    // Don't need it here
    public boolean equals(Object obj) {
      return this == obj;
    }
   
  }

}
TOP

Related Classes of org.activiti.engine.test.api.repository.diagram.ProcessDiagramRetrievalTest$DiagramElementComparator

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.