1111import org .cryptomator .cryptolib .api .FileHeaderCryptor ;
1212import org .junit .jupiter .api .AfterAll ;
1313import org .junit .jupiter .api .Assertions ;
14+ import org .junit .jupiter .api .Assumptions ;
1415import org .junit .jupiter .api .BeforeAll ;
1516import org .junit .jupiter .api .DisplayName ;
1617import org .junit .jupiter .api .MethodOrderer ;
3334import java .util .EnumSet ;
3435import java .util .concurrent .atomic .AtomicLong ;
3536import java .util .concurrent .atomic .AtomicReference ;
37+ import java .util .function .Consumer ;
3638
3739import static org .mockito .ArgumentMatchers .any ;
3840import static org .mockito .Mockito .mock ;
@@ -50,6 +52,7 @@ public class OpenCryptoFileTest {
5052 private Cryptor cryptor = mock (Cryptor .class );
5153 private FileHeaderCryptor fileHeaderCryptor = mock (FileHeaderCryptor .class );
5254 private FileHeaderHolder headerHolder = mock (FileHeaderHolder .class );
55+ private ChunkIO chunkIO = mock (ChunkIO .class );
5356 private AtomicLong fileSize = Mockito .mock (AtomicLong .class );
5457 private AtomicReference <Instant > lastModified = new AtomicReference (Instant .ofEpochMilli (0 ));
5558 private OpenCryptoFileComponent openCryptoFileComponent = mock (OpenCryptoFileComponent .class );
@@ -69,7 +72,7 @@ public static void tearDown() throws IOException {
6972
7073 @ Test
7174 public void testCloseTriggersCloseListener () {
72- OpenCryptoFile openCryptoFile = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , CURRENT_FILE_PATH , fileSize , lastModified , openCryptoFileComponent );
75+ OpenCryptoFile openCryptoFile = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , chunkIO , CURRENT_FILE_PATH , fileSize , lastModified , openCryptoFileComponent );
7376 openCryptoFile .close ();
7477 verify (closeListener ).close (CURRENT_FILE_PATH .get (), openCryptoFile );
7578 }
@@ -80,7 +83,7 @@ public void testCloseImmediatelyIfOpeningFirstChannelFails() {
8083 UncheckedIOException expectedException = new UncheckedIOException (new IOException ("fail!" ));
8184 EffectiveOpenOptions options = Mockito .mock (EffectiveOpenOptions .class );
8285 Mockito .when (options .createOpenOptionsForEncryptedFile ()).thenThrow (expectedException );
83- OpenCryptoFile openCryptoFile = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , CURRENT_FILE_PATH , fileSize , lastModified , openCryptoFileComponent );
86+ OpenCryptoFile openCryptoFile = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , chunkIO , CURRENT_FILE_PATH , fileSize , lastModified , openCryptoFileComponent );
8487
8588 UncheckedIOException exception = Assertions .assertThrows (UncheckedIOException .class , () -> {
8689 openCryptoFile .newFileChannel (options );
@@ -99,7 +102,7 @@ public void testFileSizeZerodOnTruncateExisting() throws IOException {
99102 Mockito .when (openCryptoFileComponent .newChannelComponent ()).thenReturn (channelComponentFactory );
100103 Mockito .when (channelComponentFactory .create (any (), any (), any ())).thenReturn (channelComponent );
101104 Mockito .when (channelComponent .channel ()).thenReturn (mock (CleartextFileChannel .class ));
102- OpenCryptoFile openCryptoFile = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , CURRENT_FILE_PATH , fileSize , lastModified , openCryptoFileComponent );
105+ OpenCryptoFile openCryptoFile = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , chunkIO , CURRENT_FILE_PATH , fileSize , lastModified , openCryptoFileComponent );
103106
104107 openCryptoFile .newFileChannel (options );
105108 verify (fileSize ).set (0L );
@@ -111,7 +114,7 @@ public class InitFilHeaderTests {
111114
112115 EffectiveOpenOptions options = Mockito .mock (EffectiveOpenOptions .class );
113116 FileChannel cipherFileChannel = Mockito .mock (FileChannel .class , "cipherFilechannel" );
114- OpenCryptoFile inTest = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , CURRENT_FILE_PATH , fileSize , lastModified , openCryptoFileComponent );
117+ OpenCryptoFile inTest = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , chunkIO , CURRENT_FILE_PATH , fileSize , lastModified , openCryptoFileComponent );
115118
116119 @ Test
117120 @ DisplayName ("Skip file header init, if the file header already exists in memory" )
@@ -188,19 +191,22 @@ public class FileChannelFactoryTest {
188191 private final AtomicLong realFileSize = new AtomicLong (-1L );
189192 private OpenCryptoFile openCryptoFile ;
190193 private CleartextFileChannel cleartextFileChannel ;
194+ private AtomicReference <Consumer <FileChannel >> listener ;
191195 private AtomicReference <FileChannel > ciphertextChannel ;
192196
193197 @ BeforeAll
194198 public void setup () throws IOException {
195199 FS = Jimfs .newFileSystem ("OpenCryptoFileTest.FileChannelFactoryTest" , Configuration .unix ().toBuilder ().setAttributeViews ("basic" , "posix" ).build ());
196200 CURRENT_FILE_PATH = new AtomicReference <>(FS .getPath ("currentFile" ));
197- openCryptoFile = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , CURRENT_FILE_PATH , realFileSize , lastModified , openCryptoFileComponent );
201+ openCryptoFile = new OpenCryptoFile (closeListener , chunkCache , cryptor , headerHolder , chunkIO , CURRENT_FILE_PATH , realFileSize , lastModified , openCryptoFileComponent );
198202 cleartextFileChannel = mock (CleartextFileChannel .class );
203+ listener = new AtomicReference <>();
199204 ciphertextChannel = new AtomicReference <>();
200205
201206 Mockito .when (openCryptoFileComponent .newChannelComponent ()).thenReturn (channelComponentFactory );
202207 Mockito .when (channelComponentFactory .create (Mockito .any (), Mockito .any (), Mockito .any ())).thenAnswer (invocation -> {
203208 ciphertextChannel .set (invocation .getArgument (0 ));
209+ listener .set (invocation .getArgument (2 ));
204210 return channelComponent ;
205211 });
206212 Mockito .when (channelComponent .channel ()).thenReturn (cleartextFileChannel );
@@ -221,6 +227,7 @@ public void createFileChannel() throws IOException {
221227 EffectiveOpenOptions options = EffectiveOpenOptions .from (EnumSet .of (StandardOpenOption .CREATE_NEW , StandardOpenOption .WRITE ), readonlyFlag );
222228 FileChannel ch = openCryptoFile .newFileChannel (options , attrs );
223229 Assertions .assertSame (cleartextFileChannel , ch );
230+ verify (chunkIO ).registerChannel (ciphertextChannel .get (), true );
224231 }
225232
226233 @ Test
@@ -266,6 +273,17 @@ public void testTruncateExistingInvalidatesChunkCache() throws IOException {
266273 verify (chunkCache ).invalidateStale ();
267274 }
268275
276+ @ Test
277+ @ Order (100 )
278+ @ DisplayName ("closeListener triggers chunkIO.unregisterChannel()" )
279+ public void triggerCloseListener () throws IOException {
280+ Assumptions .assumeTrue (listener .get () != null );
281+ Assumptions .assumeTrue (ciphertextChannel .get () != null );
282+
283+ listener .get ().accept (ciphertextChannel .get ());
284+ verify (chunkIO ).unregisterChannel (ciphertextChannel .get ());
285+ }
286+
269287 }
270288
271289}
0 commit comments