Skip to content

Commit c4d9406

Browse files
committed
Improve test assertions
1 parent ec442f8 commit c4d9406

File tree

8 files changed

+161
-24
lines changed

8 files changed

+161
-24
lines changed

app/src/main/java/io/apicurio/registry/storage/impl/kafkasql/KafkaSqlRegistryStorage.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,8 @@ public void importData(EntityInputStream entities, boolean preserveGlobalId, boo
621621
DataImporter dataImporter = new SqlDataImporter(log, utils, this, preserveGlobalId,
622622
preserveContentId);
623623
dataImporter.importData(entities, () -> {
624+
// TODO Re-visit this, since Apicurio Registry 3 all messages live in the same partition, so there
625+
// should be no need to wait.
624626
// Because importing just pushes a bunch of Kafka messages, we may need to
625627
// wait for a few seconds before we send the reset messages. Due to partitioning,
626628
// we can't guarantee ordering of these next two messages, and we NEED them to
@@ -636,7 +638,7 @@ public void importData(EntityInputStream entities, boolean preserveGlobalId, boo
636638
}
637639

638640
/**
639-
* @see io.apicurio.registry.storage.RegistryStorage#importData(io.apicurio.registry.storage.impexp.EntityInputStream,
641+
* @see io.apicurio.registry.storage.RegistryStorage#upgradeData(io.apicurio.registry.storage.impexp.EntityInputStream,
640642
* boolean, boolean)
641643
*/
642644
@Override
@@ -645,6 +647,8 @@ public void upgradeData(EntityInputStream entities, boolean preserveGlobalId, bo
645647
DataImporter dataImporter = new SqlDataUpgrader(log, utils, this, preserveGlobalId,
646648
preserveContentId);
647649
dataImporter.importData(entities, () -> {
650+
// TODO Re-visit this, since Apicurio Registry 3 all messages live in the same partition, so there
651+
// should be no need to wait.
648652
// Because importing just pushes a bunch of Kafka messages, we may need to
649653
// wait for a few seconds before we send the reset messages. Due to partitioning,
650654
// we can't guarantee ordering of these next two messages, and we NEED them to

app/src/main/java/io/apicurio/registry/storage/importing/v2/SqlDataUpgrader.java

+40-7
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@
55
import io.apicurio.registry.model.GAV;
66
import io.apicurio.registry.storage.RegistryStorage;
77
import io.apicurio.registry.storage.dto.ArtifactReferenceDto;
8+
import io.apicurio.registry.storage.error.InvalidArtifactTypeException;
89
import io.apicurio.registry.storage.error.VersionAlreadyExistsException;
910
import io.apicurio.registry.storage.impexp.EntityInputStream;
1011
import io.apicurio.registry.storage.impl.sql.RegistryStorageContentUtils;
1112
import io.apicurio.registry.storage.impl.sql.SqlUtil;
13+
import io.apicurio.registry.types.ContentTypes;
1214
import io.apicurio.registry.types.RegistryException;
1315
import io.apicurio.registry.types.VersionState;
1416
import io.apicurio.registry.utils.impexp.Entity;
@@ -32,6 +34,13 @@
3234
import java.util.Set;
3335
import java.util.stream.Collectors;
3436

37+
import static io.apicurio.registry.types.ArtifactType.*;
38+
39+
/**
40+
* This class takes a stream of Registry v2 entities and imports them into the application using
41+
* {@link SqlDataUpgrader#importData(EntityInputStream, Runnable)} as it's entry point. It must be used in the
42+
* upgrade process from v2 to v3.
43+
*/
3544
public class SqlDataUpgrader extends AbstractDataImporter {
3645

3746
protected RegistryStorageContentUtils utils;
@@ -97,7 +106,7 @@ public void importArtifactVersion(ArtifactVersionEntity entity) {
97106
io.apicurio.registry.utils.impexp.v3.ArtifactVersionEntity newEntity = io.apicurio.registry.utils.impexp.v3.ArtifactVersionEntity
98107
.builder().createdOn(entity.createdOn).description(entity.description)
99108
.labels(entity.labels != null
100-
? entity.labels.stream().collect(Collectors.toMap(label -> label, label -> label))
109+
? entity.labels.stream().collect(Collectors.toMap(label -> label, label -> null))
101110
: Collections.emptyMap())
102111
.name(entity.name).owner(entity.createdBy)
103112
.state(VersionState.fromValue(entity.state.value())).artifactId(entity.artifactId)
@@ -111,7 +120,7 @@ public void importArtifactVersion(ArtifactVersionEntity entity) {
111120
.artifactType(entity.artifactType).createdOn(entity.createdOn)
112121
.description(entity.description).groupId(entity.groupId)
113122
.labels(entity.labels != null
114-
? entity.labels.stream().collect(Collectors.toMap(label -> label, label -> label))
123+
? entity.labels.stream().collect(Collectors.toMap(label -> label, s -> null))
115124
: Collections.emptyMap())
116125
.modifiedBy(entity.createdBy).modifiedOn(entity.createdOn).name(entity.name)
117126
.owner(entity.createdBy).build();
@@ -169,10 +178,10 @@ public void importContent(ContentEntity entity) {
169178

170179
// Finally, using the information from the old content, a V3 content entity is created.
171180
io.apicurio.registry.utils.impexp.v3.ContentEntity newEntity = io.apicurio.registry.utils.impexp.v3.ContentEntity
172-
.builder().contentType(entity.artifactType).contentHash(entity.contentHash)
173-
.artifactType(entity.artifactType).contentBytes(entity.contentBytes)
174-
.serializedReferences(entity.serializedReferences).canonicalHash(entity.canonicalHash)
175-
.contentId(entity.contentId).build();
181+
.builder().contentType(determineContentType(entity.artifactType, typedContent))
182+
.contentHash(entity.contentHash).artifactType(entity.artifactType)
183+
.contentBytes(entity.contentBytes).serializedReferences(entity.serializedReferences)
184+
.canonicalHash(entity.canonicalHash).contentId(entity.contentId).build();
176185

177186
storage.importContent(newEntity);
178187
log.debug("Content imported successfully: {}", entity);
@@ -210,7 +219,7 @@ public void importGroup(GroupEntity entity) {
210219
try {
211220
io.apicurio.registry.utils.impexp.v3.GroupEntity newEntity = io.apicurio.registry.utils.impexp.v3.GroupEntity
212221
.builder().artifactsType(entity.artifactsType).createdOn(entity.createdOn)
213-
.description(entity.description).groupId(entity.groupId).labels(entity.properties)
222+
.description(entity.description).groupId(entity.groupId).labels(Collections.emptyMap())
214223
.modifiedBy(entity.modifiedBy).modifiedOn(entity.modifiedOn).owner(entity.createdBy)
215224
.build();
216225
storage.importGroup(newEntity);
@@ -267,4 +276,28 @@ public void importData(EntityInputStream entities, Runnable postImportAction) {
267276
throw new RegistryException("Could not read next entity to import", ex);
268277
}
269278
}
279+
280+
private String determineContentType(String artifactTypeHint, TypedContent content) {
281+
if (content.getContentType() != null) {
282+
return content.getContentType();
283+
} else {
284+
switch (artifactTypeHint) {
285+
case ASYNCAPI:
286+
case JSON:
287+
case OPENAPI:
288+
case AVRO:
289+
// WARNING: This is only safe here. We can safely return JSON because in V2 we were
290+
// transforming all YAML to JSON before storing the content in the database.
291+
return ContentTypes.APPLICATION_JSON;
292+
case PROTOBUF:
293+
return ContentTypes.APPLICATION_PROTOBUF;
294+
case GRAPHQL:
295+
return ContentTypes.APPLICATION_GRAPHQL;
296+
case XML:
297+
case XSD:
298+
return ContentTypes.APPLICATION_XML;
299+
}
300+
}
301+
throw new InvalidArtifactTypeException("Invalid or unknown artifact type: " + artifactTypeHint);
302+
}
270303
}

app/src/main/java/io/apicurio/registry/upgrade/DataUpgrader.java app/src/main/java/io/apicurio/registry/upgrade/v2/DataUpgrader.java

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package io.apicurio.registry.upgrade;
1+
package io.apicurio.registry.upgrade.v2;
22

33
import io.apicurio.common.apps.config.Info;
44
import io.apicurio.registry.storage.RegistryStorage;
@@ -23,6 +23,11 @@
2323
import java.util.Optional;
2424
import java.util.zip.ZipInputStream;
2525

26+
/**
27+
* This class, once the storage is ready, checks if a v2 export file has been configured to restore the data
28+
* from an older server and, if there's one present, triggers the data upgrade process, eventually changing
29+
* the data structure and inserting the information into the database in v3 format.
30+
*/
2631
@ApplicationScoped
2732
public class DataUpgrader {
2833

@@ -34,13 +39,13 @@ public class DataUpgrader {
3439
RegistryStorage storage;
3540

3641
@ConfigProperty(name = "apicurio.upgrade.file.location")
37-
@Info(category = "import", description = "The import URL", availableSince = "3.0.0")
38-
Optional<URL> regisrtryV2ExportFile;
42+
@Info(category = "upgrade", description = "The URL to a v2 export file", availableSince = "3.0.0")
43+
Optional<URL> registryV2ExportFile;
3944

4045
void onStorageReady(@ObservesAsync StorageEvent ev) {
41-
if (StorageEventType.READY.equals(ev.getType()) && regisrtryV2ExportFile.isPresent()) {
46+
if (StorageEventType.READY.equals(ev.getType()) && registryV2ExportFile.isPresent()) {
4247
log.info("Registry V2 export file exists.");
43-
final URL registryV2ExportUrl = regisrtryV2ExportFile.get();
48+
final URL registryV2ExportUrl = registryV2ExportFile.get();
4449
try (final InputStream registryV2ExportZip = new BufferedInputStream(
4550
registryV2ExportUrl.openStream())) {
4651
log.info("Importing {} on startup.", registryV2ExportUrl);

app/src/test/java/io/apicurio/registry/DataUpgradeTest.java

+77-5
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
package io.apicurio.registry;
22

3+
import io.apicurio.registry.model.GroupId;
4+
import io.apicurio.registry.rest.client.models.ArtifactReference;
5+
import io.apicurio.registry.utils.IoUtil;
36
import io.apicurio.registry.utils.tests.ApicurioTestTags;
47
import io.quarkus.test.junit.QuarkusTest;
58
import io.quarkus.test.junit.TestProfile;
9+
import org.junit.jupiter.api.Assertions;
610
import org.junit.jupiter.api.BeforeEach;
711
import org.junit.jupiter.api.Tag;
812
import org.junit.jupiter.api.Test;
913

10-
import static io.restassured.RestAssured.given;
11-
import static org.hamcrest.Matchers.is;
14+
import java.util.List;
1215

1316
@QuarkusTest
1417
@TestProfile(DataUpgradeTestProfile.class)
@@ -22,8 +25,77 @@ protected void beforeEach() throws Exception {
2225
}
2326

2427
@Test
25-
public void testCheckImportedData() throws Exception {
26-
given().when().accept(CT_JSON).get("/registry/v3/search/artifacts").then().statusCode(200)
27-
.body("count", is(26));
28+
public void testArtifactsCount() {
29+
Assertions.assertEquals(26, clientV3.search().artifacts().get().getCount());
30+
}
31+
32+
@Test
33+
public void testCheckGlobalRules() throws Exception {
34+
// Global rules are enabled in the export file, they must be activated.
35+
Assertions.assertEquals(3, clientV3.admin().rules().get().size());
36+
Assertions.assertEquals("FULL", clientV3.admin().rules().byRuleType("VALIDITY").get().getConfig());
37+
Assertions.assertEquals("BACKWARD",
38+
clientV3.admin().rules().byRuleType("COMPATIBILITY").get().getConfig());
39+
Assertions.assertEquals("FULL", clientV3.admin().rules().byRuleType("INTEGRITY").get().getConfig());
40+
}
41+
42+
@Test
43+
public void testCheckAvroWithReferences() throws Exception {
44+
String dereferencedContent = IoUtil.toString(clientV3.groups().byGroupId("default").artifacts()
45+
.byArtifactId("AvroSerdeReferencesExample-value").versions().byVersionExpression("1")
46+
.content().get());
47+
48+
Assertions.assertEquals(
49+
"{\"type\":\"record\",\"name\":\"TradeRaw\",\"namespace\":\"com.kubetrade.schema.trade\",\"fields\":[{\"name\":\"tradeKey\",\"type\":{\"type\":\"record\",\"name\":\"TradeKey\",\"fields\":[{\"name\":\"exchange\",\"type\":{\"type\":\"enum\",\"name\":\"Exchange\",\"namespace\":\"com.kubetrade.schema.common\",\"symbols\":[\"GEMINI\"]}},{\"name\":\"key\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}]}},{\"name\":\"symbol\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},{\"name\":\"payload\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}]}",
50+
dereferencedContent);
51+
}
52+
53+
@Test
54+
public void testCheckProtobufWithReferences() throws Exception {
55+
List<String> artifactReferences = clientV3.groups()
56+
.byGroupId(GroupId.DEFAULT.getRawGroupIdWithDefaultString()).artifacts()
57+
.byArtifactId("ProtobufSerdeReferencesExample-value").versions().byVersionExpression("1")
58+
.references().get().stream().map(ArtifactReference::getArtifactId).toList();
59+
60+
Assertions.assertTrue(artifactReferences.containsAll(List.of("google/protobuf/timestamp.proto",
61+
"sample/table_info.proto", "sample/table_notification_type.proto")));
62+
Assertions.assertEquals(3, artifactReferences.size());
63+
}
64+
65+
@Test
66+
public void testCheckJsonWithReferences() throws Exception {
67+
List<String> artifactReferences = clientV3.groups()
68+
.byGroupId(GroupId.DEFAULT.getRawGroupIdWithDefaultString()).artifacts()
69+
.byArtifactId("JsonSerdeReferencesExample").versions().byVersionExpression("1").references()
70+
.get().stream().map(ArtifactReference::getArtifactId).toList();
71+
72+
Assertions.assertEquals(4, artifactReferences.size());
73+
Assertions.assertTrue(artifactReferences
74+
.containsAll(List.of("city", "qualification", "citizenIdentifier", "address")));
75+
76+
List<ArtifactReference> cityReferences = clientV3.groups()
77+
.byGroupId(GroupId.DEFAULT.getRawGroupIdWithDefaultString()).artifacts().byArtifactId("city")
78+
.versions().byVersionExpression("1").references().get();
79+
80+
Assertions.assertEquals(1, cityReferences.size());
81+
Assertions.assertTrue(cityReferences.stream().anyMatch(
82+
artifactReference -> artifactReference.getArtifactId().equals("cityQualification")));
83+
84+
List<ArtifactReference> identifierReferences = clientV3.groups()
85+
.byGroupId(GroupId.DEFAULT.getRawGroupIdWithDefaultString()).artifacts()
86+
.byArtifactId("citizenIdentifier").versions().byVersionExpression("1").references().get();
87+
88+
Assertions.assertEquals(1, identifierReferences.size());
89+
Assertions.assertTrue(identifierReferences.stream().anyMatch(
90+
artifactReference -> artifactReference.getArtifactId().equals("identifierQualification")));
91+
92+
/*
93+
* FIXME:carnalca this cannot be asserted until json schema dereferencing is implemented in v3. The
94+
* intention here is to make sure that the content can be dereferenced as in Registry v2. String
95+
* dereferencedContent = IoUtil.toString(clientV3.groups().byGroupId("default")
96+
* .artifacts().byArtifactId("JsonSerdeReferencesExample") .versions().byVersionExpression("1")
97+
* .content() .get(configuration -> { configuration.queryParameters.references =
98+
* HandleReferencesType.DEREFERENCE; }));
99+
*/
28100
}
29101
}

docs/modules/ROOT/partials/getting-started/ref-registry-all-configs.adoc

+16-5
Original file line numberDiff line numberDiff line change
@@ -384,11 +384,6 @@ The following {registry} configuration options are available for each component
384384
|
385385
|`2.1.0.Final`
386386
|The import URL
387-
|`apicurio.upgrade.file.location`
388-
|`optional<url>`
389-
|
390-
|`3.0.0`
391-
|The import URL
392387
|===
393388

394389
== limits
@@ -831,3 +826,19 @@ The following {registry} configuration options are available for each component
831826
|Navigation prefix for all UI paths
832827
|===
833828

829+
== upgrade
830+
.upgrade configuration options
831+
[.table-expandable,width="100%",cols="6,3,2,3,5",options="header"]
832+
|===
833+
|Name
834+
|Type
835+
|Default
836+
|Available from
837+
|Description
838+
|`apicurio.upgrade.file.location`
839+
|`optional<url>`
840+
|
841+
|`3.0.0`
842+
|The URL to a v2 export file
843+
|===
844+

schema-util/util-provider/src/main/java/io/apicurio/registry/types/provider/AvroArtifactTypeUtilProvider.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import io.apicurio.registry.content.extract.ContentExtractor;
1010
import io.apicurio.registry.content.refs.JsonSchemaReferenceFinder;
1111
import io.apicurio.registry.content.refs.ReferenceFinder;
12+
import io.apicurio.registry.content.util.ContentTypeUtil;
1213
import io.apicurio.registry.rules.compatibility.AvroCompatibilityChecker;
1314
import io.apicurio.registry.rules.compatibility.CompatibilityChecker;
1415
import io.apicurio.registry.rules.validity.AvroContentValidator;
@@ -36,7 +37,10 @@ private static String removeQuotedBrackets(String content) {
3637
@Override
3738
public boolean acceptsContent(TypedContent content, Map<String, TypedContent> resolvedReferences) {
3839
try {
39-
40+
if (content.getContentType() != null && content.getContentType().toLowerCase().contains("json")
41+
&& !ContentTypeUtil.isParsableJson(content.getContent())) {
42+
return false;
43+
}
4044
// Avro without quote
4145
final Schema.Parser parser = new Schema.Parser();
4246
final List<Schema> schemaRefs = new ArrayList<>();

schema-util/util-provider/src/main/java/io/apicurio/registry/types/provider/JsonArtifactTypeUtilProvider.java

+4
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ public class JsonArtifactTypeUtilProvider extends AbstractArtifactTypeUtilProvid
2424
@Override
2525
public boolean acceptsContent(TypedContent content, Map<String, TypedContent> resolvedReferences) {
2626
try {
27+
if (content.getContentType() != null && content.getContentType().toLowerCase().contains("json")
28+
&& !ContentTypeUtil.isParsableJson(content.getContent())) {
29+
return false;
30+
}
2731
JsonNode tree = ContentTypeUtil.parseJson(content.getContent());
2832
if (tree.has("$schema") && tree.get("$schema").asText().contains("json-schema.org")
2933
|| tree.has("properties")) {

schema-util/util-provider/src/main/java/io/apicurio/registry/types/provider/ProtobufArtifactTypeUtilProvider.java

+4
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ public class ProtobufArtifactTypeUtilProvider extends AbstractArtifactTypeUtilPr
2525
@Override
2626
public boolean acceptsContent(TypedContent content, Map<String, TypedContent> resolvedReferences) {
2727
try {
28+
String contentType = content.getContentType();
29+
if (contentType != null && !contentType.toLowerCase().contains("proto")) {
30+
return false;
31+
}
2832
ProtobufFile.toProtoFileElement(content.getContent().content());
2933
return true;
3034
} catch (Exception e) {

0 commit comments

Comments
 (0)