IGNITE-3601 Added tests for "Read-only optimistic transaction shouldn't throw an exception if entry version was not changed". This closes #915.
diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryAbstractTest.java
index 34480a2..b9f4b02 100644
--- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryAbstractTest.java
+++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheGetEntryAbstractTest.java
@@ -40,6 +40,7 @@
 import org.apache.ignite.transactions.Transaction;
 import org.apache.ignite.transactions.TransactionConcurrency;
 import org.apache.ignite.transactions.TransactionIsolation;
+import org.apache.ignite.transactions.TransactionOptimisticException;
 import org.jetbrains.annotations.Nullable;
 
 import static org.apache.ignite.cache.CacheAtomicityMode.ATOMIC;
@@ -52,6 +53,7 @@
 import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
 import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED;
 import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
 
 /**
  * Test getEntry and getEntries methods.
@@ -247,6 +249,10 @@
 
                 testConcurrentTx(cache, PESSIMISTIC, REPEATABLE_READ, oneEntry);
                 testConcurrentTx(cache, PESSIMISTIC, READ_COMMITTED, oneEntry);
+
+                testConcurrentOptimisticTxGet(cache, REPEATABLE_READ);
+                testConcurrentOptimisticTxGet(cache, READ_COMMITTED);
+                testConcurrentOptimisticTxGet(cache, SERIALIZABLE);
             }
         }
         finally {
@@ -256,6 +262,37 @@
 
     /**
      * @param cache Cache.
+     * @param txIsolation Transaction isolation.
+     * @throws Exception If failed.
+     */
+    private void testConcurrentOptimisticTxGet(final IgniteCache<Integer, TestValue> cache,
+        final TransactionIsolation txIsolation) throws Exception {
+        GridTestUtils.runMultiThreaded(new Runnable() {
+            @Override public void run() {
+                final int key = 42;
+
+                IgniteTransactions txs = grid(0).transactions();
+
+                cache.put(key, new TestValue(key));
+
+                long stopTime = System.currentTimeMillis() + 3000;
+
+                while (System.currentTimeMillis() < stopTime) {
+                    try (Transaction tx = txs.txStart(OPTIMISTIC, txIsolation)) {
+                        cache.get(key);
+
+                        tx.commit();
+                    }
+                    catch (TransactionOptimisticException e) {
+                        fail("Should not throw optimistic exception in only read TX. Tx isolation: " + txIsolation);
+                    }
+                }
+            }
+        }, 10, "tx-thread");
+    }
+
+    /**
+     * @param cache Cache.
      * @param txConcurrency Transaction concurrency.
      * @param txIsolation Transaction isolation.
      * @param oneEntry If {@code true} then single entry is tested.