private void createTrioVersions(DocumentModel file) throws Exception {
    // create a first version
    file.setProperty("file", "filename", "A");
    file.putContextData(
        ScopeType.REQUEST, VersioningDocument.CREATE_SNAPSHOT_ON_SAVE_KEY, Boolean.TRUE);
    file = session.saveDocument(file);

    checkVersions(file, "0.1");

    // create a second version
    // make it dirty so it will be saved
    file.setProperty("file", "filename", "B");
    file.putContextData(
        ScopeType.REQUEST, VersioningDocument.CREATE_SNAPSHOT_ON_SAVE_KEY, Boolean.TRUE);
    maybeSleepToNextSecond();
    file = session.saveDocument(file);

    checkVersions(file, "0.1", "0.2");

    // create a third version
    file.setProperty("file", "filename", "C");
    file.putContextData(
        ScopeType.REQUEST, VersioningDocument.CREATE_SNAPSHOT_ON_SAVE_KEY, Boolean.TRUE);
    maybeSleepToNextSecond();
    file = session.saveDocument(file);

    checkVersions(file, "0.1", "0.2", "0.3");
  }
  @Test
  public void testAllowVersionWrite() {
    DocumentModel doc = session.createDocumentModel("/", "doc", "File");
    doc.setPropertyValue("icon", "icon1");
    doc = session.createDocument(doc);
    DocumentRef verRef = session.checkIn(doc.getRef(), null, null);

    // regular version cannot be written
    DocumentModel ver = session.getDocument(verRef);
    ver.setPropertyValue("icon", "icon2");
    try {
      session.saveDocument(ver);
      fail("Should not allow version write");
    } catch (PropertyException e) {
      assertTrue(e.getMessage(), e.getMessage().contains("Cannot set property on a version"));
    }

    // with proper option, it's allowed
    ver.setPropertyValue("icon", "icon3");
    ver.putContextData(CoreSession.ALLOW_VERSION_WRITE, Boolean.TRUE);
    session.saveDocument(ver);
    // refetch to check
    ver = session.getDocument(verRef);
    assertEquals("icon3", ver.getPropertyValue("icon"));
  }
  @Test
  public void testAutoCheckOut() throws Exception {
    DocumentModel doc = new DocumentModelImpl("/", "file", "File");
    doc.setPropertyValue("dc:title", "t0");
    doc = session.createDocument(doc);
    assertTrue(doc.isCheckedOut());
    session.checkIn(doc.getRef(), null, null);
    doc.refresh();
    assertFalse(doc.isCheckedOut());

    // auto-checkout
    doc.setPropertyValue("dc:title", "t1");
    doc = session.saveDocument(doc);
    assertTrue(doc.isCheckedOut());

    session.checkIn(doc.getRef(), null, null);
    doc.refresh();
    assertFalse(doc.isCheckedOut());

    // disable auto-checkout
    doc.setPropertyValue("dc:title", "t2");
    doc.putContextData(VersioningService.DISABLE_AUTO_CHECKOUT, Boolean.TRUE);
    doc = session.saveDocument(doc);
    assertFalse(doc.isCheckedOut());
    assertEquals("t2", doc.getPropertyValue("dc:title"));

    // can still be checked out normally afterwards
    doc.checkOut();
    assertTrue(doc.isCheckedOut());
    assertEquals("t2", doc.getPropertyValue("dc:title"));
  }
  @Test
  public void testRemoveSingleDocVersion() throws Exception {
    DocumentModel folder = new DocumentModelImpl("/", "folder#1", "Folder");
    folder = session.createDocument(folder);

    DocumentModel file = new DocumentModelImpl(folder.getPathAsString(), "file#1", "File");
    file = session.createDocument(file);

    checkVersions(file);

    file.setPropertyValue("file:filename", "A");
    file.putContextData(
        ScopeType.REQUEST, VersioningDocument.CREATE_SNAPSHOT_ON_SAVE_KEY, Boolean.TRUE);
    file = session.saveDocument(file);

    checkVersions(file, "0.1");

    DocumentModel lastversion = session.getLastDocumentVersion(file.getRef());
    assertNotNull(lastversion);

    assertTrue(lastversion.isVersion());
    session.removeDocument(lastversion.getRef());

    checkVersions(file);
  }
  protected void process(Element el) {
    DocConfigDescriptor createConf = getDocCreationConfig(el);
    if (createConf != null) {
      createNewDocument(el, createConf);
    }
    List<AttributeConfigDescriptor> configs = getAttributConfigs(el);
    if (configs != null) {
      for (AttributeConfigDescriptor config : configs) {
        processDocAttributes(docsStack.peek(), el, config);
      }

      DocumentModel doc = popStack();
      doc.putContextData(XML_IMPORTER_INITIALIZATION, Boolean.TRUE);
      if (!deferSave) {
        doc = session.saveDocument(doc);
      }
      pushInStack(doc);

      if (createConf != null) {
        String chain = createConf.getAutomationChain();
        if (chain != null && !"".equals(chain.trim())) {
          OperationContext ctx = new OperationContext(session, mvelCtx);
          ctx.setInput(docsStack.peek());
          try {
            getAutomationService().run(ctx, chain);
          } catch (OperationException e) {
            throw new NuxeoException(e);
          }
        }
      }
    }
    for (Object e : el.elements()) {
      process((Element) e);
    }
  }
  public List<DocumentModel> parse(Document doc) {
    Element root = doc.getRootElement();
    elToDoc = new HashMap<>();
    mvelCtx.put("xml", doc);
    mvelCtx.put("map", elToDoc);
    process(root);

    // defer saveDocument to end of operation
    if (deferSave) {
      ArrayList<DocumentModel> a = new ArrayList<>();
      DocumentModel d = null;
      while (docsStack.size() > 0) {
        d = popStack();
        d.putContextData(XML_IMPORTER_INITIALIZATION, Boolean.TRUE);
        d = session.saveDocument(d);
        a.add(d);
      }
      return a;
    } else {
      return new ArrayList<>(docsStack);
    }
  }
  @Test
  public void testVersioningOnLiveProxy() throws Exception {
    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel section = session.createDocumentModel("/", "section", "Folder");
    section = session.createDocument(section);
    DocumentModel doc = session.createDocumentModel("/", "testfile1", "File");
    doc = session.createDocument(doc);
    doc.setPropertyValue("dc:title", "A");
    doc = session.saveDocument(doc);
    DocumentRef docRef = doc.getRef();
    assertTrue(doc.isCheckedOut());
    assertVersion("0.0", doc);
    assertVersionLabel("0.0", doc);
    assertLatestVersion(null, doc);

    // create a live proxy
    DocumentModel proxy = session.createProxy(doc.getRef(), section.getRef());
    assertTrue(proxy.isCheckedOut());
    assertVersion("0.0", proxy);
    assertVersionLabel("0.0", proxy);
    assertLatestVersion(null, proxy);

    // save live proxy with no option, use default
    proxy.setPropertyValue("dc:title", "B");
    proxy = session.saveDocument(proxy);
    assertTrue(proxy.isCheckedOut());
    assertVersion("0.0", proxy);
    assertVersionLabel("0.0", proxy);
    assertLatestVersion(null, proxy);

    // change live proxy and save with minor increment
    proxy.setPropertyValue("dc:title", "C");
    proxy.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MINOR);
    proxy = session.saveDocument(proxy);
    assertFalse(proxy.isCheckedOut());
    assertVersion("0.1", proxy);
    assertVersionLabel("0.1", proxy);
    assertLatestVersion("0.1", proxy);

    // check the source document is also changed
    doc = session.getDocument(docRef);
    assertFalse(doc.isCheckedOut());
    assertVersion("0.1", doc);
    assertVersionLabel("0.1", doc);
    assertLatestVersion("0.1", doc);
    DocumentModel v01 = session.getLastDocumentVersion(docRef);
    assertEquals(v01.getId(), session.getBaseVersion(docRef).reference());

    // change with no increment, the proxy is checked out
    proxy.setPropertyValue("dc:title", "D");
    proxy = session.saveDocument(proxy);
    assertTrue(proxy.isCheckedOut());
    assertVersion("0.1", proxy);
    assertVersionLabel("0.1+", proxy);

    // check source doc
    doc = session.getDocument(docRef);
    assertEquals("D", doc.getPropertyValue("dc:title"));
    assertTrue(doc.isCheckedOut());
    assertVersion("0.1", doc);
    assertVersionLabel("0.1+", doc);
  }
  @SuppressWarnings("deprecation")
  @Test
  @LocalDeploy("org.nuxeo.ecm.core.test.tests:test-versioningservice-contrib.xml")
  public void testOldNuxeoVersioning() throws Exception {
    ((VersioningComponent) service).service = new CompatVersioningService();

    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel doc = session.createDocumentModel("/", "testfile1", "File");
    doc = session.createDocument(doc);
    doc.setPropertyValue("dc:title", "A");
    maybeSleepToNextSecond();
    doc = session.saveDocument(doc);
    DocumentRef docRef = doc.getRef();
    assertTrue(doc.isCheckedOut());
    assertVersion("1.0", doc);
    assertLatestVersion(null, doc);

    // snapshot A=1.0 and save B
    doc.setPropertyValue("dc:title", "B");
    doc.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MINOR);
    maybeSleepToNextSecond();
    doc = session.saveDocument(doc);
    assertTrue(doc.isCheckedOut());
    assertVersion("1.1", doc);
    assertLatestVersion("1.0", doc);

    // another snapshot for B=1.1, using major inc
    doc.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MAJOR);
    maybeSleepToNextSecond();
    doc = session.saveDocument(doc);
    assertTrue(doc.isCheckedOut());
    assertVersion("2.0", doc);
    assertLatestVersion("1.1", doc);
    DocumentModel v11 = session.getLastDocumentVersion(docRef);
    assertVersion("1.1", v11);

    // another snapshot but no increment doesn't change anything, doc is
    // clean
    doc.putContextData(
        ScopeType.REQUEST, VersioningDocument.CREATE_SNAPSHOT_ON_SAVE_KEY, Boolean.TRUE);
    doc = session.saveDocument(doc);
    assertTrue(doc.isCheckedOut());
    assertVersion("2.0", doc);
    assertLatestVersion("1.1", doc);

    // now dirty doc and snapshot+inc
    doc.setPropertyValue("dc:title", "C");
    maybeSleepToNextSecond();
    doc = session.saveDocument(doc);
    doc.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MINOR);
    maybeSleepToNextSecond();
    doc = session.saveDocument(doc);
    assertTrue(doc.isCheckedOut());
    assertVersion("2.1", doc);
    assertLatestVersion("2.0", doc);

    // another save+inc, no snapshot
    doc.setPropertyValue("dc:title", "D");
    doc.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MAJOR);
    maybeSleepToNextSecond();
    doc = session.saveDocument(doc);
    assertTrue(doc.isCheckedOut());
    assertVersion("3.0", doc);
    assertLatestVersion("2.1", doc);

    // checkin/checkout (old style)
    maybeSleepToNextSecond();
    session.checkIn(docRef, null);
    session.checkOut(docRef);
    doc = session.getDocument(docRef);
    assertTrue(doc.isCheckedOut());
    assertVersion("3.1", doc);
    assertLatestVersion("3.0", doc);

    // wait before doing a restore
    session.save();
    waitForAsyncCompletion();

    // restore 1.1 -> 3.2 (snapshots 3.1)
    maybeSleepToNextSecond();
    doc = session.restoreToVersion(docRef, v11.getRef());
    assertFalse(doc.isCheckedOut());
    assertVersion("1.1", doc);
    assertVersionLabel("1.1", doc);
    assertLatestVersion("3.1", doc);

    // checkout restored version
    doc.checkOut();
    assertTrue(doc.isCheckedOut());
    assertVersion("3.2", doc);
    assertVersionLabel("3.2", doc);
    assertLatestVersion("3.1", doc);
  }
  @Test
  public void testStandardVersioning() throws Exception {
    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel doc = session.createDocumentModel("/", "testfile1", "File");
    doc = session.createDocument(doc);
    doc.setPropertyValue("dc:title", "A");
    doc = session.saveDocument(doc);
    DocumentRef docRef = doc.getRef();
    assertTrue(doc.isCheckedOut());
    assertVersion("0.0", doc);
    assertVersionLabel("0.0", doc);
    assertLatestVersion(null, doc);

    // save with no option, use default
    doc.setPropertyValue("dc:title", "B");
    doc = session.saveDocument(doc);
    assertTrue(doc.isCheckedOut());
    assertVersion("0.0", doc);
    assertVersionLabel("0.0", doc);
    assertLatestVersion(null, doc);

    // change and save with new minor
    doc.setPropertyValue("dc:title", "C");
    doc.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MINOR);
    maybeSleepToNextSecond();
    doc = session.saveDocument(doc);
    assertFalse(doc.isCheckedOut());
    assertVersion("0.1", doc);
    assertVersionLabel("0.1", doc);
    assertLatestVersion("0.1", doc);
    DocumentModel v01 = session.getLastDocumentVersion(docRef);
    assertEquals(v01.getId(), session.getBaseVersion(docRef).reference());

    // checkout
    doc.checkOut();
    assertTrue(doc.isCheckedOut());
    assertVersion("0.1", doc);
    assertVersionLabel("0.1+", doc);
    assertLatestVersion("0.1", doc);

    // change and save with new major
    doc.setPropertyValue("dc:title", "D");
    doc.putContextData(VersioningService.VERSIONING_OPTION, VersioningOption.MAJOR);
    maybeSleepToNextSecond();
    doc = session.saveDocument(doc);
    assertFalse(doc.isCheckedOut());
    assertVersion("1.0", doc);
    assertVersionLabel("1.0", doc);
    assertLatestVersion("1.0", doc);
    DocumentModel v10 = session.getLastDocumentVersion(docRef);
    assertEquals(v10.getId(), session.getBaseVersion(docRef).reference());

    // direct save for autocheckout
    doc.setPropertyValue("dc:title", "E");
    doc = session.saveDocument(doc);
    assertTrue(doc.isCheckedOut());
    assertVersion("1.0", doc);
    assertVersionLabel("1.0+", doc);
    assertLatestVersion("1.0", doc);

    // checkin
    maybeSleepToNextSecond();
    DocumentRef v11ref = doc.checkIn(VersioningOption.MINOR, "foo");
    assertFalse(doc.isCheckedOut());
    assertVersion("1.1", doc);
    assertVersionLabel("1.1", doc);
    assertLatestVersion("1.1", doc);
    assertEquals(v11ref.reference(), session.getBaseVersion(docRef).reference());

    // wait before doing a restore
    session.save();
    waitForAsyncCompletion();

    // restore 0.1
    doc = session.restoreToVersion(docRef, v01.getRef());
    assertFalse(doc.isCheckedOut());
    assertVersion("0.1", doc);
    assertVersionLabel("0.1", doc);
    assertLatestVersion("1.1", doc);
    assertEquals(v01.getId(), session.getBaseVersion(docRef).reference());

    // checkout restored version
    doc.checkOut();
    assertTrue(doc.isCheckedOut());
    assertVersion("1.1", doc);
    assertVersionLabel("1.1+", doc);
    assertLatestVersion("1.1", doc);

    // publish (checks in first)
    maybeSleepToNextSecond();
    DocumentModel proxy = session.publishDocument(doc, folder);
    assertFalse(doc.isCheckedOut());
    assertVersion("1.2", doc);
    assertVersionLabel("1.2", doc);
    assertLatestVersion("1.2", doc);
    assertVersion("1.2", proxy);

    // republish, no new version
    proxy = session.publishDocument(doc, folder);
    assertFalse(doc.isCheckedOut());
    assertVersion("1.2", doc);
    assertVersionLabel("1.2", doc);
    assertLatestVersion("1.2", doc);
    assertVersion("1.2", proxy);

    // do a change (autocheckout), and republish
    doc.setPropertyValue("dc:title", "F");
    session.saveDocument(doc);
    maybeSleepToNextSecond();
    proxy = session.publishDocument(doc, folder);
    assertFalse(doc.isCheckedOut());
    assertVersion("1.3", doc);
    assertVersionLabel("1.3", doc);
    assertLatestVersion("1.3", doc);
  }