henrybear327 commented on code in PR #10934:
URL: https://github.com/apache/ozone/pull/10934#discussion_r3894238147
##########
hadoop-ozone/tools/src/test/java/org/apache/hadoop/ozone/local/TestLocalOzoneCluster.java:
##########
@@ -349,6 +354,226 @@ void prepareConfigurationRejectsTooManyDatanodes() throws
Exception {
+ "; each datanode reserves 8 local ports.", error.getMessage());
}
+ @Test
+ void zeroDatanodesIsRejected() throws Exception {
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone"))
+ .setDatanodes(0)
+ .build();
+
+ IOException error = assertPrepareFails(config);
+
+ // configureLocalDefaults() requires one datanode for safe mode, so a
zero-datanode cluster
+ // can never leave it; without this the run only fails when the readiness
wait times out.
+ assertTrue(error.getMessage().contains("Datanode count 0"),
error.getMessage());
+ }
+
+ @Test
+ void keyUnsetAfterBeingConfiguredIsNotRejected() throws Exception {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ // Configuration#unset() drops the value but keeps the entry in
updatingResource, so the key
+ // still reports a source with no value behind it.
+ seed.set(OZONE_METADATA_DIRS, "/somewhere/else", "test-ozone-site.xml");
+ seed.unset(OZONE_METADATA_DIRS);
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ try (LocalOzoneCluster cluster = new LocalOzoneCluster(config, seed)) {
+
assertNotNull(cluster.prepareConfiguration().getConfiguration().get(OZONE_METADATA_DIRS));
+ }
+ }
+
+ @Test
+ void defaultsFileNamedByPathCountsAsUserConfig() {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ // Only the shipped classpath resource is a default. A file the user
pointed at with --conf
+ // is their choice however it is named.
+ seed.set(OZONE_REPLICATION, ReplicationFactor.THREE.name(),
"/home/me/ozone-default.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ IOException error = assertPrepareFails(config, seed);
+
+ assertTrue(error.getMessage().contains(OZONE_REPLICATION),
error.getMessage());
+ }
+
+ @Test
+ void tooManyDatanodesIsRejectedBeforeFormatDeletesDataDir() throws Exception
{
+ Path dataDir = tempDir.resolve("local-ozone");
+ Path marker = writeMarker(dataDir, "keep me");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(dataDir)
+ .setFormatMode(LocalOzoneClusterConfig.FormatMode.ALWAYS)
+ .setDatanodes(LocalOzoneCluster.MAX_DATANODES + 1)
+ .build();
+
+ assertPrepareFails(config);
+
+ assertTrue(Files.exists(marker),
+ "format ALWAYS must not delete the data dir for a run that cannot
start");
+ }
+
+ @Test
+ void conflictingUserConfigIsRejected() {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ seed.set(OZONE_REPLICATION, ReplicationFactor.THREE.name(),
"test-ozone-site.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ IOException error = assertPrepareFails(config, seed);
+
+ // The user has to locate the value to remove it, so the message carries
the key, the value
+ // ozone local requires, the configured value, and the source
Configuration recorded.
+ String message = error.getMessage();
+ assertTrue(message.contains(OZONE_REPLICATION), message);
+ assertTrue(message.contains(ReplicationFactor.ONE.name()), message);
+ assertTrue(message.contains(ReplicationFactor.THREE.name()), message);
+ assertTrue(message.contains("test-ozone-site.xml"), message);
+ }
+
+ @Test
+ void userConfigMatchingTheLocalRequirementIsAccepted() throws Exception {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ seed.set(OZONE_REPLICATION, ReplicationFactor.ONE.name(),
"test-ozone-site.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ try (LocalOzoneCluster cluster = new LocalOzoneCluster(config, seed)) {
+ assertEquals(ReplicationFactor.ONE.name(),
+
cluster.prepareConfiguration().getConfiguration().get(OZONE_REPLICATION));
+ }
+ }
+
+ @Test
+ void conflictingUserConfigIsRejectedBeforeFormatDeletesDataDir() throws
Exception {
+ Path dataDir = tempDir.resolve("local-ozone");
+ Path marker = writeMarker(dataDir, "keep me");
+ OzoneConfiguration seed = new OzoneConfiguration();
+ seed.set(OZONE_REPLICATION, ReplicationFactor.THREE.name(),
"test-ozone-site.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(dataDir)
+ .setFormatMode(LocalOzoneClusterConfig.FormatMode.ALWAYS)
+ .build();
+
+ assertPrepareFails(config, seed);
+
+ assertTrue(Files.exists(marker),
+ "format ALWAYS must not delete the data dir for a run that cannot
start");
+ }
+
+ @Test
+ void equivalentDurationSpellingIsAccepted() throws Exception {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ // Same interval the local runtime requires, written in another unit.
Rejecting it would refuse
+ // to start over a value that means exactly what the runtime asked for.
+ seed.set(HDDS_HEARTBEAT_INTERVAL, "1000ms", "test-ozone-site.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ try (LocalOzoneCluster cluster = new LocalOzoneCluster(config, seed)) {
+ assertEquals("1s", cluster.prepareConfiguration().getConfiguration()
+ .get(HDDS_HEARTBEAT_INTERVAL));
+ }
+ }
+
+ @Test
+ void equivalentBooleanSpellingIsAccepted() throws Exception {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ seed.set(HDDS_CONTAINER_RATIS_ENABLED_KEY, "FALSE", "test-ozone-site.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ try (LocalOzoneCluster cluster = new LocalOzoneCluster(config, seed)) {
+ assertFalse(cluster.prepareConfiguration().getConfiguration()
+ .getBoolean(HDDS_CONTAINER_RATIS_ENABLED_KEY, true));
+ }
+ }
+
+ @Test
+ void numericReplicationIsAccepted() throws Exception {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ // ReplicationConfig.parse() reads both "1" and "ONE", and compose
environments in this repo
+ // write the numeric form, so it has to be accepted as the value the
runtime requires.
+ seed.set(OZONE_SERVER_DEFAULT_REPLICATION_KEY, "1", "test-ozone-site.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ try (LocalOzoneCluster cluster = new LocalOzoneCluster(config, seed)) {
+ assertEquals(ReplicationFactor.ONE.name(), cluster.prepareConfiguration()
+ .getConfiguration().get(OZONE_SERVER_DEFAULT_REPLICATION_KEY));
+ }
+ }
+
+ @Test
+ void conflictingDurationIsRejected() {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ seed.set(HDDS_HEARTBEAT_INTERVAL, "30s", "test-ozone-site.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ IOException error = assertPrepareFails(config, seed);
+
+ // Comparing durations by value must not swallow a genuine conflict.
+ String message = error.getMessage();
+ assertTrue(message.contains(HDDS_HEARTBEAT_INTERVAL), message);
+ assertTrue(message.contains("30s"), message);
+ }
+
+ @Test
+ void unparseableValueIsRejected() {
+ OzoneConfiguration seed = new OzoneConfiguration();
+ seed.set(HDDS_HEARTBEAT_INTERVAL, "banana", "test-ozone-site.xml");
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ IOException error = assertPrepareFails(config, seed);
+
+ // A value the accessor cannot parse is a conflict, reported by the same
message rather than
+ // escaping as a NumberFormatException from the comparison itself.
+ String message = error.getMessage();
+ assertTrue(message.contains(HDDS_HEARTBEAT_INTERVAL), message);
+ assertTrue(message.contains("banana"), message);
+ }
+
+ /**
+ * Regression guard: ozone-default.xml ships a value for most keys the local
runtime requires
+ * (hdds.heartbeat.interval=30s, and so on) and is always on the classpath,
so counting a shipped
+ * default as a user choice would reject every run.
+ */
+ @Test
+ void shippedDefaultIsNotTreatedAsUserConfig() throws Exception {
+ LocalOzoneClusterConfig config = LocalOzoneClusterConfig.builder(
+ tempDir.resolve("local-ozone")).build();
+
+ try (LocalOzoneCluster cluster = newCluster(config)) {
+ OzoneConfiguration prepared =
cluster.prepareConfiguration().getConfiguration();
+
+ assertEquals("1s", prepared.get(HDDS_HEARTBEAT_INTERVAL));
+ assertNotEquals("1s", new
OzoneConfiguration().get(HDDS_HEARTBEAT_INTERVAL),
+ "the shipped default must differ from the local value, or this
guards nothing");
+ }
+ }
+
+ @Test
+ void readinessTimeoutNamesTheUnmetCondition() {
+ TimeoutException error = assertThrows(TimeoutException.class,
+ () -> LocalOzoneCluster.waitForReadiness(() -> "only 1 of 3 datanodes
have registered",
Review Comment:
I added focused tests for the safe-mode rule formatting and changed the
timeout test to use Duration.ZERO, so it no longer waits 500 ms.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]