@Test
  public void testVersionRemoval() throws Exception {
    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel file = session.createDocumentModel("/folder", "file", "File");
    file = session.createDocument(file);
    DocumentModel proxy = session.publishDocument(file, folder);
    DocumentModel version = session.getLastDocumentVersion(file.getRef());
    session.save();

    // even Administrator/system cannot remove a version with a proxy
    try {
      session.removeDocument(version.getRef());
      fail("Admin should not be able to remove version");
    } catch (DocumentSecurityException e) {
      // ok
    }

    // remove the proxy first
    session.removeDocument(proxy.getRef());
    session.save();
    // we can now remove the version
    session.removeDocument(version.getRef());
    session.save();
  }
  @Test
  public void testPublishing() {
    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel doc = session.createDocumentModel("/", "file", "File");
    doc = session.createDocument(doc);
    checkVersions(doc);

    // publish
    DocumentModel proxy = session.publishDocument(doc, folder);
    session.save();
    String versionSeriesId = doc.getVersionSeriesId();
    assertFalse(proxy.isVersion());
    assertTrue(proxy.isProxy());
    assertTrue(proxy.hasFacet(FacetNames.IMMUTABLE));
    assertTrue(proxy.isImmutable());
    assertEquals(versionSeriesId, proxy.getVersionSeriesId());
    assertNotSame(versionSeriesId, proxy.getId());
    assertEquals("0.1", proxy.getVersionLabel());
    assertNull(proxy.getCheckinComment());
    assertFalse(proxy.isMajorVersion());
    assertTrue(proxy.isLatestVersion());
    assertFalse(proxy.isLatestMajorVersion());

    checkVersions(doc, "0.1");
    VersionModel lastVersion = session.getLastVersion(doc.getRef());
    assertNotNull(lastVersion);
    assertEquals("0.1", lastVersion.getLabel());
    DocumentModel lastVersionDocument = session.getLastDocumentVersion(doc.getRef());
    assertNotNull(lastVersionDocument);
    assertEquals("file", lastVersionDocument.getName());
  }
  @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);
  }
  @Test
  public void testPublishingAfterVersionDelete() {
    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel doc = session.createDocumentModel("/", "file", "File");
    doc = session.createDocument(doc);
    checkVersions(doc);

    VersionModel lastVersion = session.getLastVersion(doc.getRef());
    assertNull(lastVersion);
    DocumentModel lastVersionDocument = session.getLastDocumentVersion(doc.getRef());
    assertNull(lastVersionDocument);

    // publish
    DocumentModel proxy = session.publishDocument(doc, folder);
    checkVersions(doc, "0.1");
    lastVersion = session.getLastVersion(doc.getRef());
    assertNotNull(lastVersion);
    assertEquals("0.1", lastVersion.getLabel());
    lastVersionDocument = session.getLastDocumentVersion(doc.getRef());
    assertNotNull(lastVersionDocument);
    assertEquals("file", lastVersionDocument.getName());

    // unpublish
    session.removeDocument(proxy.getRef());
    // delete the version
    List<VersionModel> versions = session.getVersionsForDocument(doc.getRef());
    assertEquals(1, versions.size());
    DocumentModel docVersion = session.getDocumentWithVersion(doc.getRef(), versions.get(0));
    session.removeDocument(docVersion.getRef());

    checkVersions(doc);
    lastVersion = session.getLastVersion(doc.getRef());
    assertNull(lastVersion);
    lastVersionDocument = session.getLastDocumentVersion(doc.getRef());
    assertNull(lastVersionDocument);

    // republish
    DocumentModel newProxy = session.publishDocument(doc, folder);
    checkVersions(doc, "0.2");
    lastVersion = session.getLastVersion(doc.getRef());
    assertNotNull(lastVersion);
    assertEquals("0.2", lastVersion.getLabel());
    lastVersionDocument = session.getLastDocumentVersion(doc.getRef());
    assertNotNull(lastVersionDocument);
    assertEquals("file", lastVersionDocument.getName());
  }
  @Test
  public void testGetLastVersion() {
    DocumentModel doc = session.createDocumentModel("/", "doc", "File");
    doc = session.createDocument(doc);
    session.save();
    DocumentRef v1ref = session.checkIn(doc.getRef(), VersioningOption.MAJOR, null);
    session.checkOut(doc.getRef());
    DocumentRef v2ref = session.checkIn(doc.getRef(), VersioningOption.MINOR, null);

    // last version on the doc
    DocumentModel last = session.getLastDocumentVersion(doc.getRef());
    assertEquals(v2ref.reference(), last.getId());
    DocumentRef lastRef = session.getLastDocumentVersionRef(doc.getRef());
    assertEquals(v2ref.reference(), lastRef.reference());

    // last version on any version
    last = session.getLastDocumentVersion(v2ref);
    assertEquals(v2ref.reference(), last.getId());
    lastRef = session.getLastDocumentVersionRef(v2ref);
    assertEquals(v2ref.reference(), lastRef.reference());
  }
  @Test
  public void testVersionLifecycle() throws Exception {
    DocumentModel root = session.getRootDocument();
    DocumentModel doc = new DocumentModelImpl("/", "doc", "File");

    doc = session.createDocument(doc);
    doc.setProperty("dublincore", "title", "t1");
    doc = session.saveDocument(doc);

    session.publishDocument(doc, root);
    session.save();

    // get version
    DocumentModel ver = session.getLastDocumentVersion(doc.getRef());
    assertTrue(ver.isVersion());

    assertEquals("project", ver.getCurrentLifeCycleState());
    ver.followTransition("approve");
    session.save();

    doc = session.getDocument(new PathRef("/doc"));
    ver = session.getLastDocumentVersion(doc.getRef());
    assertEquals("approved", ver.getCurrentLifeCycleState());
  }
  // security on versions, see TestLocalAPIWithCustomVersioning
  @Test
  public void testVersionSecurity() throws Exception {
    DocumentModel folder = new DocumentModelImpl("/", "folder", "Folder");
    folder = session.createDocument(folder);
    ACP acp = new ACPImpl();
    ACE ace = new ACE("princ1", "perm1", true);
    ACL acl = new ACLImpl("acl1", false);
    acl.add(ace);
    acp.addACL(acl);
    session.setACP(folder.getRef(), acp, true);
    DocumentModel file = new DocumentModelImpl("/folder", "file", "File");
    file = session.createDocument(file);
    // set security
    acp = new ACPImpl();
    ace = new ACE("princ2", "perm2", true);
    acl = new ACLImpl("acl2", false);
    acl.add(ace);
    acp.addACL(acl);
    session.setACP(file.getRef(), acp, true);
    session.save();

    DocumentModel proxy = session.publishDocument(file, folder);
    DocumentModel version = session.getLastDocumentVersion(file.getRef());
    session.save();

    // check security on version
    acp = session.getACP(version.getRef());
    ACL[] acls = acp.getACLs();
    assertEquals(2, acls.length);
    acl = acls[0];
    assertEquals(1, acl.size());
    assertEquals("princ2", acl.get(0).getUsername());
    acl = acls[1];
    assertEquals(1 + 3, acl.size()); // 1 + 3 root defaults
    assertEquals("princ1", acl.get(0).getUsername());

    // remove live document (there's a proxy so the version stays)
    session.removeDocument(file.getRef());
    session.save();
    // recheck security on version (works because we're administrator)
    acp = session.getACP(version.getRef());
    assertNull(acp);
    // check proxy still accessible (in another session)
    try (CoreSession session2 = openSessionAs(SecurityConstants.ADMINISTRATOR)) {
      session2.getDocument(proxy.getRef());
    }
  }
  @Test
  public void testGetDocumentWithVersion() throws Exception {
    String name2 = "file#248";
    DocumentModel childFile = new DocumentModelImpl("/", name2, "File");
    childFile = session.createDocument(childFile);
    session.save();
    DocumentRef v1Ref = session.checkIn(childFile.getRef(), null, null);
    session.checkOut(childFile.getRef());

    childFile.setProperty("file", "filename", "second name");
    childFile.setProperty("dc", "title", "f1");
    childFile.setProperty("dc", "description", "desc 1");
    session.saveDocument(childFile);
    session.save();
    maybeSleepToNextSecond();
    DocumentRef v2Ref = session.checkIn(childFile.getRef(), null, null);

    DocumentModel newDoc = session.getDocument(childFile.getRef());
    assertNotNull(newDoc);
    assertNotNull(newDoc.getRef());
    assertEquals("second name", newDoc.getProperty("file", "filename"));

    // restore, no snapshot as already pristine
    waitForFulltextIndexing();
    maybeSleepToNextSecond();
    DocumentModel restoredDoc = session.restoreToVersion(childFile.getRef(), v1Ref);

    assertNotNull(restoredDoc);
    assertNotNull(restoredDoc.getRef());
    assertNull(restoredDoc.getProperty("file", "filename"));

    DocumentModel last = session.getLastDocumentVersion(childFile.getRef());
    assertNotNull(last);
    assertNotNull(last.getRef());
    assertEquals(v2Ref.reference(), last.getId());
    assertEquals("second name", last.getProperty("file", "filename"));
  }
  @Test
  public void testPublishingAfterCopy() {
    DocumentModel folder = session.createDocumentModel("/", "folder", "Folder");
    folder = session.createDocument(folder);
    DocumentModel doc = session.createDocumentModel("/", "file", "File");
    doc = session.createDocument(doc);
    checkVersions(doc);

    // publish
    DocumentModel proxy = session.publishDocument(doc, folder);
    checkVersions(doc, "0.1");
    DocumentModel lastVersion = session.getLastDocumentVersion(doc.getRef());
    assertNotNull(lastVersion);
    assertEquals("0.1", lastVersion.getVersionLabel());
    DocumentModel lastVersionDocument = session.getLastDocumentVersion(doc.getRef());
    assertNotNull(lastVersionDocument);
    assertEquals("file", lastVersionDocument.getName());

    // copy published file, version is reset
    DocumentModel copy = session.copy(doc.getRef(), folder.getRef(), "fileCopied");
    checkVersions(copy);
    lastVersion = session.getLastDocumentVersion(copy.getRef());
    assertNull(lastVersion);
    lastVersionDocument = session.getLastDocumentVersion(copy.getRef());
    assertNull(lastVersionDocument);

    // republish
    DocumentModel newProxy = session.publishDocument(copy, folder);
    checkVersions(copy, "0.1");
    lastVersion = session.getLastDocumentVersion(copy.getRef());
    assertNotNull(lastVersion);
    assertEquals("0.1", lastVersion.getVersionLabel());
    lastVersionDocument = session.getLastDocumentVersion(copy.getRef());
    assertNotNull(lastVersionDocument);
    assertEquals("fileCopied", lastVersionDocument.getName());
  }
  @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);
  }