Package org.hibernate.ogm.datastore.couchdb.test.dialect.optimisticlocking

Source Code of org.hibernate.ogm.datastore.couchdb.test.dialect.optimisticlocking.ConcurrentModificationTest

/*
* Hibernate OGM, Domain model persistence for NoSQL datastores
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.ogm.datastore.couchdb.test.dialect.optimisticlocking;

import static org.fest.assertions.Assertions.assertThat;

import java.util.concurrent.Callable;
import java.util.concurrent.Executors;

import org.hibernate.Session;
import org.hibernate.StaleObjectStateException;
import org.hibernate.Transaction;
import org.hibernate.ogm.utils.OgmTestCase;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
* Tests for concurrent updates of CouchDB entities with mapped revision property.
*
* @author Gunnar Morling
*/
public class ConcurrentModificationTest extends OgmTestCase {

  private Session session;

  @Before
  public void createSession() {
    session = openSession();
  }

  @After
  public void deleteTestDataAndCloseSession() {
    session.clear();
    if ( session.getTransaction().isActive() ) {
      session.getTransaction().rollback();
    }
    Transaction transaction = session.beginTransaction();

    Novel novel = (Novel) session.get( Novel.class, "novel-1" );
    if ( novel != null ) {
      session.delete( novel );
    }

    Animal animal = (Animal) session.get( Animal.class, "animal-1" );
    if ( animal != null ) {
      session.delete( animal );
    }

    animal = (Animal) session.get( Animal.class, "animal-2" );
    if ( animal != null ) {
      session.delete( animal );
    }

    Zoo zoo = (Zoo) session.get( Zoo.class, "zoo-1" );
    if ( zoo != null ) {
      session.delete( zoo );
    }

    Contributor contributor = (Contributor) session.get( Contributor.class, "contributor-1" );
    if ( contributor != null ) {
      session.delete( contributor );
    }

    contributor = (Contributor) session.get( Contributor.class, "contributor-2" );
    if ( contributor != null ) {
      session.delete( contributor );
    }

    Project project = (Project) session.get( Project.class, "project-1" );
    if ( project != null ) {
      session.delete( project );
    }

    project = (Project) session.get( Project.class, "project-2" );
    if ( project != null ) {
      session.delete( project );
    }

    project = (Project) session.get( Project.class, "project-3" );
    if ( project != null ) {
      session.delete( project );
    }

    ProjectGroup projectGroup = (ProjectGroup) session.get( ProjectGroup.class, "project-group-1" );
    if ( projectGroup != null ) {
      session.delete( projectGroup );
    }

    transaction.commit();
    session.close();
  }

  @Test(expected = StaleObjectStateException.class)
  public void concurrentModificationShouldCauseException() throws Exception {
    Novel novel = createAndPersistNovel();

    String newRevision = doConcurrentUpdateToNovel();
    assertThat( newRevision ).isNotEqualTo( novel.get_rev() );

    Transaction transaction = session.beginTransaction();
    novel.setDescription( "Description 2" );
    transaction.commit();
  }

  @Test(expected = StaleObjectStateException.class)
  public void mergeAfterConcurrentModificationShouldCauseException() throws Exception {
    Novel novel = createAndPersistNovel();
    session.clear();

    doConcurrentUpdateToNovel();

    session.beginTransaction();
    novel = (Novel) session.merge( novel );
  }

  @Test(expected = StaleObjectStateException.class)
  public void updateAfterConcurrentDeletionShouldCauseException() throws Exception {
    createAndPersistNovel();
    session.clear();

    Transaction transaction = session.beginTransaction();

    Novel novel = (Novel) session.get( Novel.class, "novel-1" );
    concurrentlyDeleteNovel();
    novel.setPosition( 2 );

    transaction.commit();
  }

  @Test(expected = StaleObjectStateException.class)
  public void deletionAfterConcurrentModificationShouldCauseException() throws Exception {
    Novel novel = createAndPersistNovel();

    doConcurrentUpdateToNovel();

    Transaction transaction = session.beginTransaction();
    session.delete( novel );
    transaction.commit();
  }

