以下代码在具有OpenJDK 8的Ubuntu 18.04上成功,但在基于OpenJDK 8的Docker映像maven:3-jdk-8-slim
内失败:
String userHome = System.getProperty("user.home");
System.out.println(String.format("system property user.home: %s",
userHome));
File file = new File(userHome, "file");
if(!file.createNewFile()) {
throw new IOException("test arrangement failed");
}
if(!file.setReadable(false)) {
throw new IOException("test arrangement failed");
}
assertFalse(file.canRead());
故障详细信息:
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertFalse(Assert.java:64)
at org.junit.Assert.assertFalse(Assert.java:74)
at de.richtercloud.docker.java.file.readability.TheTest.testSomeMethod(TheTest.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
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.InvokeMethod.evaluate(InvokeMethod.java:17)
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.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)
引用assertFalse(file.canRead())
断言。此断言应该通过,因为file.setReadable(false)
返回了true
,因此成功了。
我使用基于Docker的GitLab CI在SSCCE中重现了该问题,因此可以在https://gitlab.com/krichter/docker-java-file-readability/-/jobs/203311757上找到详细的输出。 SSCCE所包含的信息除上述代码摘录外没有更多,但是使本地调查更加容易。
我在寻找解释,而不是解决方法。
答案 0 :(得分:10)
documentation of File.canRead()
包含一条注释,说明其结果可能令人困惑:
essential
测试应用程序是否可以读取此表示的文件 抽象路径名。 在某些平台上,可能可以启动 具有允许其读取的特殊特权的Java虚拟机 标记为不可读的文件。因此,此方法可能 即使该文件没有读取权限也返回
false
。
在docker进程下,通常以root身份运行,从而赋予普通用户看不到的特权。
证明root可以读取缺乏读取权限的文件:
public boolean canRead()
答案 1 :(得分:0)
我找到了解决此问题的方法。
在您的 docker 中,如果您的 linux 映像可能,您将必须创建一个非管理员用户,然后使用该用户“su”并以该用户身份启动您需要的所有命令。
这是一个仅在您不是管理员或 root 用户时才有效的示例:
# useradd -m myUser
# su - myUser
$ pwd
/home/myUser
$ cat <<EOF > Test.java
> import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
public class Test {
public static void main(String[] args) throws IOException {
Path tempDir = Files.createTempDirectory("Test");
final File nonReadableFile = new File(tempDir.toFile(), "nonReadableFile.txt");
System.out.println(nonReadableFile.getAbsolutePath());
nonReadableFile.createNewFile();
System.out.println(nonReadableFile.canRead());
nonReadableFile.setReadable(false);
System.out.println(nonReadableFile.canRead());
}
}
> > > > > > > > > > > > > > > > > > > EOF
$ javac Test.java
$ java Test
/tmp/Test2125736191041151487/nonReadableFile.txt
true
false
答案 2 :(得分:-3)
此断言应该通过,因为
File.canRead()
应该在File.setReadable(false)
之后返回false。
仅当setReadable()
返回true时。当您扔掉返回代码而不是对其进行操作时,您的tedt无效。