| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.lucene.mockfile; |
| |
| import java.io.FileNotFoundException; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.URI; |
| import java.nio.file.FileSystem; |
| import java.nio.file.Files; |
| import java.nio.file.NoSuchFileException; |
| import java.nio.file.Path; |
| import java.nio.file.StandardCopyOption; |
| import java.util.concurrent.CyclicBarrier; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| |
| import org.apache.lucene.util.Constants; |
| |
| /** Basic tests for WindowsFS */ |
| public class TestWindowsFS extends MockFileSystemTestCase { |
| |
| @Override |
| public void setUp() throws Exception { |
| super.setUp(); |
| // irony: currently we don't emulate windows well enough to work on windows! |
| assumeFalse("windows is not supported", Constants.WINDOWS); |
| } |
| |
| @Override |
| protected Path wrap(Path path) { |
| FileSystem fs = new WindowsFS(path.getFileSystem()).getFileSystem(URI.create("file:///")); |
| return new FilterPath(path, fs); |
| } |
| |
| /** Test Files.delete fails if a file has an open inputstream against it */ |
| public void testDeleteOpenFile() throws IOException { |
| Path dir = wrap(createTempDir()); |
| |
| OutputStream file = Files.newOutputStream(dir.resolve("stillopen")); |
| file.write(5); |
| file.close(); |
| InputStream is = Files.newInputStream(dir.resolve("stillopen")); |
| |
| IOException e = expectThrows(IOException.class, () -> Files.delete(dir.resolve("stillopen"))); |
| assertTrue(e.getMessage().contains("access denied")); |
| is.close(); |
| } |
| |
| /** Test Files.deleteIfExists fails if a file has an open inputstream against it */ |
| public void testDeleteIfExistsOpenFile() throws IOException { |
| Path dir = wrap(createTempDir()); |
| |
| OutputStream file = Files.newOutputStream(dir.resolve("stillopen")); |
| file.write(5); |
| file.close(); |
| InputStream is = Files.newInputStream(dir.resolve("stillopen")); |
| |
| IOException e = expectThrows(IOException.class, () -> Files.deleteIfExists(dir.resolve("stillopen"))); |
| assertTrue(e.getMessage().contains("access denied")); |
| is.close(); |
| } |
| |
| /** Test Files.rename fails if a file has an open inputstream against it */ |
| // TODO: what does windows do here? |
| public void testRenameOpenFile() throws IOException { |
| Path dir = wrap(createTempDir()); |
| |
| OutputStream file = Files.newOutputStream(dir.resolve("stillopen")); |
| file.write(5); |
| file.close(); |
| InputStream is = Files.newInputStream(dir.resolve("stillopen")); |
| |
| IOException e = expectThrows(IOException.class, () -> |
| Files.move(dir.resolve("stillopen"), dir.resolve("target"), StandardCopyOption.ATOMIC_MOVE)); |
| assertTrue(e.getMessage().contains("access denied")); |
| is.close(); |
| } |
| |
| public void testOpenDeleteConcurrently() throws IOException, Exception { |
| final Path dir = wrap(createTempDir()); |
| final Path file = dir.resolve("thefile"); |
| final CyclicBarrier barrier = new CyclicBarrier(2); |
| final AtomicBoolean stopped = new AtomicBoolean(false); |
| Thread t = new Thread() { |
| @Override |
| public void run() { |
| try { |
| barrier.await(); |
| } catch (Exception ex) { |
| throw new RuntimeException(ex); |
| } |
| while (stopped.get() == false) { |
| try { |
| if (random().nextBoolean()) { |
| Files.delete(file); |
| } else if (random().nextBoolean()) { |
| Files.deleteIfExists(file); |
| } else { |
| Path target = file.resolveSibling("other"); |
| Files.move(file, target); |
| Files.delete(target); |
| } |
| } catch (IOException ex) { |
| // continue |
| } |
| } |
| } |
| }; |
| t.start(); |
| barrier.await(); |
| try { |
| final int iters = 10 + random().nextInt(100); |
| for (int i = 0; i < iters; i++) { |
| boolean opened = false; |
| try (OutputStream stream = Files.newOutputStream(file)) { |
| opened = true; |
| stream.write(0); |
| // just create |
| } catch (FileNotFoundException | NoSuchFileException ex) { |
| assertEquals("File handle leaked - file is closed but still registered", 0, ((WindowsFS) dir.getFileSystem().provider()).openFiles.size()); |
| assertFalse("caught FNF on close", opened); |
| } |
| assertEquals("File handle leaked - file is closed but still registered", 0, ((WindowsFS) dir.getFileSystem().provider()).openFiles.size()); |
| Files.deleteIfExists(file); |
| } |
| } finally { |
| stopped.set(true); |
| t.join(); |
| } |
| } |
| |
| public void testMove() throws IOException { |
| Path dir = wrap(createTempDir()); |
| OutputStream file = Files.newOutputStream(dir.resolve("file")); |
| file.write(1); |
| file.close(); |
| Files.move(dir.resolve("file"), dir.resolve("target")); |
| assertTrue(Files.exists(dir.resolve("target"))); |
| assertFalse(Files.exists(dir.resolve("file"))); |
| try (InputStream stream = Files.newInputStream(dir.resolve("target"))) { |
| assertEquals(1, stream.read()); |
| } |
| file = Files.newOutputStream(dir.resolve("otherFile")); |
| file.write(2); |
| file.close(); |
| |
| Files.move(dir.resolve("otherFile"), dir.resolve("target"), StandardCopyOption.REPLACE_EXISTING); |
| assertTrue(Files.exists(dir.resolve("target"))); |
| assertFalse(Files.exists(dir.resolve("otherFile"))); |
| try (InputStream stream = Files.newInputStream(dir.resolve("target"))) { |
| assertEquals(2, stream.read()); |
| } |
| } |
| } |