package org.sqlite;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import static org.junit.Assert.assertEquals;

import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

public class BusyHandlerTest {
    private Connection conn;
    private Statement stat;

    @Before
    public void connect() throws Exception {
        conn = DriverManager.getConnection("jdbc:sqlite:test.db");
        stat = conn.createStatement();
    }

    @After
    public void close() throws SQLException {
        stat.close();
        conn.close();
    }

    public class BusyWork extends Thread {
        private final Connection conn;
        private final Statement stat;
        
        public BusyWork() throws Exception {
            conn = DriverManager.getConnection("jdbc:sqlite:test.db");
            stat = conn.createStatement();
            stat.setQueryTimeout(10);
        }
        
        @Override
        public void run(){

            try {
                synchronized(this) {
                    // Generate some work for the sqlite vm
                    stat.executeUpdate("drop table if exists foo;");
                    stat.executeUpdate("create table foo (id integer);");

                    int i = 0;
                    while (i<10000) {
                        String stmt = "insert into foo (id) values (" + i + ")";
                        stat.addBatch(stmt);
                        i++;
                    }
                }
            } catch (SQLException ex) {System.out.println("HERE"+ex.toString());}

            try {
                stat.executeBatch();
            } catch (SQLException ex) {System.out.println("BLOB"+ex.toString());}
        }
    }
    
    private void workWork() throws SQLException, InterruptedException {
        // I let busyWork inject first so it can busy the db
        Thread.sleep(1000);
        
        // Generate some work for the sqlite vm
        int i = 0;
        while (i<100) {
            stat.executeQuery("insert into foo (id) values (" + i + ")");
            i++;
        }
    }

    @Test
    public void basicBusyHandler() throws Exception {
        final int[] calls = {0};
        BusyHandler.setHandler(conn, new BusyHandler() {
            @Override
            protected int callback(int nbPrevInvok) throws SQLException {
                assertTrue(calls[0] == nbPrevInvok);
                calls[0]++;
                
                if (nbPrevInvok <= 1) {
                    return 1;
                } else {
                    return 0;
                }
            }
        });
        
        BusyWork busyWork = new BusyWork();
        busyWork.start();
        
        // I let busyWork prepare a huge insert
        Thread.sleep(1000);
        
        synchronized(busyWork){ 
            try{
                workWork();
            } catch(SQLException ex) {
                assertTrue(ex.getErrorCode() == SQLiteErrorCode.SQLITE_BUSY.code);
            }
        }
        
        busyWork.interrupt();
        assertTrue(calls[0] == 3);
    }

    @Test
    public void testUnregister() throws Exception {
        final int[] calls = {0};
        BusyHandler.setHandler(conn, new BusyHandler() {
            @Override
            protected int callback(int nbPrevInvok) throws SQLException {
                assertTrue(calls[0] == nbPrevInvok);
                calls[0]++;
                
                if (nbPrevInvok <= 1) {
                    return 1;
                } else {
                    return 0;
                }
            }
        });
        
        BusyWork busyWork = new BusyWork();
        busyWork.start();
        // I let busyWork prepare a huge insert
        Thread.sleep(1000);
        synchronized(busyWork){ 
            try{
                workWork();
            } catch(SQLException ex) {
                assertTrue(ex.getErrorCode() == SQLiteErrorCode.SQLITE_BUSY.code);
            }
        }
        assertTrue(calls[0] == 3);
        
        int totalCalls = calls[0];
        BusyHandler.clearHandler(conn);
        busyWork = new BusyWork();
        busyWork.start();
        // I let busyWork prepare a huge insert
        Thread.sleep(1000);
        synchronized(busyWork){ 
            try{
                workWork();
            } catch(SQLException ex) {
                assertTrue(ex.getErrorCode() == SQLiteErrorCode.SQLITE_BUSY.code);
            }
        }
    
        busyWork.interrupt();
        assertEquals(totalCalls, calls[0]);
    }

    @Test
    public void testInterrupt() throws Exception {

        try {
            BusyHandler.setHandler(conn, new BusyHandler() {
                @Override
                protected int callback(int nbPrevInvok) throws SQLException {
                    return 1;
                }
            });
            workWork();
        } catch (SQLException ex) {
            // Expected error
            return;
        }
        // Progress function throws, not reached
        fail();
    }
}
@@ -589,32 +589,39 @@
 on(%22jdbc:sqlite:
+target/
 test.db%22);%0A     
@@ -607,32 +607,32 @@
 rget/test.db%22);%0A
-
         stat = c
@@ -889,25 +889,17 @@
 t stat;%0A
-        
 %0A
+
         
@@ -995,16 +995,23 @@
 :sqlite:
+target/
 test.db%22
@@ -1100,33 +1100,25 @@
 ;%0A        %7D%0A
-        
 %0A
+
         @Ove
@@ -1906,29 +1906,25 @@
     %7D%0A    %7D%0A
-    
 %0A
+
     private 
@@ -2068,33 +2068,25 @@
 leep(1000);%0A
-        
 %0A
+
         // G
@@ -2603,33 +2603,17 @@
 s%5B0%5D++;%0A
-                
 %0A
+
         
@@ -2769,33 +2769,25 @@
         %7D);%0A
-        
 %0A
+
         Busy
@@ -2844,25 +2844,17 @@
 tart();%0A
-        
 %0A
+
         
@@ -2921,24 +2921,16 @@
 (1000);%0A
-        
 %0A       
@@ -2945,33 +2945,32 @@
 nized(busyWork)%7B
- 
 %0A            try
@@ -3145,25 +3145,17 @@
       %7D%0A
-        
 %0A
+
         
@@ -3551,25 +3551,9 @@
 ++;%0A
-                
 %0A
+
     
@@ -3717,25 +3717,17 @@
     %7D);%0A
-        
 %0A
+
         
@@ -3887,33 +3887,32 @@
 nized(busyWork)%7B
- 
 %0A            try
@@ -4126,17 +4126,9 @@
 3);%0A
-        
 %0A
+
     
@@ -4366,17 +4366,16 @@
 syWork)%7B
- 
 %0A       
@@ -4562,13 +4562,9 @@
   %7D%0A
-    
 %0A
+
     
@@ -5136,9 +5136,10 @@
 ;%0A    %7D%0A
-
 %7D
+%0A

Use target/test.db in BusyHandler so as not to create garbage db