  private Novel createAndPersistNovel() {
    Transaction transaction = session.beginTransaction();

    Novel novel = createNovel();

    assertThat( novel.get_rev() ).isNull();
    session.persist( novel );
    transaction.commit();
    assertThat( novel.get_rev() ).isNotNull();
    return novel;
  }

  private Novel createNovel() {
    Novel novel = new Novel();
    novel.setId( "novel-1" );
    novel.setDescription( "Description 1" );
    novel.setPosition( 1 );

    return novel;
  }

  private String doConcurrentUpdateToNovel() throws Exception {
    return Executors.newSingleThreadExecutor().submit( new Callable<String>() {

      @Override
      public String call() throws Exception {
        Session session = openSession();

        Transaction transaction = session.beginTransaction();
        final Novel novel = (Novel) session.get( Novel.class, "novel-1" );
        novel.setDescription( "Description 2" );
        transaction.commit();

        return novel.get_rev();
      }
    } ).get();
  }

  private String concurrentlyDeleteNovel() throws Exception {
    return Executors.newSingleThreadExecutor().submit( new Callable<String>() {

      @Override
      public String call() throws Exception {
        Session session = openSession();

        Transaction transaction = session.beginTransaction();
        final Novel novel = (Novel) session.get( Novel.class, "novel-1" );
        session.delete( novel );
        transaction.commit();

        return novel.get_rev();
      }
    } ).get();
  }

  @Test(expected = StaleObjectStateException.class)
  public void customColumnNameShouldBeUsableForRevisionProperty() throws Exception {
    Animal animal = createAndPersistAnimal();

    String newRevision = doConcurrentUpdateToAnimal();
    assertThat( newRevision ).isNotEqualTo( animal.getRevision() );

    Transaction transaction = session.beginTransaction();
    animal.setName( "Xavier" );
    transaction.commit();
  }

  @Test
  public void canUpdateObjectPropertyAfterUpdateOfAssociationStoredInEntity() {
    Animal animal1 = createAndPersistAnimal();
    Animal animal2 = createAndPersistAnotherAnimal();
    Zoo zoo = createAndPersistZoo( animal1 );

    Transaction transaction = session.beginTransaction();

    zoo.getAnimals().add( animal2 );
    zoo.setName( "Hilwelma" );

    transaction.commit();

    transaction = session.beginTransaction();

    zoo = (Zoo) session.get( Zoo.class, "zoo-1" );
    assertThat( zoo.getName() ).isEqualTo( "Hilwelma" );
    assertThat( zoo.getAnimals() ).onProperty( "name" ).containsOnly( "Bruno", "Berta" );

    transaction.commit();
  }

  @Test
  public void canUpdateEntityAfterUpdateOfAssociationStoredInEntityOnInverseSide() {
    Project project = createAndPersistProjectWithProjectGroup();

    Transaction transaction = session.beginTransaction();

    project.getProjectGroup().setName( "Fancy projects" );

    transaction.commit();

    transaction = session.beginTransaction();

    ProjectGroup projectGroup = (ProjectGroup) session.get( ProjectGroup.class, "project-group-1" );
    assertThat( projectGroup.getName() ).isEqualTo( "Fancy projects" );
    assertThat( projectGroup.getProjects() ).onProperty( "name" ).containsOnly( "Validator" );

    transaction.commit();
  }

  @Test
  public void canUpdateEntityAfterRemovalOfAssociationStoredInEntityOnInverseSide() {
    Project project = createAndPersistProjectWithProjectGroup();
    ProjectGroup projectGroup = project.getProjectGroup();

    Transaction transaction = session.beginTransaction();

    projectGroup.getProjects().remove( project );
    project.setProjectGroup( null );

    transaction.commit();

    transaction = session.beginTransaction();

    projectGroup.setName( "Fancy projects" );

    transaction.commit();

    transaction = session.beginTransaction();

    projectGroup = (ProjectGroup) session.get( ProjectGroup.class, "project-group-1" );
    assertThat( projectGroup.getName() ).isEqualTo( "Fancy projects" );
    assertThat( projectGroup.getProjects() ).isEmpty();

    transaction.commit();
  }

