This is an automated email from the ASF dual-hosted git repository. ntimofeev pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/cayenne.git
commit 8af684a960a304049b0f6383e00ead7a47a5bfa2 Author: Dmitriy Tarasenko <dmitriy.tarasie...@gmail.com> AuthorDate: Sat May 29 21:48:47 2021 +0300 feat: tests for descriptor and listeners new properties --- .../apache/cayenne/tx/TransactionDescriptor.java | 13 +- .../cayenne/tx/DefaultTransactionManagerIT.java | 8 +- .../cayenne/tx/TransactionCustomConnectionIT.java | 226 +++++++++++++++++++++ .../apache/cayenne/tx/TransactionIsolationIT.java | 2 +- .../tx/TransactionPropagationRollbackIT.java | 6 +- 5 files changed, 243 insertions(+), 12 deletions(-) diff --git a/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionDescriptor.java b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionDescriptor.java index ecb273a..3ced787 100644 --- a/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionDescriptor.java +++ b/cayenne-server/src/main/java/org/apache/cayenne/tx/TransactionDescriptor.java @@ -52,7 +52,7 @@ public class TransactionDescriptor { * <code>TransactionDescriptor.ISOLATION_DEFAULT</code> * @param propagation transaction propagation behaviour * @see TransactionPropagation - * @deprecated since 4.2.M4. Use builder instead + * @deprecated since 4.2. Use builder instead */ @Deprecated public TransactionDescriptor(int isolation, TransactionPropagation propagation) { @@ -78,7 +78,7 @@ public class TransactionDescriptor { /** * @param propagation transaction propagation behaviour * @see TransactionPropagation - * @deprecated since 4.2.M4. Use builder instead + * @deprecated since 4.2. Use builder instead */ @Deprecated public TransactionDescriptor(TransactionPropagation propagation) { @@ -106,14 +106,19 @@ public class TransactionDescriptor { return customConnectionSupplier; } + public static Builder builder(){ + return new Builder(); + } + /** * Builder class for TransactionDescriptor. - * - * @since 4.2.M4 + * @since 4.2 */ public static class Builder { private final TransactionDescriptor transactionDescriptor = new TransactionDescriptor(); + private Builder(){} + /** * @param isolation one of the following <code>Connection</code> constants: * <code>Connection.TRANSACTION_READ_UNCOMMITTED</code>, diff --git a/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java b/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java index ef9de67..276b258 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/tx/DefaultTransactionManagerIT.java @@ -86,7 +86,7 @@ public class DefaultTransactionManagerIT { assertSame(tx, BaseTransaction.getThreadTransaction()); return expectedResult; }, - new TransactionDescriptor.Builder() + TransactionDescriptor.builder() .propagation(TransactionPropagation.NESTED) .build() ); @@ -111,7 +111,7 @@ public class DefaultTransactionManagerIT { assertSame(tx, BaseTransaction.getThreadTransaction()); return expectedResult; }, - new TransactionDescriptor.Builder() + TransactionDescriptor.builder() .propagation(TransactionPropagation.MANDATORY) .build() ); @@ -137,7 +137,7 @@ public class DefaultTransactionManagerIT { assertSame(tx, BaseTransaction.getThreadTransaction()); return expectedResult; }, - new TransactionDescriptor.Builder() + TransactionDescriptor.builder() .propagation(TransactionPropagation.MANDATORY) .build() ); @@ -169,7 +169,7 @@ public class DefaultTransactionManagerIT { assertSame(tx2, BaseTransaction.getThreadTransaction()); return expectedResult; }, - new TransactionDescriptor.Builder() + TransactionDescriptor.builder() .propagation(TransactionPropagation.REQUIRES_NEW) .build() ); diff --git a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionCustomConnectionIT.java b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionCustomConnectionIT.java new file mode 100644 index 0000000..90f2397 --- /dev/null +++ b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionCustomConnectionIT.java @@ -0,0 +1,226 @@ +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + ****************************************************************/ + +package org.apache.cayenne.tx; + +import org.apache.cayenne.access.DataContext; +import org.apache.cayenne.configuration.server.ServerRuntime; +import org.apache.cayenne.di.Inject; +import org.apache.cayenne.log.JdbcEventLogger; +import org.apache.cayenne.query.ObjectSelect; +import org.apache.cayenne.testdo.testmap.Artist; +import org.apache.cayenne.unit.di.server.CayenneProjects; +import org.apache.cayenne.unit.di.server.ServerCase; +import org.apache.cayenne.unit.di.server.UseServerRuntime; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.Assert.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.*; + +/** + * Check if connection can be decorated with listeners and that default connection of TransactionDescriptor + * has major priority + * + * @see BaseTransaction,TransactionDescriptor + * @since 4.2 + */ +@UseServerRuntime(CayenneProjects.TESTMAP_PROJECT) +public class TransactionCustomConnectionIT extends ServerCase { + + private final Logger logger = LoggerFactory.getLogger(TransactionIsolationIT.class); + + @Inject + DataContext context; + + @Inject + ServerRuntime runtime; + + @Inject + private JdbcEventLogger jdbcEventLogger; + + TransactionManager manager; + private static boolean firstReadonlyCondition; + + @Before + public void initTransactionManager() { + // no binding in test container, get it from runtime + manager = runtime.getInjector().getInstance(TransactionManager.class); + } + + /** + * Test depends on decoration of readonly property of the connection, but not every driver supports readonly setting. + * So this test calculated for drivers with current support, but if it is not supported, this test mustn't fail + * because it checks if readonly wasn't changed by setter and changes firstReadonlyCondition flag value + * if it is true to avoid fails. In that case test is useless, but it's behavior in other cases can submit + * right behavior of methods + */ + @Test + public void testConnectionDecorationWithListeners() { + Transaction t = new CayenneTransaction(jdbcEventLogger); + //add listeners which will check if connection object will be changed after every decorate call + List<TransactionListener> listeners = addAndGetListenersWithCustomReadonlyTo(t); + BaseTransaction.bindThreadTransaction(t); + try { + ObjectSelect.query(Artist.class).select(context); + + //check if the last listener set readonly property to false + t.getConnections().forEach((key, connection) -> { + try { + assertEquals(connection.isReadOnly(), firstReadonlyCondition); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + }); + + //check if every decoration from listener was called + for (TransactionListener transactionListener : listeners) { + verify(transactionListener).decorateConnection(any(), any()); + } + } finally { + BaseTransaction.bindThreadTransaction(null); + t.commit(); + } + } + + private List<TransactionListener> addAndGetListenersWithCustomReadonlyTo(Transaction t) { + Class<?>[] classes = new Class[]{ListenerWithFirstReadonlyDecorator.class, ListenerWithSecondReadonlyDecorator.class}; + List<TransactionListener> listeners = new ArrayList<>(); + for (Class<?> aClass : classes) { + TransactionListener listener = (TransactionListener) mock(aClass); + listeners.add(listener); + when(listener.decorateConnection(any(), any())).thenCallRealMethod(); + t.addListener(listener); + } + return listeners; + } + + //listener, which will check if readonly property of connection is false and set it to true + class ListenerWithFirstReadonlyDecorator implements TransactionListener { + + @Override + public void willCommit(Transaction tx) { + + } + + @Override + public void willRollback(Transaction tx) { + + } + + @Override + public void willAddConnection(Transaction tx, String connectionName, Connection connection) { + + } + + @Override + public Connection decorateConnection(Transaction tx, Connection connection) { + try { + firstReadonlyCondition = connection.isReadOnly(); + connection.setReadOnly(!firstReadonlyCondition); + + if (connection.isReadOnly() == firstReadonlyCondition) { + firstReadonlyCondition = !connection.isReadOnly(); + } + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + return connection; + } + } + + //listener, which will check if readonly property of connection is true and set it to false + class ListenerWithSecondReadonlyDecorator implements TransactionListener { + + @Override + public void willCommit(Transaction tx) { + + } + + @Override + public void willRollback(Transaction tx) { + + } + + @Override + public void willAddConnection(Transaction tx, String connectionName, Connection connection) { + + } + + @Override + public Connection decorateConnection(Transaction tx, Connection connection) { + try { + assertEquals(!firstReadonlyCondition, connection.isReadOnly()); + connection.setReadOnly(!connection.isReadOnly()); + if (connection.isReadOnly() == !firstReadonlyCondition) { + firstReadonlyCondition = !firstReadonlyCondition; + } + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + return connection; + } + } + + @Test + public void testDefaultConnectionInDescriptor() { + Transaction t = new CayenneTransaction(jdbcEventLogger); + BaseTransaction.bindThreadTransaction(t); + try { + ObjectSelect.query(Artist.class).select(context); + Connection connection = t.getConnections().values().stream().findFirst().get(); + + try { + connection.setAutoCommit(true); + } catch (SQLException throwables) { + throwables.printStackTrace(); + } + + TransactionDescriptor mockDescriptor = mock(TransactionDescriptor.class); + when(mockDescriptor.getCustomConnectionSupplier()).thenReturn(() -> connection); + when(mockDescriptor.getPropagation()).thenReturn(TransactionPropagation.REQUIRES_NEW); + when(mockDescriptor.getIsolation()).thenReturn(Connection.TRANSACTION_SERIALIZABLE); + + performInTransaction(mockDescriptor); + verify(mockDescriptor, times(2)).getCustomConnectionSupplier(); + } finally { + BaseTransaction.bindThreadTransaction(null); + t.commit(); + } + + } + + private void performInTransaction(TransactionDescriptor descriptor) { + Artist artist = context.newObject(Artist.class); + artist.setArtistName("test"); + manager.performInTransaction(() -> { + artist.setArtistName("test3"); + context.commitChanges(); + return null; + }, descriptor); + } +} diff --git a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionIsolationIT.java b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionIsolationIT.java index c2d00af..3bdefee 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionIsolationIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionIsolationIT.java @@ -74,7 +74,7 @@ public class TransactionIsolationIT extends ServerCase { return; } - TransactionDescriptor descriptor = new TransactionDescriptor.Builder() + TransactionDescriptor descriptor = TransactionDescriptor.builder() .propagation(TransactionPropagation.REQUIRES_NEW) .isolation(Connection.TRANSACTION_SERIALIZABLE) .build(); diff --git a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionPropagationRollbackIT.java b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionPropagationRollbackIT.java index cd6c937..8306d2e 100644 --- a/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionPropagationRollbackIT.java +++ b/cayenne-server/src/test/java/org/apache/cayenne/tx/TransactionPropagationRollbackIT.java @@ -69,7 +69,7 @@ public class TransactionPropagationRollbackIT extends ServerCase { */ @Test public void testPropagationRequiresNew() { - TransactionDescriptor descriptor = new TransactionDescriptor.Builder() + TransactionDescriptor descriptor = TransactionDescriptor.builder() .propagation(TransactionPropagation.REQUIRES_NEW) .isolation(Connection.TRANSACTION_SERIALIZABLE) .build(); @@ -89,7 +89,7 @@ public class TransactionPropagationRollbackIT extends ServerCase { @Test public void testPropagationNested() { - TransactionDescriptor descriptor = new TransactionDescriptor.Builder() + TransactionDescriptor descriptor = TransactionDescriptor.builder() .isolation(Connection.TRANSACTION_SERIALIZABLE) .propagation(TransactionPropagation.NESTED) .build(); @@ -109,7 +109,7 @@ public class TransactionPropagationRollbackIT extends ServerCase { @Test public void testPropagationMandatory() { - TransactionDescriptor descriptor = new TransactionDescriptor.Builder() + TransactionDescriptor descriptor = TransactionDescriptor.builder() .isolation(Connection.TRANSACTION_SERIALIZABLE) .propagation(TransactionPropagation.MANDATORY) .build();