Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package com.github.ambry.account;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.util.Map;

Expand All @@ -24,6 +25,7 @@
* updated fields through this builder. A {@link Dataset} can be built in two ways: 1) from an existing {@link Dataset}
* object; and 2) by supplying required fields of a {@link Dataset}.
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class DatasetBuilder {
// necessary
private String accountName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

// Migration config applicable to accounts and containers used to migrate from one storage backend to another.
// Determines whether an op is sent to primary storage backend only, secondary storage backend only or both.
@JsonIgnoreProperties(ignoreUnknown = true)
public class MigrationConfig {
// Applicable only to container metadata and used to override account level config.
public static final String OVERRIDE_ACCOUNT_MIGRATION_CONFIG = "overrideAccountMigrationConfig";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@
package com.github.ambry.account;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonIgnoreProperties(ignoreUnknown = true)
public class RampControl {
public static final String SECONDARY_ENABLED_KEY = "secondaryEnabled";
@JsonProperty(SECONDARY_ENABLED_KEY)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package com.github.ambry.server;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.github.ambry.server.storagestats.HostAccountStorageStats;

Expand All @@ -23,6 +24,7 @@
*/
@JsonPropertyOrder({"header", "stats"})
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class HostAccountStorageStatsWrapper {
private StatsHeader header;
private HostAccountStorageStats stats;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,31 @@
*/
package com.github.ambry.server;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.github.ambry.server.storagestats.HostPartitionClassStorageStats;


/**
* A wrapper model object that contains a {@link HostPartitionClassStorageStats} and a {@link StatsHeader} with metadata.
*/
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
@JsonIgnoreProperties(ignoreUnknown = true)
public class HostPartitionClassStorageStatsWrapper {
private final StatsHeader header;
private final HostPartitionClassStorageStats stats;
private StatsHeader header;
private HostPartitionClassStorageStats stats;

public HostPartitionClassStorageStatsWrapper(StatsHeader header, HostPartitionClassStorageStats stats) {
this.header = header;
this.stats = stats;
}

/**
* Empty constructor for Jackson
*/
public HostPartitionClassStorageStatsWrapper() {
}

/**
* Return {@link StatsHeader}.
* @return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import java.util.ArrayList;
import java.util.List;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;


Expand All @@ -26,6 +27,7 @@
*/
@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
@JsonPropertyOrder({"description", "timestamp", "storesContactedCount", "storesRespondedCount", "unreachableStores"})
@JsonIgnoreProperties(ignoreUnknown = true)
public class StatsHeader {
public enum StatsDescription {
STORED_DATA_SIZE
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.fasterxml.jackson.annotation.JsonAnyGetter;
import com.fasterxml.jackson.annotation.JsonAnySetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -48,6 +49,7 @@
* }
* }
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class HostAccountStorageStats {
@JsonIgnore
private Map<Long, Map<Short, Map<Short, ContainerStorageStats>>> storageStats = new HashMap<>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/
package com.github.ambry.server.storagestats;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
Expand Down Expand Up @@ -44,6 +45,7 @@
* }
* }
*/
@JsonIgnoreProperties(ignoreUnknown = true)
public class HostPartitionClassStorageStats {
private Map<String, Map<Long, Map<Short, Map<Short, ContainerStorageStats>>>> storageStats = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 2023 LinkedIn Corp. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
package com.github.ambry.account;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static org.junit.Assert.*;


/**
* Forward and backward compatibility tests for {@link Dataset} / {@link DatasetBuilder}.
*/
public class DatasetBuilderCompatibilityTest {

private final ObjectMapper objectMapper = new ObjectMapper();

/**
* Forward compatibility: unknown fields in Dataset JSON should be ignored during deserialization.
*/
@Test
public void testForwardCompatibility() throws Exception {
String json = "{\"accountName\":\"testAccount\",\"containerName\":\"testContainer\","
+ "\"datasetName\":\"testDataset\",\"versionSchema\":\"TIMESTAMP\","
+ "\"retentionCount\":10,\"someNewField\":\"futureValue\",\"anotherNewField\":true}";
Dataset deserialized = objectMapper.readValue(json, Dataset.class);
assertEquals("testAccount", deserialized.getAccountName());
assertEquals("testContainer", deserialized.getContainerName());
assertEquals("testDataset", deserialized.getDatasetName());
assertEquals(Dataset.VersionSchema.TIMESTAMP, deserialized.getVersionSchema());
assertEquals(Integer.valueOf(10), deserialized.getRetentionCount());
}

/**
* Backward compatibility: Dataset JSON without optional fields should deserialize with null defaults.
*/
@Test
public void testBackwardCompatibility() throws Exception {
String json = "{\"accountName\":\"testAccount\",\"containerName\":\"testContainer\","
+ "\"datasetName\":\"testDataset\",\"versionSchema\":\"MONOTONIC\"}";
Dataset deserialized = objectMapper.readValue(json, Dataset.class);
assertEquals("testAccount", deserialized.getAccountName());
assertEquals(Dataset.VersionSchema.MONOTONIC, deserialized.getVersionSchema());
assertNull(deserialized.getRetentionPolicy());
assertNull(deserialized.getRetentionCount());
assertNull(deserialized.getRetentionTimeInSeconds());
assertNull(deserialized.getUserTags());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,40 @@ public void testDeserializationIgnoresUnknownFields() throws Exception {
assertEquals(30.0, listRamp.getShadowListPct(), 0.001);
}

/**
* Forward compatibility: MigrationConfig (outer class) with unknown fields should deserialize successfully.
*/
@Test
public void testMigrationConfigIgnoresUnknownFields() throws Exception {
String json = "{\"overrideAccountMigrationConfig\":true,"
+ "\"writeRamp\":{\"forceDisableDualWriteAndDelete\":false,\"dualWriteAndDeleteAsyncPct\":10.0,"
+ "\"dualWriteAndDeleteSyncPctNonStrict\":0.0,\"dualWriteAndDeleteSyncPctStrict\":0.0,"
+ "\"writeAndDeleteOnlyToSecondary\":false},"
+ "\"readRamp\":{\"forceDisableReadFromSecondary\":false,\"shadowReadMetadataPct\":5.0,"
+ "\"shadowReadMd5Pct\":0.0,\"shadowReadContentPct\":0.0,\"serveReadFromSecondaryPct\":0.0,"
+ "\"disableFallbackToPrimary\":false,\"dualHeadSyncPct\":0.0},"
+ "\"listRamp\":{\"forceDisableListFromSecondary\":false,\"shadowListPct\":0.0,"
+ "\"serveListFromSecondaryPct\":0.0,\"disableFallbackToPrimary\":false},"
+ "\"someNewTopLevelField\":\"futureValue\"}";
MigrationConfig deserialized = objectMapper.readValue(json, MigrationConfig.class);
assertTrue(deserialized.isOverrideAccountMigrationConfig());
assertEquals(10.0, deserialized.getWriteRamp().getDualWriteAndDeleteAsyncPct(), 0.001);
assertEquals(5.0, deserialized.getReadRamp().getShadowReadMetadataPct(), 0.001);
}

/**
* Backward compatibility: MigrationConfig with missing optional ramps should deserialize with nulls.
*/
@Test
public void testMigrationConfigBackwardCompatibility() throws Exception {
String json = "{\"overrideAccountMigrationConfig\":false}";
MigrationConfig deserialized = objectMapper.readValue(json, MigrationConfig.class);
assertFalse(deserialized.isOverrideAccountMigrationConfig());
assertNull(deserialized.getWriteRamp());
assertNull(deserialized.getReadRamp());
assertNull(deserialized.getListRamp());
}

@Test
public void testDeserializationWithoutDualHeadSyncPct() throws Exception {
String json = "{\"overrideAccountMigrationConfig\":false,"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright 2017 LinkedIn Corp. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
package com.github.ambry.account;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Test;

import static org.junit.Assert.*;


/**
* Forward and backward compatibility tests for {@link RampControl}.
*/
public class RampControlCompatibilityTest {

private final ObjectMapper objectMapper = new ObjectMapper();

/**
* Forward compatibility: unknown fields in JSON should be ignored.
*/
@Test
public void testForwardCompatibility() throws Exception {
String json = "{\"secondaryEnabled\":true,\"someNewField\":\"futureValue\",\"anotherNewField\":42}";
RampControl deserialized = objectMapper.readValue(json, RampControl.class);
assertTrue(deserialized.isSecondaryEnabled());
}

/**
* Backward compatibility: minimal JSON with only known fields should deserialize correctly.
*/
@Test
public void testBackwardCompatibility() throws Exception {
String json = "{\"secondaryEnabled\":false}";
RampControl deserialized = objectMapper.readValue(json, RampControl.class);
assertFalse(deserialized.isSecondaryEnabled());
}
}
Loading
Loading