blob: 073746bad6f3eefb355cdfc220071a354b4d0b6e [file] [log] [blame]
/*
* 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.store;
import java.io.EOFException;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.nio.file.NoSuchFileException;
import java.nio.file.Path;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.RandomIndexWriter;
// See: https://issues.apache.org/jira/browse/SOLR-12028 Tests cannot remove files on Windows machines occasionally
public class TestMockDirectoryWrapper extends BaseDirectoryTestCase {
@Override
protected Directory getDirectory(Path path) throws IOException {
final MockDirectoryWrapper dir;
if (random().nextBoolean()) {
dir = newMockDirectory();
} else {
dir = newMockFSDirectory(path);
}
return dir;
}
// we wrap the directory in slow stuff, so only run nightly
@Override
@Nightly
public void testThreadSafetyInListAll() throws Exception {
super.testThreadSafetyInListAll();
}
public void testDiskFull() throws IOException {
// test writeBytes
MockDirectoryWrapper dir = newMockDirectory();
dir.setMaxSizeInBytes(3);
final byte[] bytes = new byte[] { 1, 2};
IndexOutput out = dir.createOutput("foo", IOContext.DEFAULT);
out.writeBytes(bytes, bytes.length); // first write should succeed
// close() to ensure the written bytes are not buffered and counted
// against the directory size
out.close();
IndexOutput out2 = dir.createOutput("bar", IOContext.DEFAULT);
expectThrows(IOException.class, () -> out2.writeBytes(bytes, bytes.length));
out2.close();
dir.close();
// test copyBytes
dir = newMockDirectory();
dir.setMaxSizeInBytes(3);
out = dir.createOutput("foo", IOContext.DEFAULT);
out.copyBytes(new ByteArrayDataInput(bytes), bytes.length); // first copy should succeed
// close() to ensure the written bytes are not buffered and counted
// against the directory size
out.close();
IndexOutput out3 = dir.createOutput("bar", IOContext.DEFAULT);
expectThrows(IOException.class, () -> out3.copyBytes(new ByteArrayDataInput(bytes), bytes.length));
out3.close();
dir.close();
}
public void testMDWinsideOfMDW() throws Exception {
// add MDW inside another MDW
Directory dir = new MockDirectoryWrapper(random(), newMockDirectory());
RandomIndexWriter iw = new RandomIndexWriter(random(), dir);
for (int i = 0; i < 20; i++) {
iw.addDocument(new Document());
}
iw.commit();
iw.close();
dir.close();
}
// just shields the wrapped directory from being closed
private static class PreventCloseDirectoryWrapper extends FilterDirectory {
public PreventCloseDirectoryWrapper(Directory in) {
super(in);
}
@Override
public void close() {
}
}
public void testCorruptOnCloseIsWorkingFSDir() throws Exception {
Path path = createTempDir();
try(Directory dir = newFSDirectory(path)) {
testCorruptOnCloseIsWorking(dir);
}
}
public void testCorruptOnCloseIsWorkingRAMDir() throws Exception {
try(Directory dir = new RAMDirectory()) {
testCorruptOnCloseIsWorking(dir);
}
}
private void testCorruptOnCloseIsWorking(Directory dir) throws Exception {
dir = new PreventCloseDirectoryWrapper(dir);
try (MockDirectoryWrapper wrapped = new MockDirectoryWrapper(random(), dir)) {
// otherwise MDW sometimes randomly leaves the file intact and we'll see false test failures:
wrapped.alwaysCorrupt = true;
// MDW will only try to corrupt things if it sees an index:
RandomIndexWriter iw = new RandomIndexWriter(random(), dir);
iw.addDocument(new Document());
iw.close();
// not sync'd!
try (IndexOutput out = wrapped.createOutput("foo", IOContext.DEFAULT)) {
for(int i=0;i<100;i++) {
out.writeInt(i);
}
}
// MDW.close now corrupts our unsync'd file (foo):
}
boolean changed = false;
IndexInput in = null;
try {
in = dir.openInput("foo", IOContext.DEFAULT);
} catch (NoSuchFileException | FileNotFoundException fnfe) {
// ok
changed = true;
}
if (in != null) {
for(int i=0;i<100;i++) {
int x;
try {
x = in.readInt();
} catch (EOFException eofe) {
changed = true;
break;
}
if (x != i) {
changed = true;
break;
}
}
in.close();
}
assertTrue("MockDirectoryWrapper on dir=" + dir + " failed to corrupt an unsync'd file", changed);
}
public void testAbuseClosedIndexInput() throws Exception {
MockDirectoryWrapper dir = newMockDirectory();
IndexOutput out = dir.createOutput("foo", IOContext.DEFAULT);
out.writeByte((byte) 42);
out.close();
final IndexInput in = dir.openInput("foo", IOContext.DEFAULT);
in.close();
expectThrows(RuntimeException.class, in::readByte);
dir.close();
}
public void testAbuseCloneAfterParentClosed() throws Exception {
MockDirectoryWrapper dir = newMockDirectory();
IndexOutput out = dir.createOutput("foo", IOContext.DEFAULT);
out.writeByte((byte) 42);
out.close();
IndexInput in = dir.openInput("foo", IOContext.DEFAULT);
final IndexInput clone = in.clone();
in.close();
expectThrows(RuntimeException.class, clone::readByte);
dir.close();
}
public void testAbuseCloneOfCloneAfterParentClosed() throws Exception {
MockDirectoryWrapper dir = newMockDirectory();
IndexOutput out = dir.createOutput("foo", IOContext.DEFAULT);
out.writeByte((byte) 42);
out.close();
IndexInput in = dir.openInput("foo", IOContext.DEFAULT);
IndexInput clone1 = in.clone();
IndexInput clone2 = clone1.clone();
in.close();
expectThrows(RuntimeException.class, clone2::readByte);
dir.close();
}
}