content: package ru.yandex.qatools.allure;
  
  import org.junit.After;
  import org.junit.Before;
  import org.junit.Rule;
  import org.junit.Test;
  import org.junit.rules.TemporaryFolder;
  import org.xml.sax.SAXException;
  import ru.yandex.qatools.allure.config.AllureModelUtils;
  import ru.yandex.qatools.allure.events.ClearStepStorageEvent;
  import ru.yandex.qatools.allure.events.ClearTestStorageEvent;
  import ru.yandex.qatools.allure.events.MakeAttachmentEvent;
  import ru.yandex.qatools.allure.events.StepFinishedEvent;
  import ru.yandex.qatools.allure.events.StepStartedEvent;
  import ru.yandex.qatools.allure.events.TestCaseFinishedEvent;
  import ru.yandex.qatools.allure.events.TestCaseStartedEvent;
  import ru.yandex.qatools.allure.events.TestSuiteFinishedEvent;
  import ru.yandex.qatools.allure.events.TestSuiteStartedEvent;
  import ru.yandex.qatools.allure.model.Attachment;
  import ru.yandex.qatools.allure.model.Step;
  import ru.yandex.qatools.allure.model.TestCaseResult;
  import ru.yandex.qatools.allure.model.TestSuiteResult;
  import ru.yandex.qatools.allure.utils.AllureResultsUtils;
  
  import javax.xml.transform.stream.StreamSource;
  import javax.xml.validation.Validator;
  import java.io.File;
  import java.io.IOException;
  import java.io.UnsupportedEncodingException;
  import java.util.ArrayList;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Set;
  import java.util.UUID;
  import java.util.concurrent.Callable;
  import java.util.concurrent.ExecutorService;
  import java.util.concurrent.Executors;
  import java.util.concurrent.Future;
  
  import static org.hamcrest.Matchers.hasSize;
  import static org.hamcrest.core.Is.is;
  import static org.junit.Assert.assertEquals;
  import static org.junit.Assert.assertFalse;
  import static org.junit.Assert.assertNotEquals;
  import static org.junit.Assert.assertNotNull;
  import static org.junit.Assert.assertNull;
  import static org.junit.Assert.assertThat;
  import static org.junit.Assert.assertTrue;
  import static ru.yandex.qatools.allure.commons.AllureFileUtils.listTestSuiteFiles;
  
  /**
   * @author Dmitry Baev charlie@yandex-team.ru
   *         Date: 14.12.13
   */
  public class AllureLifecycleTest {
  
      private static final String UTF_8 = "UTF-8";
      @Rule
      public TemporaryFolder folder = new TemporaryFolder();
  
      public File resultsDirectory;
  
      @Before
      public void setUp() throws Exception {
          resultsDirectory = folder.newFolder();
          AllureResultsUtils.setResultsDirectory(resultsDirectory);
      }
  
      @Test
      public void allureLifecycleTest() throws Exception {
          String uid = UUID.randomUUID().toString();
          TestSuiteResult testSuite = fireTestSuiteStart(uid);
          TestSuiteResult anotherTestSuite = fireCustomTestSuiteEvent(uid);
          assertEquals(testSuite, anotherTestSuite);
  
          TestCaseResult testCase = fireTestCaseStart(uid);
          TestCaseResult anotherTestCase = fireCustomTestCaseEvent();
          assertEquals(testCase, anotherTestCase);
  
          assertThat(testSuite.getTestCases(), hasSize(1));
          assertEquals(testSuite.getTestCases().get(0), testCase);
  
          Step parentStep = fireStepStart();
          Attachment firstAttach = fireMakeAttachment();
  
          assertThat(parentStep.getAttachments(), hasSize(1));
          assertEquals(parentStep.getAttachments().get(0), firstAttach);
  
          Step nestedStep = fireStepStart();
          Attachment secondAttach = fireMakeAttachment();
  
          assertFalse(firstAttach == secondAttach);
  
          assertThat(nestedStep.getAttachments(), hasSize(1));
          assertTrue(nestedStep.getAttachments().get(0) == secondAttach);
  
          fireStepFinished();
  
          assertThat(parentStep.getSteps(), hasSize(1));
          assertEquals(parentStep.getSteps().get(0), nestedStep);
  
          fireStepFinished();
  
          Attachment testCaseAttachment = fireMakeAttachment();
  
          fireTestCaseFinished();
  
          assertThat(testCase.getSteps(), hasSize(1));
          assertEquals(testCase.getSteps().get(0), parentStep);
  
          assertThat(testCase.getAttachments(), hasSize(1));
          assertEquals(testCase.getAttachments().get(0), testCaseAttachment);
  
          fireTestSuiteFinished(uid);
          validateTestSuite();
  
          assertThat(testSuite.getTestCases(), hasSize(1));
  
          String otherUid = UUID.randomUUID().toString();
          TestSuiteResult nextTestSuite = fireTestSuiteStart(otherUid);
          assertNotEquals(anotherTestSuite, nextTestSuite);
      }
  
      @Test
      public void allureClearStorageTest() {
          String suiteUid = UUID.randomUUID().toString();
          TestSuiteResult testSuite = fireTestSuiteStart(suiteUid);
          TestCaseResult testCase = fireTestCaseStart(suiteUid);
          assertThat(testSuite.getTestCases(), hasSize(1));
          assertEquals(testSuite.getTestCases().get(0), testCase);
  
          Step parentStep = fireStepStart();
          Step nestedStep = fireStepStart();
          fireStepFinished();
  
          assertThat(parentStep.getSteps(), hasSize(1));
          assertTrue(parentStep.getSteps().get(0) == nestedStep);
  
          fireStepFinished();
          fireClearStepStorage();
  
          assertThat(testCase.getSteps(), hasSize(0));
          fireClearTestStorage();
          TestCaseResult afterClearing = Allure.LIFECYCLE.getTestCaseStorage().get();
          assertFalse(testCase == afterClearing);
          checkTestCaseIsNew(afterClearing);
  
      }
  
      @Test
      public void supportForConcurrentUseOfChildThreads() throws Exception {
          final int threads = 20;
          final int stepsCount = 1000;
  
          final Allure lifecycle = Allure.LIFECYCLE;
  
          String suiteUid = UUID.randomUUID().toString();
          fireTestSuiteStart(suiteUid);
          fireTestCaseStart(suiteUid);
  
          ExecutorService service = Executors.newFixedThreadPool(threads);
  
          final List<Callable<Object>> tasks = new ArrayList<>();
          for (int i = 0; i < threads; i++) {
              tasks.add(new Callable<Object>() {
                  @Override
                  public Object call() throws Exception {
                      for (int i = 0; i < stepsCount; i++) {
                          lifecycle.fire(new StepStartedEvent("test-step"));
                          lifecycle.fire(new StepFinishedEvent());
                      }
                      return "";
                  }
              });
          }
  
          List<Future<Object>> futures = service.invokeAll(tasks);
          for (Future<Object> future : futures) {
              future.get();
          }
  
          assertThat(lifecycle.getStepStorage().pollLast().getSteps(), hasSize(threads * stepsCount));
      }
  
      @Test
      public void supportForConcurrentUseOfChildThreadsTestCases() throws Exception {
          final int threads = 20;
          final int testCases = 1000;
  
          final Allure lifecycle = Allure.LIFECYCLE;
  
          String suiteUid = UUID.randomUUID().toString();
          fireTestSuiteStart(suiteUid);
          fireTestCaseStart(suiteUid);
  
          ExecutorService service = Executors.newFixedThreadPool(threads);
  
          final List<Callable<Object>> tasks = new ArrayList<>();
  
          final String uid = UUID.randomUUID().toString();
          lifecycle.fire(new TestSuiteStartedEvent(uid, uid));
          for (int i = 0; i < threads; i++) {
              tasks.add(new Callable<Object>() {
                  @Override
                  public Object call() throws Exception {
                      for (int i = 0; i < testCases; i++) {
                          lifecycle.fire(new TestCaseStartedEvent(uid, "test-case"));
                          lifecycle.fire(new StepFinishedEvent());
                      }
                      return "";
                  }
              });
          }
  
          List<Future<Object>> futures = service.invokeAll(tasks);
          for (Future<Object> future : futures) {
              future.get();
          }
  
          assertThat(lifecycle.getTestSuiteStorage().get(uid).getTestCases(), hasSize(threads * testCases));
      }
  
      private void checkTestCaseIsNew(TestCaseResult testCaseResult) {
          assertNull(testCaseResult.getName());
          assertNull(testCaseResult.getTitle());
          assertNull(testCaseResult.getDescription());
          assertNull(testCaseResult.getFailure());
          assertNull(testCaseResult.getStatus());
          assertTrue(testCaseResult.getSteps().isEmpty());
          assertTrue(testCaseResult.getAttachments().isEmpty());
          assertTrue(testCaseResult.getLabels().isEmpty());
          assertTrue(testCaseResult.getParameters().isEmpty());
          assertTrue(testCaseResult.getStart() == 0 && testCaseResult.getStop() == 0);
      }
  
      private void fireClearTestStorage() {
          Allure.LIFECYCLE.fire(new ClearTestStorageEvent());
      }
  
      private void fireClearStepStorage() {
          Allure.LIFECYCLE.fire(new ClearStepStorageEvent());
      }
  
      public TestSuiteResult fireTestSuiteStart(String uid) {
          Allure.LIFECYCLE.fire(new TestSuiteStartedEvent(uid, "some.suite.name"));
          TestSuiteResult testSuite = Allure.LIFECYCLE.getTestSuiteStorage().get(uid);
          assertNotNull(testSuite);
          assertThat(testSuite.getName(), is("some.suite.name"));
          assertThat(testSuite.getTestCases(), hasSize(0));
          return testSuite;
      }
  
      public void fireTestSuiteFinished(String uid) {
          Allure.LIFECYCLE.fire(new TestSuiteFinishedEvent(uid));
      }
  
      public void validateTestSuite() throws SAXException, IOException {
          Validator validator = AllureModelUtils.getAllureSchemaValidator();
  
          for (File each : listTestSuiteFiles(resultsDirectory)) {
              validator.validate(new StreamSource(each));
          }
      }
  
      public TestCaseResult fireTestCaseStart(String uid) {
          Allure.LIFECYCLE.fire(new TestCaseStartedEvent(uid, "some.case.name"));
          TestCaseResult testCase = Allure.LIFECYCLE.getTestCaseStorage().get();
          assertNotNull(testCase);
          assertThat(testCase.getName(), is("some.case.name"));
          return testCase;
      }
  
      public void fireTestCaseFinished() {
          Allure.LIFECYCLE.fire(new TestCaseFinishedEvent());
      }
  
      public Step fireStepStart() {
          Allure.LIFECYCLE.fire(new StepStartedEvent("some.step.name"));
          Step step = Allure.LIFECYCLE.getStepStorage().getLast();
          assertNotNull(step);
          assertThat(step.getName(), is("some.step.name"));
          return step;
      }
  
      public Attachment fireMakeAttachment() throws UnsupportedEncodingException {
          Step lastStep = Allure.LIFECYCLE.getStepStorage().getLast();
          int attachmentsCount = lastStep.getAttachments().size();
  
          Allure.LIFECYCLE.fire(new MakeAttachmentEvent("some.attach.title".getBytes(UTF_8), "attach.body", ""));
  
          assertThat(lastStep.getAttachments().size(), is(attachmentsCount + 1));
          Attachment attachment = lastStep.getAttachments().get(attachmentsCount);
          assertNotNull(attachment);
  
          return attachment;
      }
  
      public void fireStepFinished() {
          Allure.LIFECYCLE.fire(new StepFinishedEvent());
      }
  
      public TestSuiteResult fireCustomTestSuiteEvent(String uid) {
          Allure.LIFECYCLE.fire(new ChangeTestSuiteTitleEvent(uid, "new.suite.title"));
          TestSuiteResult testSuite = Allure.LIFECYCLE.getTestSuiteStorage().get(uid);
          assertNotNull(testSuite);
          assertThat(testSuite.getTitle(), is("new.suite.title"));
          return testSuite;
      }
  
      public TestCaseResult fireCustomTestCaseEvent() {
          Allure.LIFECYCLE.fire(new ChangeTestCaseTitleEvent("new.case.title"));
          TestCaseResult testCase = Allure.LIFECYCLE.getTestCaseStorage().get();
          assertNotNull(testCase);
          assertThat(testCase.getTitle(), is("new.case.title"));
          return testCase;
      }
  
      @After
      public void tearDown() {
          AllureResultsUtils.setResultsDirectory(null);
      }
  
  }
  