rubenlagus / TelegramBots

Java library to create bots using Telegram Bots API
https://telegram.me/JavaBotsApi
MIT License
4.78k stars 1.22k forks source link

"File is already opened and is locked" when testing #725

Closed andriihorpenko closed 4 years ago

andriihorpenko commented 4 years ago

When I run all tests within a class I get this error: "File is already opened and is locked". When I run tests individually everything works like a charm. According to the extended error, bot is trying to work with the database but I am not using it. Also after each test, a file with no extension is created in the project root directory which corresponds to a username of a bot. This is how my setUp method with @Before annotation looks like:

@Before
public void setUp() {
    Environment environment = mock(Environment.class);
    when(environment.get("BOT_TOKEN")).thenReturn("token");
    when(environment.get("BOT_USERNAME")).thenReturn("username");
    when(environment.get("CREATOR_ID")).thenReturn("0");

    bot = new SoldierBot(environment);
    sender = mock(MessageSender.class);
    bot.setSender(sender);
}

Here is the full stacktrace:

File is already opened and is locked: username org.mapdb.DBException$FileLocked: File is already opened and is locked: username at org.mapdb.volume.Volume.lockFile(Volume.java:495) at org.mapdb.volume.RandomAccessFileVol.(RandomAccessFileVol.java:52) at org.mapdb.volume.RandomAccessFileVol$1.makeVolume(RandomAccessFileVol.java:26) at org.mapdb.StoreWAL$realVolume$1.invoke(StoreWAL.kt:75) at org.mapdb.StoreWAL$realVolume$1.invoke(StoreWAL.kt:18) at org.mapdb.StoreWAL.(StoreWAL.kt:74) at org.mapdb.StoreWAL$Companion.make(StoreWAL.kt:56) at org.mapdb.StoreWAL$Companion.make$default(StoreWAL.kt:55) at org.mapdb.DBMaker$Maker.make(DBMaker.kt:464) at org.telegram.abilitybots.api.db.MapDBContext.onlineInstance(MapDBContext.java:57) at org.telegram.abilitybots.api.bot.AbilityBot.(AbilityBot.java:42) at com.andriihorpenko.SoldierBot.(SoldierBot.java:22) at com.andriihorpenko.CheckNewUserTest.setUp(CheckNewUserTest.java:39) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:110) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58) at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:38) at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:62) at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:51) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:32) at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:93) at com.sun.proxy.$Proxy2.processTestClass(Unknown Source) at org.gradle.api.internal.tasks.testing.worker.TestWorker.processTestClass(TestWorker.java:118) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:566) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:35) at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:175) at org.gradle.internal.remote.internal.hub.MessageHubBackedObjectConnection$DispatchWrapper.dispatch(MessageHubBackedObjectConnection.java:157) at org.gradle.internal.remote.internal.hub.MessageHub$Handler.run(MessageHub.java:404) at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:63) at org.gradle.internal.concurrent.ManagedExecutorImpl$1.run(ManagedExecutorImpl.java:46) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at org.gradle.internal.concurrent.ThreadFactoryImpl$ManagedThreadRunnable.run(ThreadFactoryImpl.java:55) at java.base/java.lang.Thread.run(Thread.java:834) Caused by: java.nio.channels.OverlappingFileLockException at java.base/sun.nio.ch.FileLockTable.checkList(FileLockTable.java:229) at java.base/sun.nio.ch.FileLockTable.add(FileLockTable.java:123) at java.base/sun.nio.ch.FileChannelImpl.tryLock(FileChannelImpl.java:1154) at java.base/java.nio.channels.FileChannel.tryLock(FileChannel.java:1165) at org.mapdb.volume.Volume.lockFile(Volume.java:490) ... 59 more

andriihorpenko commented 4 years ago

In addition, this is a bot's constructor I'm using(highlighted one, as you see I am not using one with DBContext): image

kortov commented 4 years ago

Ahah, with all your opened issues, I've got all this pitfalls :) I created a bean for a db as a temp file. You can create temp db with test profile and a permanent db for a prod profile, but I was lazy to implement this. This is my code

@Bean
    fun dbForBot(): DBContext {
        val db = DBMaker
                .tempFileDB()
//                .fileDB(properties.botUsername)
                .fileMmapEnableIfSupported()
                .closeOnJvmShutdown()
                .transactionEnable()
                .fileDeleteAfterClose()
                .make()

        return MapDBContext(db)
    }
kortov commented 4 years ago

by default the permanent file db is created in the parent classes constructors

addo47 commented 4 years ago

Use MapDbContext::offlineInstance, pass the db to your bot in your setUp. Then on tearDown (@ After), do db.clear; db.close();You'll need to expose a constructor that calls the super constructor with the DB parameter.

andriihorpenko commented 4 years ago

Cool, now it's all good, thanks!