Question

Je suis en train de créer des tests d'intégration pour une application héritée déployée sur Weblogic 8.1 en utilisant une sous-classe de AbstractTransactionalJUnit4SpringContextTests.

Ma méthode de test a les annotations suivantes:

@Test
@Rollback(true)
public void testDeployedEJBCall throws Exception {...}

Ma classe de test fait référence aussi des haricots de type org.springframework.ejb.access.SimpleRemoteStatelessSessionProxyFactoryBean, qui proxy les EJB déployés sur mon serveur weblogic.

Quand j'appelle des méthodes sur ce grain de proxy de manière à ma méthode séquentiel de test, la transaction est annulée correctement à la fin du test.

par exemple. :

@Test
@Rollback(true)
public void testDeployedEJBCall throws Exception {
    Long result1 = myejb.method(100L);
    Long result2 = myejb.method(200L);
    ...
}

Cependant, je voudrais faire 2 appels parallèles à la même méthode EJB. Par conséquent, je l'ai fait une classe interne qui implémente appelable, afin d'appeler mes méthodes en 2 fils et espérer courir ceux en parallèle.
Cependant, cela semble rendre les méthodes ejb à appeler en dehors de ma transaction, et rien est annulée.

Voici ce que la classe test complet souhaite quand je lance les appels de méthode en parallèle:

import org.springframework.test.annotation.*;

@RunWith(SpringJUnit4ClassRunner.class)
@Transactional
@ContextConfiguration(locations = {"classpath:path/to/tests-config.xml"})
@TransactionConfiguration(defaultRollback=true)
public final class IntegrationTests extends AbstractTransactionalJUnit4SpringContextTests {
    @Autowired
    protected JndiTemplate jndiTemplate;
    @Resource
    protected Proxy myEJB;

    public IntegrationTests() {
        super();
        this.logger = Logger.getLogger(IntegrationTests.class);
    }

    @Test
    @Rollback(true)
    public void testDeployedEJBCall() throws Exception {
        // Create a thread pool for parallel execution. 
        ExecutorService exec = Executors.newFixedThreadPool(2);

        // Prepare the tasks for parallel execution
        List<CallEJBTask> tasks = new ArrayList<CallEJBTask>();
        tasks.add(new CallEJBTask(100L, this.myEJB));
        tasks.add(new CallEJBTask(200L, this.myEJB));

        // Execute all pending tasks in the exec Threadpool
        List<Future<Long>> results = exec.invokeAll(tasks);

        // Get the results of each task
        Long result1 = results.get(0).get();
        Long result2 = results.get(1).get();

        ...
    }
}

private class CallEBJTask implements Callable<Long> {
    private final Long valueToTest;
    private final MyEJB myEJB;

    public CallEJBTask(Long valueToTest, Proxy myEJBProxy)
        this.valueToTest = valueToTest;
        this.myEJB = (MyEJB)myEJBProxy;
    }

    public Long call() throws Exception {
        return getResult();
    }

    public Long getResult() {
        Long result = null;

        try {
            result = this.myEJB.method(this.patient);

        } catch (Exception e) {
            ...
        }
        return result;   
    } 
}

Y at-il un moyen de faire ce rollback ???

Merci pour votre aide.

Cordialement,

Philippe

Était-ce utile?

La solution

Pas automatiquement, non. Le problème est que les deux fils supplémentaires ne participent pas à la transaction, d'où leurs actions ne rollback pas.

Quel est le but des deux exécutions parallèles? Vous pourrez probablement tester les problèmes de concurrence avec cette approche, si c'est ce que vous visez pour.

Edit: Le problème est que le dépistage des problèmes de concurrence est très difficile, parce que vos tests sont, au mieux, probabiliste - succès ou l'échec dépendent des problèmes de synchronisation subtils qui peuvent seule surface sur la piste milliardième . Voir cet article Serverside pour un bon résumé des principes de base.

La règle de base devrait être d'éviter enfilage de codage main chaque fois que possible, car il est difficile d'obtenir le droit et difficile à tester. Si vous le pouvez, éviter un état partagé entre les threads, et s'il n'y a pas moyen de contourner cela, appuyer sur les structures de données simultanées et exécuteurs asynchrones du paquet java.util.concurrent.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top