package org.exist.storage;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.exist.EXistException;
import org.exist.security.PermissionDeniedException;
import org.exist.test.ExistEmbeddedServer;
import org.exist.util.LockException;
import org.exist.xmldb.XmldbURI;
import org.exist.test.TestConstants;
import org.exist.collections.Collection;
import org.exist.collections.IndexInfo;
import org.exist.storage.txn.TransactionManager;
import org.exist.storage.txn.Txn;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertNotNull;
import org.junit.ClassRule;
import org.junit.Test;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Optional;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class DirtyShutdownTest {

    private static final Logger LOG = LogManager.getLogger(DirtyShutdownTest.class);

    @ClassRule
    public static final ExistEmbeddedServer existEmbeddedServer = new ExistEmbeddedServer(true, true);
    
    @Test
    public void run() {
        final ExecutorService service = Executors.newSingleThreadExecutor();
        service.execute(() -> storeRepeatedly());

        synchronized (this) {
            try {
                wait(5000);
            } catch (final InterruptedException e) {
                Thread.currentThread().interrupt();
                LOG.error(e.getMessage(), e);
            }
        }
    }

    public void storeRepeatedly() {
        final BrokerPool pool = existEmbeddedServer.getBrokerPool();
        final TransactionManager transact = pool.getTransactionManager();
        try(final DBBroker broker = pool.get(Optional.of(pool.getSecurityManager().getSystemSubject()))) {

            Collection root;

            try(final Txn transaction = transact.beginTransaction()) {
                root = broker.getOrCreateCollection(transaction, TestConstants.TEST_COLLECTION_URI);
                assertNotNull(root);
                broker.saveCollection(transaction, root);
                transact.commit(transaction);
            }

            for (int i = 0; i < 50; i++) {
                try(final Txn transaction = transact.beginTransaction()) {

                    final URL url = getClass().getClassLoader().getResource("/samples/shakespeare/macbeth.xml");
                    final Path f = Paths.get(url.toURI());

                    final IndexInfo info = root.validateXMLResource(transaction, broker, XmldbURI.create("test.xml"), new InputSource(f.toUri().toASCIIString()));
                    assertNotNull(info);
                    root.store(transaction, broker, info, new InputSource(f.toUri().toASCIIString()));

                    transact.commit(transaction);
                }
            }
        } catch (final PermissionDeniedException | EXistException | URISyntaxException | SAXException | LockException | IOException e) {
            LOG.error(e.getMessage(), e);
            fail(e.getMessage());
        }
    }
}

@@ -263,32 +263,84 @@
 .LockException;%0A
+import org.exist.util.io.FastByteArrayOutputStream;%0A
 import org.exist
@@ -556,16 +556,121 @@
 txn.Txn;
+%0A%0Aimport static java.nio.charset.StandardCharsets.UTF_8;%0Aimport static org.exist.samples.Samples.SAMPLES;
 %0Aimport 
@@ -882,32 +882,60 @@
 io.IOException;%0A
+import java.io.InputStream;%0A
 import java.net.
@@ -1089,62 +1089,9 @@
 ent.
-ExecutorService;%0Aimport java.util.concurrent.Executors
+*
 ;%0A%0Ap
@@ -1363,16 +1363,64 @@
 id run()
+ throws ExecutionException, InterruptedException
  %7B%0A     
@@ -1503,47 +1503,174 @@
     
-service.execute(() -%3E storeRepeatedly()
+final Callable%3CVoid%3E callable = () -%3E %7B%0A            storeRepeatedly();%0A            return null;%0A        %7D;%0A        final Future%3CVoid%3E future = service.submit(callable
 );%0A%0A
@@ -1915,24 +1915,137 @@
  %7D%0A        %7D
+%0A%0A        // will raise an exception, failing the test, if the callable raised an exception%0A        future.get();
 %0A    %7D%0A%0A    
@@ -2702,42 +2702,26 @@
    f
-or (int i = 0; i %3C 50; i++) %7B%0A    
+inal String data;%0A
     
@@ -2735,175 +2735,237 @@
  try
+ 
 (final 
-Txn transaction = transact.beginTransaction()) %7B%0A%0A                    final URL url = getClass().getClassLoader().getResource(%22/samples/shakespeare/macbeth.xml%22
+FastByteArrayOutputStream os = new FastByteArrayOutputStream();%0A                 final InputStream is = SAMPLES.getMacbethSample()) %7B%0A                os.write(is);%0A                data = new String(os.toByteArray(), UTF_8
 );%0A 
@@ -2963,32 +2963,39 @@
 UTF_8);%0A        
+    %7D%0A%0A
             fina
@@ -2995,45 +2995,112 @@
    f
-inal Path f = Paths.get(url.toURI());
+or (int i = 0; i %3C 50; i++) %7B%0A                try(final Txn transaction = transact.beginTransaction()) %7B
 %0A%0A  
@@ -3219,50 +3219,12 @@
 %22), 
-new InputSource(f.toUri().toASCIIString())
+data
 );%0A 
@@ -3325,50 +3325,12 @@
 fo, 
-new InputSource(f.toUri().toASCIIString())
+data
 );%0A%0A
@@ -3482,29 +3482,8 @@
 on %7C
- URISyntaxException %7C
  SAX

Test previously raised an exception but passed, now runs correctly