Skip to content

Commit 00b0b85

Browse files
authored
Compare migrationConfig correctly for accounts and containers (#3179)
1 parent 256b6c2 commit 00b0b85

File tree

4 files changed

+128
-2
lines changed

4 files changed

+128
-2
lines changed

ambry-account/src/integration-test/java/com/github/ambry/account/MySqlAccountServiceIntegrationTest.java

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2116,4 +2116,94 @@ public void testContainerMigrationConfigIntegration() throws Exception {
21162116
assertNotNull("Container should exist after removing MigrationConfig", fetchedContainer3);
21172117
assertNull("MigrationConfig should be null after removal", fetchedContainer3.getMigrationConfig());
21182118
}
2119+
2120+
/**
2121+
* Integration test for adding migration config to an existing account that was created without one.
2122+
* This test verifies that the equality check properly detects the migration config change.
2123+
*/
2124+
@Test
2125+
public void testAddMigrationConfigToExistingAccount() throws Exception {
2126+
// 1. Create an account WITHOUT migration config
2127+
Account accountWithoutMigrationConfig =
2128+
new AccountBuilder((short) 127, "accountWithoutMigration", Account.AccountStatus.ACTIVE).build();
2129+
mySqlAccountService.updateAccounts(Collections.singletonList(accountWithoutMigrationConfig));
2130+
2131+
// 2. Fetch and verify migration config is null
2132+
Account fetched = mySqlAccountService.getAccountById(accountWithoutMigrationConfig.getId());
2133+
assertNotNull("Account should exist", fetched);
2134+
assertNull("MigrationConfig should be null initially", fetched.getMigrationConfig());
2135+
2136+
// 3. Update the account to ADD migration config
2137+
MigrationConfig migrationConfig =
2138+
new MigrationConfig(false, new MigrationConfig.WriteRamp(false, 75.0, 0.0, 0.0, false),
2139+
new MigrationConfig.ReadRamp(false, 25.0, 0.0, 0.0, 0.0, false), new MigrationConfig.ListRamp());
2140+
Account updatedWithMigrationConfig = new AccountBuilder(fetched).migrationConfig(migrationConfig).build();
2141+
mySqlAccountService.updateAccounts(Collections.singletonList(updatedWithMigrationConfig));
2142+
2143+
// 4. Fetch and verify migration config was added successfully
2144+
Account fetched2 = mySqlAccountService.getAccountById(updatedWithMigrationConfig.getId());
2145+
assertNotNull("Account should exist after adding MigrationConfig", fetched2);
2146+
assertNotNull("MigrationConfig should not be null after adding", fetched2.getMigrationConfig());
2147+
assertEquals("Async dual write percentage should match", 75.0,
2148+
fetched2.getMigrationConfig().getWriteRamp().getDualWriteAndDeleteAsyncPct(), 0.001);
2149+
assertEquals("Shadow read metadata percentage should match", 25.0,
2150+
fetched2.getMigrationConfig().getReadRamp().getShadowReadMetadataPct(), 0.001);
2151+
2152+
// 5. Verify that the account was detected as updated (not just added)
2153+
// This implicitly tests that equalsWithoutContainers() now includes migrationConfig
2154+
assertFalse("Account should not equal the original without migration config",
2155+
fetched.equalsWithoutContainers(fetched2));
2156+
}
2157+
2158+
/**
2159+
* Integration test for adding migration config to an existing container that was created without one.
2160+
* This test verifies that the equality check properly detects the migration config change.
2161+
*/
2162+
@Test
2163+
public void testAddMigrationConfigToExistingContainer() throws Exception {
2164+
// 1. Create an account with a container WITHOUT migration config
2165+
Container containerWithoutMigrationConfig =
2166+
new ContainerBuilder((short) 3, "containerWithoutMigration", Container.ContainerStatus.ACTIVE,
2167+
"containerWithoutMigration", (short) 128).build();
2168+
Account account =
2169+
new AccountBuilder((short) 128, "accountForContainerMigration", Account.AccountStatus.ACTIVE).containers(
2170+
Collections.singleton(containerWithoutMigrationConfig)).build();
2171+
mySqlAccountService.updateAccounts(Collections.singletonList(account));
2172+
2173+
// 2. Fetch and verify container migration config is null
2174+
Account fetched = mySqlAccountService.getAccountById(account.getId());
2175+
assertNotNull("Account should exist", fetched);
2176+
Container fetchedContainer = fetched.getContainerByName(containerWithoutMigrationConfig.getName());
2177+
assertNotNull("Container should exist", fetchedContainer);
2178+
assertNull("Container MigrationConfig should be null initially", fetchedContainer.getMigrationConfig());
2179+
2180+
// 3. Update the container to ADD migration config
2181+
MigrationConfig migrationConfig =
2182+
new MigrationConfig(true, new MigrationConfig.WriteRamp(false, 80.0, 10.0, 5.0, false),
2183+
new MigrationConfig.ReadRamp(false, 30.0, 20.0, 15.0, 10.0, false),
2184+
new MigrationConfig.ListRamp(false, 40.0, 50.0, false));
2185+
Container updatedContainer = new ContainerBuilder(fetchedContainer).setMigrationConfig(migrationConfig).build();
2186+
Account updatedAccount = new AccountBuilder(fetched).containers(Collections.singleton(updatedContainer)).build();
2187+
mySqlAccountService.updateAccounts(Collections.singletonList(updatedAccount));
2188+
2189+
// 4. Fetch and verify migration config was added successfully
2190+
Account fetched2 = mySqlAccountService.getAccountById(updatedAccount.getId());
2191+
assertNotNull("Account should exist after adding container MigrationConfig", fetched2);
2192+
Container fetchedContainer2 = fetched2.getContainerByName(updatedContainer.getName());
2193+
assertNotNull("Container should exist after adding MigrationConfig", fetchedContainer2);
2194+
assertNotNull("Container MigrationConfig should not be null after adding", fetchedContainer2.getMigrationConfig());
2195+
assertTrue("overrideAccountMigrationConfig should be true",
2196+
fetchedContainer2.getMigrationConfig().isOverrideAccountMigrationConfig());
2197+
assertEquals("Async dual write percentage should match", 80.0,
2198+
fetchedContainer2.getMigrationConfig().getWriteRamp().getDualWriteAndDeleteAsyncPct(), 0.001);
2199+
assertEquals("Shadow read metadata percentage should match", 30.0,
2200+
fetchedContainer2.getMigrationConfig().getReadRamp().getShadowReadMetadataPct(), 0.001);
2201+
assertEquals("Shadow list percentage should match", 40.0,
2202+
fetchedContainer2.getMigrationConfig().getListRamp().getShadowListPct(), 0.001);
2203+
2204+
// 5. Verify that the container was detected as updated (not just added)
2205+
// This implicitly tests that Container.equals() now includes migrationConfig
2206+
assertFalse("Container should not equal the original without migration config",
2207+
fetchedContainer.equals(fetchedContainer2));
2208+
}
21192209
}

