Skip to content

Commit 092cce7

Browse files
committed
test(aspect migration mutator): Handled review comments
1 parent 1c47ddc commit 092cce7

2 files changed

Lines changed: 47 additions & 276 deletions

File tree

entity-registry/src/test/java/com/linkedin/metadata/aspect/hooks/AspectMigrationMutatorBaseTest.java

Lines changed: 47 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
import static org.testng.Assert.assertTrue;
88

99
import com.linkedin.common.urn.Urn;
10-
import com.linkedin.common.urn.UrnUtils;
1110
import com.linkedin.data.template.RecordTemplate;
1211
import com.linkedin.events.metadata.ChangeType;
1312
import com.linkedin.metadata.aspect.AspectRetriever;
@@ -22,6 +21,7 @@
2221
import java.util.List;
2322
import java.util.stream.Collectors;
2423
import javax.annotation.Nonnull;
24+
import org.testng.SkipException;
2525
import org.testng.annotations.BeforeMethod;
2626
import org.testng.annotations.Test;
2727

@@ -31,13 +31,20 @@
3131
* on supplying realistic aspect payloads and asserting the correctness of the transformed result.
3232
*
3333
* <p>Extend this class for every concrete {@link AspectMigrationMutator} implementation. All
34-
* contract-level {@code @Test} methods are inherited automatically — the subclass only needs to
35-
* supply three things:
34+
* contract-level {@code @Test} methods are inherited automatically. The subclass must implement
35+
* four abstract methods and may optionally override one more:
3636
*
3737
* <ol>
38-
* <li>{@link #mutator()} — the implementation under test
39-
* <li>{@link #provideSourceAspect()} — a realistic aspect payload at {@code sourceVersion}
40-
* <li>{@link #assertTransformed(RecordTemplate)} — assertions specific to the migration logic
38+
* <li><b>Required:</b> {@link #mutator()} — the implementation under test
39+
* <li><b>Required:</b> {@link #entityUrn()} — a URN whose entity type matches the aspect (e.g. a
40+
* dataset URN for a dataset aspect, a dataJob URN for a dataJob aspect)
41+
* <li><b>Required:</b> {@link #provideSourceAspect()} — a realistic aspect payload at {@code
42+
* sourceVersion}, ready to be transformed
43+
* <li><b>Required:</b> {@link #assertTransformed(RecordTemplate)} — assertions that verify the
44+
* migration logic produced the correct result
45+
* <li><b>Optional:</b> {@link #configureRetrieverMock(AspectRetriever)} — stub retriever behavior
46+
* when the mutator looks up related aspects during the transform; {@link #mockRetriever} is
47+
* also accessible as a field for per-test stubs or {@code verify()} calls
4148
* </ol>
4249
*
4350
* <p>Example subclass:
@@ -49,6 +56,10 @@
4956
* return new MyAspectV1ToV2Migrator();
5057
* }
5158
*
59+
* @Override protected Urn entityUrn() {
60+
* return UrnUtils.getUrn("urn:li:dataset:(urn:li:dataPlatform:hive,test,PROD)");
61+
* }
62+
*
5263
* @Override protected RecordTemplate provideSourceAspect() {
5364
* Owner v1 = new Owner();
5465
* v1.setOldField("someValue");
@@ -65,9 +76,6 @@
6576
*/
6677
public abstract class AspectMigrationMutatorBaseTest {
6778

68-
private static final Urn DATASET_URN =
69-
UrnUtils.getUrn("urn:li:dataset:(urn:li:dataPlatform:hive,test,PROD)");
70-
7179
// Abstract
7280

7381
/** Returns the {@link AspectMigrationMutator} implementation under test. */
@@ -90,18 +98,36 @@ public abstract class AspectMigrationMutatorBaseTest {
9098
*/
9199
protected abstract void assertTransformed(@Nonnull RecordTemplate result);
92100

101+
/**
102+
* Returns the entity URN used when constructing test items. Must match the entity type that the
103+
* mutator's aspect belongs to (e.g. return a {@code dataJob} URN for a dataJob aspect mutator).
104+
*/
105+
@Nonnull
106+
protected abstract Urn entityUrn();
107+
108+
/**
109+
* Hook for subclasses to configure additional retriever mock behavior. Called at the end of
110+
* {@link #setUp()} after the base stubs are in place. Override when the mutator under test uses
111+
* the retriever to compute the transform (e.g. to look up related aspects).
112+
*/
113+
protected void configureRetrieverMock(@Nonnull AspectRetriever retrieverMock) {
114+
// no-op by default
115+
}
116+
93117
// Shared
94118

95119
protected EntityRegistry entityRegistry;
96120
protected RetrieverContext retrieverContext;
121+
protected AspectRetriever mockRetriever;
97122

98123
@BeforeMethod
99124
public void setUp() {
100125
entityRegistry = new TestEntityRegistry();
101-
AspectRetriever mockRetriever = mock(AspectRetriever.class);
126+
mockRetriever = mock(AspectRetriever.class);
102127
when(mockRetriever.getEntityRegistry()).thenReturn(entityRegistry);
103128
retrieverContext = mock(RetrieverContext.class);
104129
when(retrieverContext.getAspectRetriever()).thenReturn(mockRetriever);
130+
configureRetrieverMock(mockRetriever);
105131
}
106132

107133
// Version contract (auto-inherited)
@@ -146,7 +172,7 @@ public void writeMutation_atSourceVersion_mutatesAndBumpsVersion() {
146172
public void writeMutation_atDefaultSchemaVersion_mutatesAndBumpsVersion() {
147173
// null schemaVersion is treated as DEFAULT_SCHEMA_VERSION — only relevant when sourceVersion==1
148174
if (mutator().getSourceVersion() != AspectMigrationMutator.DEFAULT_SCHEMA_VERSION) {
149-
return;
175+
throw new SkipException("only applies when sourceVersion == DEFAULT_SCHEMA_VERSION");
150176
}
151177
ChangeMCP item = buildItem(provideSourceAspect(), new SystemMetadata()); // no schemaVersion set
152178

@@ -155,36 +181,25 @@ public void writeMutation_atDefaultSchemaVersion_mutatesAndBumpsVersion() {
155181

156182
assertTrue(results.get(0).getSecond(), "Expected mutated=true for null schemaVersion (=1)");
157183
assertEquals((long) item.getSystemMetadata().getSchemaVersion(), mutator().getTargetVersion());
158-
}
159-
160-
@Test
161-
public void writeMutation_alreadyAtTargetVersion_isNoOp() {
162-
SystemMetadata sm = new SystemMetadata();
163-
sm.setSchemaVersion(mutator().getTargetVersion());
164-
165-
ChangeMCP item = buildItem(provideSourceAspect(), sm);
166-
167-
List<Pair<ChangeMCP, Boolean>> results =
168-
mutator().writeMutation(List.of(item), retrieverContext).collect(Collectors.toList());
169-
170-
assertFalse(results.get(0).getSecond(), "Expected no-op when already at targetVersion");
171-
assertEquals(
172-
(long) item.getSystemMetadata().getSchemaVersion(),
173-
mutator().getTargetVersion(),
174-
"schemaVersion must remain unchanged");
184+
assertTransformed(item.getRecordTemplate());
175185
}
176186

177187
@Test
178188
public void writeMutation_futureVersion_isNoOp() {
179189
SystemMetadata sm = new SystemMetadata();
180-
sm.setSchemaVersion(mutator().getTargetVersion() + 1); // ahead of this mutator
190+
long futureVersion = mutator().getTargetVersion() + 1;
191+
sm.setSchemaVersion(futureVersion); // ahead of this mutator
181192

182193
ChangeMCP item = buildItem(provideSourceAspect(), sm);
183194

184195
List<Pair<ChangeMCP, Boolean>> results =
185196
mutator().writeMutation(List.of(item), retrieverContext).collect(Collectors.toList());
186197

187198
assertFalse(results.get(0).getSecond(), "Expected no-op for version ahead of targetVersion");
199+
assertEquals(
200+
(long) item.getSystemMetadata().getSchemaVersion(),
201+
futureVersion,
202+
"schemaVersion must not be modified for a future version");
188203
}
189204

190205
// Read path (auto-inherited)
@@ -207,25 +222,13 @@ public void readMutation_atSourceVersion_mutatesAndBumpsVersion() {
207222
assertTransformed(item.getRecordTemplate());
208223
}
209224

210-
@Test
211-
public void readMutation_alreadyAtTargetVersion_isNoOp() {
212-
SystemMetadata sm = new SystemMetadata();
213-
sm.setSchemaVersion(mutator().getTargetVersion());
214-
215-
ChangeMCP item = buildItem(provideSourceAspect(), sm);
216-
217-
List<Pair<ReadItem, Boolean>> results =
218-
mutator().readMutation(List.of(item), retrieverContext).collect(Collectors.toList());
219-
220-
assertFalse(results.get(0).getSecond(), "Expected no-op on read path when already migrated");
221-
}
222-
223225
// Helper
224226
protected ChangeMCP buildItem(RecordTemplate record, SystemMetadata sm) {
227+
Urn urn = entityUrn();
225228
return TestMCP.builder()
226-
.urn(DATASET_URN)
229+
.urn(urn)
227230
.changeType(ChangeType.UPSERT)
228-
.entitySpec(entityRegistry.getEntitySpec("dataset"))
231+
.entitySpec(entityRegistry.getEntitySpec(urn.getEntityType()))
229232
.aspectSpec(entityRegistry.getAspectSpecs().get(mutator().getAspectName()))
230233
.recordTemplate(record)
231234
.systemMetadata(sm)

0 commit comments

Comments
 (0)