以下代码在带有OpenJDK 8的Ubuntu 18.04上成功执行,但在maven:3-jdk-8-slim基于OpenJDK 8 的Docker映像内失败:
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());
Run Code Online (Sandbox Code Playgroud)
故障详细信息:
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)
Run Code Online (Sandbox Code Playgroud)
指的是assertFalse(file.canRead())断言。该声明应该通过,因为file.setReadable(false)返回true并因此成功。
我使用基于Docker的GitLab CI在SSCCE中重现了该问题,因此可以在https://gitlab.com/krichter/docker-java-file-readability/-/jobs/203311757上找到详细的输出。SSCCE所包含的信息并不比上面的代码摘录多,但是可以简化本地调查。
我在寻找解释,而不是解决方法。
Leo*_*eon 10
的文档中File.canRead()包含一条注释,其结果可能会引起混淆:
public boolean canRead()测试应用程序是否可以读取此抽象路径名表示的文件。在某些平台上,可以使用特殊特权启动Java虚拟机,以使其能够读取标记为不可读的文件。因此,
true即使文件没有读取权限,此方法也可能返回。
在docker之下,进程通常以root身份运行,从而赋予其普通用户看不到的特权。
证明root可以读取缺少读取权限的文件:
$ echo abcd > somefile
$ ls -l somefile
-rw-rw-r-- 1 leon leon 5 Aug 26 21:43 somefile
$ cat somefile
abcd
$ chmod a-rw somefile
$ ls -l somefile
---------- 1 leon leon 5 Aug 26 21:43 somefile
$ cat somefile
cat: somefile: Permission denied
$ sudo cat somefile
abcd
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
411 次 |
| 最近记录: |