一次正常的Hadoop测试运行会测试那些可以通过本地文件系统在本地测试的文件系统。这通常意味着file://
及其底层的LocalFileSystem
,以及通过HDFS MiniCluster测试的hdfs://
。
除非有专门配置连接到提供文件系统的远程服务器,否则其他文件系统将被跳过。
这些文件系统绑定必须在XML配置文件中定义,通常是hadoop-common-project/hadoop-common/src/test/resources/contract-test-options.xml
。该文件被排除在外,不应被签入。
在contract-test-options.xml
中,必须在属性fs.contract.test.fs.ftp
中定义文件系统名称。然后必须提供连接FTP服务器的具体登录选项。
还必须在选项fs.contract.test.ftp.testdir
中提供一个测试目录路径。这是执行操作的基础目录。
示例:
<configuration> <property> <name>fs.contract.test.fs.ftp</name> <value>ftp://server1/</value> </property> <property> <name>fs.ftp.user.server1</name> <value>testuser</value> </property> <property> <name>fs.contract.test.ftp.testdir</name> <value>/home/testuser/test</value> </property> <property> <name>fs.ftp.password.server1</name> <value>secret-login</value> </property> </configuration>
向合约测试中添加新FileSystem的核心是添加一个新的合约类,然后为每个你想测试的测试套件创建一个新的非抽象测试类。
contract
下,用于存放文件和测试。AbstractFSContract
。Test
开头并加上文件系统名称。例如:TestHDFSRenameContract
。createContract()
。src/test/resources/contract-test-options.xml
文件中定义的所有文件系统绑定。例如,以下是本地文件系统中create()
测试的实现。
package org.apache.hadoop.fs.contract.localfs; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.contract.AbstractCreateContractTest; import org.apache.hadoop.fs.contract.AbstractFSContract; public class TestLocalCreateContract extends AbstractCreateContractTest { @Override protected AbstractFSContract createContract(Configuration conf) { return new LocalFSContract(conf); } }
AbstractFSContract
子类的标准实现技术是完全由存储在测试资源树中的Hadoop XML配置文件驱动。最佳实践是将其存储在/contract
目录下,并以文件系统名称命名,例如contract/localfs.xml
。通过XML文件定义所有文件系统选项,可以直观地展示文件系统的行为列表。
LocalFSContract
是一个特殊情况,因为它必须根据运行的操作系统调整其大小写敏感策略:对于 Windows 和 OS/X,文件系统是大小写不敏感的,因此必须将 ContractOptions.IS_CASE_SENSITIVE
选项设置为 false。此外,Windows 文件系统不支持 Unix 文件和目录权限,因此也必须设置相关标志。这是在从资源树加载 XML 契约文件之后完成的,只需更新现已加载的配置选项:
getConf().setBoolean(getConfKey(ContractOptions.SUPPORTS_UNIX_PERMISSIONS), false);
如果你的新FileSystem
测试用例未能通过其中一项合约测试,你可以采取哪些措施?
这取决于问题的原因
FileSystem
子类未正确实现规范。修复。FileSystem
子类隐藏这些差异,例如通过异常转换。hdfs-dev
邮件列表中提出。请注意:虽然FileSystem测试存在于Hadoop核心代码库中,但文件系统规范及配套测试的所有权归属于HDFS团队。如果某个测试因功能不支持而需要跳过,请在ContractOptions
类中查找现有的配置选项。如果没有对应方法,短期解决方案是重写该方法并使用ContractTestUtils.skip()
消息记录测试被跳过的事实。使用此方法会将消息打印到日志中,然后通知测试运行器该测试已被跳过。这样可以突显问题所在。
推荐的策略是调用父类,捕获异常,并验证异常类和部分错误字符串与当前实现抛出的相匹配。如果父类实际上成功了——也就是说,它以当前实现尚未做到的方式失败——它也应该fail()
。这将确保测试路径仍被执行,测试的任何其他失败(可能是回归)会被捕获。并且,如果该功能确实被实现了,这一变更也会被捕获。
长期解决方案是增强基础测试以添加一个新的可选功能键。这需要与hdfs-dev
邮件列表上的开发人员协作。
契约测试包含严格异常与宽松异常的概念。严格异常报告意味着:使用IOException
的特定子类报告失败,例如FileNotFoundException
、EOFException
等。宽松报告意味着抛出IOException
。
虽然文件系统应该抛出更严格的异常,但可能存在无法这样做的原因。允许抛出宽松的异常,但这会妨碍对用户应用程序中故障的诊断。要声明某个文件系统不支持更严格的异常,请将选项fs.contract.supports-strict-exceptions
设置为false。
针对远程文件系统的测试需要指定文件系统的URL;针对需要登录信息的远程文件系统的测试则需要用户名/ID和密码。
所有这些细节必须放置在文件src/test/resources/contract-test-options.xml
中,并且需要配置您的SCM工具确保该文件永远不会提交到subversion、git或类似版本控制系统。此外,必须配置构建过程确保该文件永远不会被打包到任何生成的-test
构件中。Hadoop构建就是这样处理的,从JAR文件中排除了src/test/**/*.xml
。另外,还需要创建src/test/resources/auth-keys.xml
文件,它可以是contract-test-options.xml
的副本。AbstractFSContract
类会自动加载这个资源文件(如果存在);可以为特定测试用例添加特定的键值。
例如,以下是S3A测试密钥的示例:
<configuration> <property> <name>fs.contract.test.fs.s3a</name> <value>s3a://tests3contract</value> </property> <property> <name>fs.s3a.access.key</name> <value>DONOTPCOMMITTHISKEYTOSCM</value> </property> <property> <name>fs.s3a.secret.key</name> <value>DONOTEVERSHARETHISSECRETKEY!</value> </property> </configuration>
如果文件系统URL未在属性fs.contract.test.fs.%s
中定义(其中%s
匹配文件系统的模式名称),则AbstractBondedFSContract
会自动跳过测试套件。
运行测试时,需要关闭maven.test.skip
,因为这些测试默认情况下该参数为true。可以通过类似mvn test -Ptests-on
的命令来实现。
通过所有FileSystem契约测试并不意味着一个文件系统可以被描述为“与HDFS兼容”。这些测试试图查看每个操作的独立功能,并关注每个动作的前置条件和后置条件。未涵盖的核心领域包括分布式系统中的并发性和故障处理方面。
使用FileSystem API还有一些特定的方面:
hadoop -fs
命令行界面。当然,欢迎提供验证这些行为的测试。
seek()
、rename()
、create()
等所做的那样。这是为了与文件系统契约规范按操作拆分的方式相匹配。这也使得文件系统实现者可以一次专注于一个测试套件。AbstractFSContractTestBase
创建一个新的抽象测试套件类。同样,在类名中使用Abstract
。org.apache.hadoop.fs.contract.ContractTestUtils
中的实用工具类来辅助测试,其中包含大量面向文件系统的断言。使用这些工具可以对文件系统状态进行断言,并在断言失败时包含诊断信息,例如目录列表和不匹配文件的转储。部分测试直接针对根文件系统进行操作,尝试执行诸如重命名“/”等类似操作。根目录具有“特殊性”,对其进行测试非常重要,尤其是在对象存储等非POSIX文件系统上。这些测试可能对原生文件系统造成极大破坏,请谨慎使用。
将测试添加到AbstractRootDirectoryContractTest
下,或者创建一个新测试,要求:(a) 标题中包含Root
字样,(b) 在setup方法中添加检查以在根测试被禁用时跳过测试:
skipIfUnsupported(TEST_ROOT_TESTS_ENABLED);
不要提供针对本地文件系统运行的此测试套件的实现。
旨在生成可扩展负载的测试——包括大量小文件以及少量大文件——应设计为可配置的,以便测试套件的用户可以配置文件的数量和大小。
请注意,在对象存储上,目录重命名操作通常是O(files)*O(data)
,而删除操作是O(files)
。后者意味着即使是任何目录清理操作都可能需要时间,并有可能超时。设计能够应对远程文件系统所有操作可能延迟的测试非常重要。
该规范尚不完整。它没有全面覆盖FileSystem类,并且现有指定类中可能还有部分内容未被涵盖。