  @Test
  public void canUpdateEntityOnInverseSideOfManyToManyAssocationAfterUpdateToAssociation() throws Exception {
    // given
    Project search = createAndPersistProjectWithUser();
    Project ogm = createAndPersistProjectWithContributor();

    // when
    Transaction transaction = session.beginTransaction();
    User bob = search.getUsers().iterator().next();
    bob.getProjects().add( ogm );
    ogm.getUsers().add( bob );
    transaction.commit();

    transaction = session.beginTransaction();
    bob.setName( "Alice" );
    transaction.commit();
    session.clear();

    // then
    transaction = session.beginTransaction();
    bob = (User) session.get( User.class, "user-1" );
    assertThat( bob.getName() ).isEqualTo( "Alice" );
    assertThat( bob.getProjects() ).onProperty( "name" ).containsOnly( "OGM", "Search" );
    transaction.commit();
  }

  @Test(expected = StaleObjectStateException.class)
  public void concurrentUpdateToAssociationShouldCauseException() throws Exception {
    Animal animal = createAndPersistAnimal();
    Zoo zoo = createAndPersistZoo( animal );

    doConcurrentUpdateToTheZoosAnimals();

    Transaction transaction = session.beginTransaction();
    zoo.getAnimals().remove( zoo.getAnimals().iterator().next() );
    transaction.commit();
  }

  @Test(expected = StaleObjectStateException.class)
  public void concurrentUpdateToObjectShouldCauseExceptionWhenUpdatingAssociation() throws Exception {
    Animal animal = createAndPersistAnimal();
    Zoo zoo = createAndPersistZoo( animal );

    doConcurrentUpdateToZoo();

    Transaction transaction = session.beginTransaction();
    zoo.getAnimals().remove( zoo.getAnimals().iterator().next() );
    transaction.commit();
  }

  @Test
  public void concurrentUpdateToObjectShouldCauseNoExceptionWithAssociationExcludedFromOptimisticLocking() throws Exception {
    Project ogm = createAndPersistProjectWithContributor();

    doConcurrentUpdateToProject();

    Transaction transaction = session.beginTransaction();
    ogm.setName( "OGM!" );
    transaction.commit();
    session.clear();

    transaction = session.beginTransaction();

    ogm = (Project) session.get( Project.class, "project-1" );
    assertThat( ogm.getName() ).isEqualTo( "OGM!" );
    assertThat( ogm.getMembers() ).onProperty( "name" ).containsOnly( "Davide", "Sanne" );

    transaction.commit();
  }

  private Animal createAndPersistAnimal() {
    Animal animal = new Animal();
    animal.setId( "animal-1" );
    animal.setName( "Bruno" );

    Transaction transaction = session.beginTransaction();
    assertThat( animal.getRevision() ).isNull();
    session.persist( animal );
    transaction.commit();
    assertThat( animal.getRevision() ).isNotNull();

    return animal;
  }

  private Animal createAndPersistAnotherAnimal() {
    return createAndPersistAnotherAnimal( session );
  }

  private Animal createAndPersistAnotherAnimal(Session session) {
    Animal animal = new Animal();
    animal.setId( "animal-2" );
    animal.setName( "Berta" );

    Transaction transaction = session.beginTransaction();
    assertThat( animal.getRevision() ).isNull();
    session.persist( animal );
    transaction.commit();
    assertThat( animal.getRevision() ).isNotNull();

    return animal;
  }

  private Zoo createAndPersistZoo(Animal animal) {
    Zoo zoo = new Zoo();
    zoo.setId( "zoo-1" );
    zoo.setName( "Bagenhecks Tierpark" );
    zoo.getAnimals().add( animal );

    Transaction transaction = session.beginTransaction();
    session.persist( zoo );
    transaction.commit();

    return zoo;
  }

