mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
2 days ago 97dbf50dd56ee7640411ac61e6aa288f208a4375
opendj-server-legacy/src/test/java/org/opends/server/backends/jdbc/TestCase.java
@@ -22,6 +22,7 @@
import org.opends.server.backends.pluggable.spi.AccessMode;
import org.opends.server.backends.pluggable.spi.Cursor;
import org.opends.server.backends.pluggable.spi.Importer;
import org.opends.server.backends.pluggable.spi.ReadOnlyStorageException;
import org.opends.server.backends.pluggable.spi.ReadOperation;
import org.opends.server.backends.pluggable.spi.ReadableTransaction;
import org.opends.server.backends.pluggable.spi.TreeName;
@@ -320,6 +321,86 @@
      }
   }
   /**
    * A storage opened READ_ONLY must still hand out the write transaction {@code RootContainer.open()} asks for
    * there - otherwise the offline export-ldif, verify-index and backendstat fail before reading anything - and
    * that transaction must serve exactly what the open needs and nothing more: opening an existing tree, reads,
    * cursors and record counts, while every mutation, including a delete through a cursor it opened, is
    * refused (#874).
    */
   @Test
   public void testReadOnlyTransactionReadsButRefusesWrites() throws Exception {
      final JDBCStorage storage = new JDBCStorage(createBackendCfg(), null);
      final TreeName tree = new TreeName("testReadOnlyTransaction", "tree");
      final TreeName absent = new TreeName("testReadOnlyTransaction", "absent");
      try {
         storage.open(AccessMode.READ_WRITE);
         storage.write(new WriteOperation() {
            @Override
            public void run(WriteableTransaction txn) throws Exception {
               txn.openTree(tree, true);
               txn.put(tree, key(0), value(0));
               txn.put(tree, key(1), value(1));
            }
         });
         storage.close();
         storage.open(AccessMode.READ_ONLY);
         storage.write(new WriteOperation() {
            @Override
            public void run(WriteableTransaction txn) throws Exception {
               // what RootContainer.open() does through this transaction in read-only mode
               txn.openTree(tree, false);
               assertEquals(txn.read(tree, key(0)), value(0));
               assertEquals(txn.getRecordCount(tree), 2);
               try (final Cursor<ByteString, ByteString> cursor = txn.openCursor(tree)) {
                  assertTrue(cursor.next());
                  assertEquals(cursor.getKey(), key(0));
                  try {
                     cursor.delete();
                     fail("delete() through a cursor of a read-only transaction must fail");
                  } catch (UnsupportedOperationException expected) {}
               }
               assertReadOnly("openTree(createOnDemand)", () -> txn.openTree(absent, true));
               assertReadOnly("put", () -> txn.put(tree, key(2), value(2)));
               assertReadOnly("update", () -> txn.update(tree, key(0), old -> value(3)));
               assertReadOnly("delete", () -> txn.delete(tree, key(0)));
               assertReadOnly("deleteTree", () -> txn.deleteTree(tree));
            }
         });
         // nothing above reached the database
         storage.close();
         storage.open(AccessMode.READ_WRITE);
         storage.read(new ReadOperation<Void>() {
            @Override
            public Void run(ReadableTransaction txn) throws Exception {
               assertEquals(txn.getRecordCount(tree), 2);
               assertEquals(txn.read(tree, key(0)), value(0));
               return null;
            }
         });
      } finally {
         try {
            storage.write(new WriteOperation() {
               @Override
               public void run(WriteableTransaction txn) throws Exception {
                  txn.deleteTree(tree);
               }
            });
         } catch (Exception ignored) {}
         storage.close();
      }
   }
   private static void assertReadOnly(String operation, Runnable mutation) {
      try {
         mutation.run();
         fail(operation + " must fail on a read-only storage");
      } catch (ReadOnlyStorageException expected) {}
   }
   /** Buffer-served repositioning relies on the database collating keys in unsigned byte order. */
   @Test
   public void testCursorKeyOrderIsUnsigned() throws Exception {