ambry-api/src/main/java/com/github/ambry/account/Account.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -370,7 +370,8 @@ public boolean equalsWithoutContainers(Account account) {
370370
// We don't compare snapshot version and lastModifiedTime
371371
return id == account.id && name.equals(account.name) && status == account.status
372372
&& aclInheritedByContainer == account.aclInheritedByContainer && quotaResourceType == account.quotaResourceType
373-
&& Objects.equals(rampControl, account.rampControl);
373+
&& Objects.equals(rampControl, account.rampControl)
374+
&& Objects.equals(migrationConfig, account.migrationConfig);
374375
}
375376

376377
@Override

ambry-api/src/main/java/com/github/ambry/account/Container.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,8 @@ public boolean equals(Object o) {
756756
&& Objects.equals(accessControlAllowOrigin, container.accessControlAllowOrigin)
757757
&& Objects.equals(contentTypeWhitelistForFilenamesOnDownload, container.contentTypeWhitelistForFilenamesOnDownload)
758758
&& Objects.equals(cacheTtlInSecond, container.cacheTtlInSecond)
759-
&& Objects.equals(userMetadataKeysToNotPrefixInResponse, container.userMetadataKeysToNotPrefixInResponse);
759+
&& Objects.equals(userMetadataKeysToNotPrefixInResponse, container.userMetadataKeysToNotPrefixInResponse)
760+
&& Objects.equals(migrationConfig, container.migrationConfig);
760761
//@formatter:on
761762
}
762763

ambry-api/src/main/java/com/github/ambry/account/MigrationConfig.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ public boolean equals(Object o) {
109109
Double.compare(that.dualWriteAndDeleteSyncPctStrict, dualWriteAndDeleteSyncPctStrict) == 0 &&
110110
writeAndDeleteOnlyToSecondary == that.writeAndDeleteOnlyToSecondary;
111111
}
112+
113+
@Override
114+
public int hashCode() {
115+
return java.util.Objects.hash(forceDisableDualWriteAndDelete, dualWriteAndDeleteAsyncPct,
116+
dualWriteAndDeleteSyncPctNonStrict, dualWriteAndDeleteSyncPctStrict, writeAndDeleteOnlyToSecondary);
117+
}
112118
}
113119

114120
// Read ramp config
@@ -188,6 +194,12 @@ public boolean equals(Object o) {
188194
Double.compare(that.serveReadFromSecondaryPct, serveReadFromSecondaryPct) == 0 &&
189195
disableFallbackToPrimary == that.disableFallbackToPrimary;
190196
}
197+
198+
@Override
199+
public int hashCode() {
200+
return java.util.Objects.hash(forceDisableReadFromSecondary, shadowReadMetadataPct,
201+
shadowReadMd5Pct, shadowReadContentPct, serveReadFromSecondaryPct, disableFallbackToPrimary);
202+
}
191203
}
192204

193205
// List ramp config.
@@ -247,6 +259,12 @@ public boolean equals(Object o) {
247259
Double.compare(that.serveListFromSecondaryPct, serveListFromSecondaryPct) == 0 &&
248260
disableFallbackToPrimary == that.disableFallbackToPrimary;
249261
}
262+
263+
@Override
264+
public int hashCode() {
265+
return java.util.Objects.hash(forceDisableListFromSecondary, shadowListPct,
266+
serveListFromSecondaryPct, disableFallbackToPrimary);
267+
}
250268
}
251269

252270
// Default migration config.
@@ -281,4 +299,20 @@ public ReadRamp getReadRamp() {
281299
public ListRamp getListRamp() {
282300
return listRamp;
283301
}
302+
303+
@Override
304+
public boolean equals(Object o) {
305+
if (this == o) return true;
306+
if (o == null || getClass() != o.getClass()) return false;
307+
MigrationConfig that = (MigrationConfig) o;
308+
return overrideAccountMigrationConfig == that.overrideAccountMigrationConfig &&
309+
java.util.Objects.equals(writeRamp, that.writeRamp) &&
310+
java.util.Objects.equals(readRamp, that.readRamp) &&
311+
java.util.Objects.equals(listRamp, that.listRamp);
312+
}
313+
314+
@Override
315+
public int hashCode() {
316+
return java.util.Objects.hash(overrideAccountMigrationConfig, writeRamp, readRamp, listRamp);
317+
}
284318
}

0 commit comments

Comments
 (0)