  private String doConcurrentUpdateToAnimal() throws Exception {
    return Executors.newSingleThreadExecutor().submit( new Callable<String>() {

      @Override
      public String call() throws Exception {
        Session session = openSession();

        Transaction transaction = session.beginTransaction();
        final Animal animal = (Animal) session.get( Animal.class, "animal-1" );
        animal.setName( "Xavier" );
        transaction.commit();

        return animal.getRevision();
      }
    } ).get();
  }

  private String doConcurrentUpdateToTheZoosAnimals() throws Exception {
    return Executors.newSingleThreadExecutor().submit( new Callable<String>() {

      @Override
      public String call() throws Exception {
        Session session = openSession();

        Animal berta = createAndPersistAnotherAnimal( session );

        Transaction transaction = session.beginTransaction();
        final Zoo zoo = (Zoo) session.get( Zoo.class, "zoo-1" );
        zoo.getAnimals().add( berta );
        transaction.commit();

        return zoo.getRevision();
      }
    } ).get();
  }

  private String doConcurrentUpdateToZoo() throws Exception {
    return Executors.newSingleThreadExecutor().submit( new Callable<String>() {

      @Override
      public String call() throws Exception {
        Session session = openSession();
        Transaction transaction = session.beginTransaction();

        final Zoo zoo = (Zoo) session.get( Zoo.class, "zoo-1" );
        zoo.setName( "Hilwema" );

        transaction.commit();
        return zoo.getRevision();
      }
    } ).get();
  }

  private Project createAndPersistProjectWithContributor() {
    Transaction transaction = session.beginTransaction();

    Project ogm = new Project();
    ogm.setId( "project-1" );
    ogm.setName( "OGM" );
    session.persist( ogm  );

    Contributor davide = new Contributor();
    davide.setId( "contributor-1" );
    davide.setName( "Davide" );
    session.persist( davide );

    ogm.getMembers().add( davide );
    davide.getProjects().add( ogm );

    transaction.commit();
    return ogm;
  }

  private Project createAndPersistProjectWithUser() {
    Transaction transaction = session.beginTransaction();

    Project ogm = new Project();
    ogm.setId( "project-2" );
    ogm.setName( "Search" );
    session.persist( ogm  );

    User bob = new User();
    bob.setId( "user-1" );
    bob.setName( "Bob" );
    session.persist( bob );

    ogm.getUsers().add( bob );
    bob.getProjects().add( ogm );

    transaction.commit();
    return ogm;
  }

  private Project createAndPersistProjectWithProjectGroup() {
    Transaction transaction = session.beginTransaction();

    Project validator = new Project();
    validator.setId( "project-3" );
    validator.setName( "Validator" );
    session.persist( validator  );

    ProjectGroup hibernateProjects = new ProjectGroup();
    hibernateProjects.setId( "project-group-1" );
    hibernateProjects.setName( "Hibernate" );
    session.persist( hibernateProjects );

    validator.setProjectGroup( hibernateProjects );
    hibernateProjects.getProjects().add( validator );

    transaction.commit();
    return validator;
  }

  private String doConcurrentUpdateToProject() throws Exception {
    return Executors.newSingleThreadExecutor().submit( new Callable<String>() {

      @Override
      public String call() throws Exception {
        Session session = openSession();

        Transaction transaction = session.beginTransaction();
        final Project project = (Project) session.get( Project.class, "project-1" );

        Contributor sanne = new Contributor();
        sanne.setId( "contributor-2" );
        sanne.setName( "Sanne" );

        sanne.getProjects().add( project );
        project.getMembers().add( sanne );

        session.persist( sanne );

        transaction.commit();

        return project.getRevision();
      }
    } ).get();
  }

  @Override
  protected Class<?>[] getAnnotatedClasses() {
    return new Class<?>[] { Novel.class, Animal.class, Zoo.class, Project.class, Contributor.class, User.class, ProjectGroup.class };
  }
}
TOP

Related Classes of org.hibernate.ogm.datastore.couchdb.test.dialect.optimisticlocking.ConcurrentModificationTest

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.