gt:         Message message = new Message();
context: /*
   * Copyright (c) Mirth Corporation. All rights reserved.
   * 
   * http://www.mirthcorp.com
   * 
   * The software in this package is published under the terms of the MPL license a copy of which has
   * been included with this distribution in the LICENSE.txt file.
   */
  
  package com.mirth.connect.plugins.datapruner;
  
  import static org.junit.Assert.assertEquals;
  
  import java.io.File;
  import java.util.ArrayList;
  import java.util.Calendar;
  import java.util.List;
  import java.util.concurrent.Callable;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  import java.util.concurrent.Future;
  
  import org.apache.commons.io.FileUtils;
  import org.apache.log4j.Logger;
  import org.junit.BeforeClass;
  import org.junit.Ignore;
  import org.junit.Test;
  
  import com.mirth.connect.donkey.model.event.Event;
  import com.mirth.connect.donkey.model.message.ConnectorMessage;
  import com.mirth.connect.donkey.model.message.ContentType;
  import com.mirth.connect.donkey.model.message.Message;
  import com.mirth.connect.donkey.model.message.MessageContent;
  import com.mirth.connect.donkey.model.message.RawMessage;
  import com.mirth.connect.donkey.model.message.Status;
  import com.mirth.connect.donkey.server.Donkey;
  import com.mirth.connect.donkey.server.DonkeyConfiguration;
  import com.mirth.connect.donkey.server.controllers.ChannelController;
  import com.mirth.connect.donkey.server.event.EventDispatcher;
  import com.mirth.connect.plugins.datapruner.DataPruner.Strategy;
  import com.mirth.connect.server.controllers.ConfigurationController;
  import com.mirth.connect.server.controllers.ControllerFactory;
  import com.mirth.connect.server.controllers.EngineController;
  import com.mirth.connect.server.controllers.tests.TestUtils;
  import com.mirth.connect.util.messagewriter.MessageWriter;
  import com.mirth.connect.util.messagewriter.MessageWriterException;
  import com.mirth.connect.util.messagewriter.MessageWriterOptions;
  
  public class DataPrunerTest {
      private final static String TEMP_ARCHIVE_FOLDER = "/tmp/prunertest";
      private final static int TEST_POWER = 7;
      private final static int PERFORMANCE_TEST_POWER = 10;
      private final static int ARCHIVER_PAGE_SIZE = 1000;
      private final static String TEST_CHANNEL_ID = "prunerTestChannel";
      private final static String TEST_SERVER_ID = "testServerId";
      private final static String TEST_MESSAGE_CONTENT = TestUtils.TEST_HL7_MESSAGE;
  
      // @formatter:off
      private static Calendar messageDateThreshold;
      private static Calendar contentDateThreshold;
      private static int testSize;
      private static int[] blockSizes = new int[] { 0, 1000 };
      private static Logger logger = Logger.getLogger(DataPrunerTest.class);
      // @formatter:on
  
      @BeforeClass
      public final static void init() throws Exception {
          ConfigurationController configurationController = ConfigurationController.getInstance();
          configurationController.initializeSecuritySettings();
          configurationController.initializeDatabaseSettings();
  
          Donkey donkey = Donkey.getInstance();
          donkey.startEngine(new DonkeyConfiguration(configurationController.getApplicationDataDir(), configurationController.getDatabaseSettings().getProperties(), null, new EventDispatcher() {
              @Override
              public void dispatchEvent(Event event) {}
          }, "testserverid"));
  
          ChannelController.getInstance().initChannelStorage(TEST_CHANNEL_ID);
  
          messageDateThreshold = Calendar.getInstance();
          messageDateThreshold.set(Calendar.DAY_OF_MONTH, messageDateThreshold.get(Calendar.DAY_OF_MONTH) - 90);
  
          contentDateThreshold = Calendar.getInstance();
          contentDateThreshold.set(Calendar.DAY_OF_MONTH, contentDateThreshold.get(Calendar.DAY_OF_MONTH) - 45);
  
          testSize = (int) Math.pow(2, TEST_POWER);
      }
  
      @Test
      public void testPruneAll() throws Exception {
          runPrunerTests(true, true);
      }
  
      @Test
      public void testPruneContentOnly() throws Exception {
          runPrunerTests(false, true);
      }
  
      private void runPrunerTests(boolean messagesPrunable, boolean contentPrunable) throws Exception {
          prepareTestMessages(TEST_CHANNEL_ID, messagesPrunable, contentPrunable, true, Status.SENT, TEST_POWER);
          new DataPruner().pruneChannel(TEST_CHANNEL_ID, messageDateThreshold, contentDateThreshold, null);
          assertEquals(messagesPrunable ? 0 : testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID));
          assertEquals(contentPrunable ? 0 : testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID, true));
          
          for (Strategy strategy : Strategy.values()) {
              for (int blockSize : blockSizes) {
                  try {
                      MessageWriterOptions writerOptions = new MessageWriterOptions();
                      writerOptions.setRootFolder(TEMP_ARCHIVE_FOLDER);
                      writerOptions.setFilePattern("message${message.messageId}.xml");
                      
                      DataPruner pruner = new DataPruner();
                      pruner.setArchiveEnabled(true);
                      pruner.setArchiverOptions(writerOptions);
                      pruner.setPageSize(ARCHIVER_PAGE_SIZE);
                      pruner.setStrategy(strategy);
                      pruner.setRetryCount(0);
                      pruner.setBlockSize(blockSize);
      
                      logger.info("Running pruner w/ archiver test, strategy: " + strategy + ", block size: " + blockSize + ", prune messages: " + messagesPrunable + ", prune content: " + contentPrunable);
                      
                      prepareTestMessages(TEST_CHANNEL_ID, messagesPrunable, contentPrunable, true, Status.SENT, TEST_POWER);
                      pruner.pruneChannel(TEST_CHANNEL_ID, messageDateThreshold, contentDateThreshold, pruner.getArchiverOptions().getRootFolder());
                      assertEquals(messagesPrunable ? 0 : testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID));
                      assertEquals(contentPrunable ? 0 : testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID, true));
                  } catch (AssertionError e) {
                      logger.error(e);
                      throw e;
                  } finally {
                      FileUtils.deleteQuietly(new File(TEMP_ARCHIVE_FOLDER));
                  }
              }
          }
      }
  
      @Test
      public void testPruneNone() throws Exception {
          prepareTestMessages(TEST_CHANNEL_ID, false, false, true, Status.SENT, TEST_POWER);
          DataPruner pruner = new DataPruner();
          pruner.pruneChannel(TEST_CHANNEL_ID, messageDateThreshold, contentDateThreshold, null);
          assertEquals(testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID));
          assertEquals(testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID, true));
      }
  
      @Test
      public final void testPruneSkipIncomplete() throws Exception {
          prepareTestMessages(TEST_CHANNEL_ID, true, true, false, Status.SENT, TEST_POWER);
          DataPruner pruner = new DataPruner();
          pruner.pruneChannel(TEST_CHANNEL_ID, messageDateThreshold, contentDateThreshold, null);
          assertEquals(testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID));
          assertEquals(testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID, true));
      }
  
      @Test
      public final void testPruneIncomplete() throws Exception {
          prepareTestMessages(TEST_CHANNEL_ID, true, true, false, Status.SENT, TEST_POWER);
          DataPruner pruner = new DataPruner();
          pruner.setSkipIncomplete(false);
          pruner.pruneChannel(TEST_CHANNEL_ID, messageDateThreshold, contentDateThreshold, null);
          assertEquals(0, TestUtils.getNumMessages(TEST_CHANNEL_ID));
          assertEquals(0, TestUtils.getNumMessages(TEST_CHANNEL_ID, true));
      }
  
      @Test
      public final void testPruneQueued() throws Exception {
          prepareTestMessages(TEST_CHANNEL_ID, true, true, true, Status.QUEUED, TEST_POWER);
          DataPruner pruner = new DataPruner();
          pruner.pruneChannel(TEST_CHANNEL_ID, messageDateThreshold, contentDateThreshold, null);
          assertEquals(testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID));
          assertEquals(testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID, true));
      }
  
      @Test
      public final void testPruneError() throws Exception {
          prepareTestMessages(TEST_CHANNEL_ID, true, true, true, Status.ERROR, TEST_POWER);
          DataPruner pruner = new DataPruner();
          pruner.pruneChannel(TEST_CHANNEL_ID, messageDateThreshold, contentDateThreshold, null);
          assertEquals(testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID));
          assertEquals(testSize, TestUtils.getNumMessages(TEST_CHANNEL_ID, true));
      }
  
      @Test
      @Ignore
      public final void testPerformance() throws Exception {
          prepareTestMessages(TEST_CHANNEL_ID, true, true, true, Status.SENT, PERFORMANCE_TEST_POWER);
          DataPruner pruner = new DataPruner();
  
          long startTime = System.currentTimeMillis();
          pruner.pruneChannel(TEST_CHANNEL_ID, messageDateThreshold, contentDateThreshold, null);
          long duration = System.currentTimeMillis() - startTime;
          
          System.out.println("Archiver/Pruner executed in " + duration + "ms");
          System.out.println(TestUtils.getPerSecondRate((long) Math.pow(2, PERFORMANCE_TEST_POWER), duration, 2) + " msg/sec");
          
          assertEquals(0, TestUtils.getNumMessages(TEST_CHANNEL_ID));
          assertEquals(0, TestUtils.getNumMessages(TEST_CHANNEL_ID, true));
      }
      
      @Test
      @Ignore
      public final void testConcurrency() throws Exception {
          /*
           * To run this concurrency test, you must setup a "reader" channel through the
           * administrator, that routes messages to other channels that will be pruned. Then specify
           * the ids of those channels below.
           */
          final String readerChannelId = "f7158274-8692-4e53-9d17-db732c3346b8";
          ExecutorService executor = Executors.newSingleThreadExecutor();
          TestUtils.startMirthServer(15000);
  
          DataPruner pruner = new DataPruner();
          pruner.setBlockSize(1);
          pruner.setStrategy(Strategy.INCLUDE_LIST);
          pruner.setRetryCount(0);
          
          TestUtils.deleteAllMessages(readerChannelId);
          TestUtils.deleteAllMessages("0831345e-bbe0-4d62-8f2d-c65280bd479b");
          TestUtils.deleteAllMessages("b2e28f1b-d867-435a-a5f6-3b33d5261e66");
  
          // send messages into the test channel on a separate thread
          Future<Void> future = executor.submit(new Callable<Void>() {
              @Override
              public Void call() throws Exception {
                  EngineController engineController = ControllerFactory.getFactory().createEngineController();
                  logger.info("Sending messages");
  
                  for (int i = 0; i < 100000; i++) {
                      logger.info("sending message #" + i);
                      engineController.dispatchRawMessage(readerChannelId, new RawMessage(TestUtils.TEST_HL7_MESSAGE), false);
                  }
  
                  logger.info("Finished sending messages");
                  return null;
              }
          });
          
          logger.info("Executing pruner");
          
          // run the pruner while messages are processing
          while (!future.isDone()) {
              pruner.run();
              Thread.sleep(2000);
          }
          
          logger.info("Test completed");
      }
  
      private static void prepareTestMessages(String channelId, boolean messagesPrunable, Boolean contentPrunable, boolean processed, Status destinationStatus, int power) throws Exception {
          logger.debug("Preparing " + ((int) Math.pow(2, power)) + " test messages");
          Calendar dateThreshold;
  
          TestUtils.deleteAllMessages(channelId);
  
          if (messagesPrunable) {
              dateThreshold = messageDateThreshold;
          } else if (contentPrunable) {
              dateThreshold = contentDateThreshold;
          } else {
              dateThreshold = Calendar.getInstance();
          }
  
          Calendar receivedDate = Calendar.getInstance();
          receivedDate.setTime(dateThreshold.getTime());
          receivedDate.set(Calendar.DAY_OF_MONTH, receivedDate.get(Calendar.DAY_OF_MONTH) - 1);
  
  