1 package io.apicurio.registry.maven;
2
3 import com.fasterxml.jackson.core.JsonProcessingException;
4 import com.fasterxml.jackson.databind.JsonNode;
5 import com.fasterxml.jackson.databind.ObjectMapper;
6 import com.github.tomakehurst.wiremock.WireMockServer;
7 import com.github.tomakehurst.wiremock.common.FileSource;
8 import com.github.tomakehurst.wiremock.core.WireMockConfiguration;
9 import com.github.tomakehurst.wiremock.extension.Parameters;
10 import com.github.tomakehurst.wiremock.extension.ResponseTransformer;
11 import com.github.tomakehurst.wiremock.http.Request;
12 import com.github.tomakehurst.wiremock.http.Response;
13 import io.apicurio.registry.rest.v3.beans.IfArtifactExists;
14 import io.apicurio.registry.types.ArtifactType;
15 import org.junit.jupiter.api.AfterEach;
16 import org.junit.jupiter.api.BeforeEach;
17 import org.junit.jupiter.api.Test;
18
19 import java.io.File;
20 import java.nio.file.Paths;
21 import java.util.HashSet;
22 import java.util.Set;
23
24 import static com.github.tomakehurst.wiremock.client.WireMock.*;
25 import static org.junit.jupiter.api.Assertions.assertEquals;
26 import static org.junit.jupiter.api.Assertions.assertTrue;
27
28 public class RegisterAsyncApiAvroAutoRefsTest {
29
30 private RegisterRegistryMojo mojo;
31 private final File examplesRoot = Paths.get("../../examples/").toAbsolutePath().toFile();
32 private WireMockServer wireMockServer;
33 private Set<String> registeredArtifacts = new HashSet<>();
34
35 @BeforeEach public void setup() {
36
37 wireMockServer = new WireMockServer(WireMockConfiguration.wireMockConfig().dynamicPort()
38 .extensions(new CaptureRequestTransformer()));
39 wireMockServer.start();
40
41
42 wireMockServer.stubFor(post(urlPathMatching("/apis/registry/v3/groups/.*/artifacts")).willReturn(
43 aResponse().withTransformers("capture-request-transformer").withStatus(200)
44 .withHeader("Content-Type", "application/json")));
45
46 mojo = new RegisterRegistryMojo();
47 mojo.setRegistryUrl(wireMockServer.baseUrl() + "/apis/registry/v3");
48
49
50 registeredArtifacts.clear();
51 }
52
53 @AfterEach public void tearDown() {
54 if (wireMockServer != null) {
55 wireMockServer.stop();
56 }
57 }
58
59 @Test public void testAsyncApiWithAvroAutoRefs() throws Exception {
60 File exampleDir = new File(examplesRoot, "asyncapi-avro-maven-with-references-auto");
61 File asyncApiFile = new File(exampleDir, "src/main/resources/schemas/asyncapi-avro-refs.yml");
62
63
64 RegisterArtifact artifact = new RegisterArtifact();
65 artifact.setGroupId("asyncapi-avro-maven-with-references-auto");
66 artifact.setArtifactId("CustomersExample");
67 artifact.setVersion("1.0.0");
68 artifact.setArtifactType(ArtifactType.ASYNCAPI);
69 artifact.setFile(asyncApiFile);
70 artifact.setIfExists(IfArtifactExists.FIND_OR_CREATE_VERSION);
71 artifact.setCanonicalize(true);
72 artifact.setAutoRefs(true);
73
74 mojo.setArtifacts(java.util.Collections.singletonList(artifact));
75 mojo.execute();
76
77 assertEquals(6, registeredArtifacts.size());
78 assertTrue(registeredArtifacts.contains("asyncapi-avro-maven-with-references-auto:CustomersExample"));
79 assertTrue(registeredArtifacts.contains(
80 "asyncapi-avro-maven-with-references-auto:io.example.api.dtos.CustomerEvent"));
81 assertTrue(registeredArtifacts.contains(
82 "asyncapi-avro-maven-with-references-auto:io.example.api.dtos.Address"));
83 assertTrue(registeredArtifacts.contains(
84 "asyncapi-avro-maven-with-references-auto:io.example.api.dtos.PaymentMethod"));
85 assertTrue(registeredArtifacts.contains(
86 "asyncapi-avro-maven-with-references-auto:io.example.api.dtos.PaymentMethodType"));
87 assertTrue(registeredArtifacts.contains(
88 "asyncapi-avro-maven-with-references-auto:io.example.api.dtos.CustomerDeletedEvent"));
89
90 }
91
92 @Test public void testAvroAutoRefs() throws Exception {
93 File exampleDir = new File(examplesRoot, "avro-maven-with-references-auto");
94 File avroFile = new File(exampleDir, "src/main/resources/schemas/TradeRaw.avsc");
95
96
97 RegisterArtifact artifact = new RegisterArtifact();
98 artifact.setGroupId("com.kubetrade.schema.trade");
99 artifact.setArtifactId("TradeRaw");
100 artifact.setVersion("2.0");
101 artifact.setArtifactType(ArtifactType.AVRO);
102 artifact.setFile(avroFile);
103 artifact.setIfExists(IfArtifactExists.FIND_OR_CREATE_VERSION);
104 artifact.setCanonicalize(true);
105 artifact.setAutoRefs(true);
106
107 mojo.setArtifacts(java.util.Collections.singletonList(artifact));
108 mojo.execute();
109
110 assertEquals(4, registeredArtifacts.size());
111 assertTrue(registeredArtifacts.contains("com.kubetrade.schema.trade:TradeRaw"));
112 assertTrue(registeredArtifacts.contains("com.kubetrade.schema.trade:TradeKey"));
113 assertTrue(registeredArtifacts.contains("com.kubetrade.schema.trade:TradeValue"));
114 assertTrue(registeredArtifacts.contains("com.kubetrade.schema.common:Exchange"));
115 }
116
117 @Test public void testAvroAnalyzeDirectory() throws Exception {
118 File exampleDir = new File(examplesRoot, "avro-maven-with-references-auto");
119 File avroFile = new File(exampleDir, "src/main/resources/schemas/TradeRaw.avsc");
120
121
122 RegisterArtifact artifact = new RegisterArtifact();
123 artifact.setGroupId("avro-maven-with-analyze-directory");
124 artifact.setArtifactId("TradeRaw");
125 artifact.setVersion("2.0");
126 artifact.setArtifactType(ArtifactType.AVRO);
127 artifact.setFile(avroFile);
128 artifact.setIfExists(IfArtifactExists.FIND_OR_CREATE_VERSION);
129 artifact.setCanonicalize(true);
130 artifact.setAnalyzeDirectory(true);
131
132 mojo.setArtifacts(java.util.Collections.singletonList(artifact));
133 mojo.execute();
134
135 assertEquals(4, registeredArtifacts.size());
136 assertTrue(registeredArtifacts.contains("avro-maven-with-analyze-directory:TradeRaw"));
137 assertTrue(registeredArtifacts.contains(
138 "avro-maven-with-analyze-directory:com.kubetrade.schema.trade.TradeKey"));
139 assertTrue(registeredArtifacts.contains(
140 "avro-maven-with-analyze-directory:com.kubetrade.schema.trade.TradeValue"));
141 assertTrue(registeredArtifacts.contains(
142 "avro-maven-with-analyze-directory:com.kubetrade.schema.common.Exchange"));
143 }
144
145
146 class CaptureRequestTransformer extends ResponseTransformer {
147
148 @Override public String getName() {
149 return "capture-request-transformer";
150 }
151
152 @Override public Response transform(Request request, Response response, FileSource fileSource,
153 Parameters parameters) {
154 try {
155 String responseBody = generateResponseBasedOnRequest(request);
156 return Response.Builder.like(response).but().body(responseBody).build();
157 } catch (JsonProcessingException e) {
158 throw new RuntimeException(e);
159 }
160
161 }
162
163 private String generateResponseBasedOnRequest(Request request) throws JsonProcessingException {
164 String url = request.getUrl();
165 String body = request.getBodyAsString();
166
167 String groupId = extractGroupIdFromUrl(url);
168 String artifactId = extractArtifactIdFromBody(body);
169
170 registeredArtifacts.add(groupId + ":" + artifactId);
171
172 return """
173 {
174 "version": {
175 "version": "1",
176 "globalId": 12345,
177 "contentId": 67890
178 },
179 "artifact": {
180 "groupId": "%s",
181 "artifactId": "%s"
182 }
183 }
184 """.formatted(groupId, artifactId);
185 }
186
187 private String extractGroupIdFromUrl(String url) {
188
189 String[] parts = url.split("/");
190 for (int i = 0; i < parts.length - 1; i++) {
191 if ("groups".equals(parts[i]) && i + 1 < parts.length) {
192 return parts[i + 1];
193 }
194 }
195 return "default";
196 }
197
198 private String extractArtifactIdFromBody(String body) throws JsonProcessingException {
199 ObjectMapper mapper = new ObjectMapper();
200 JsonNode jsonNode = mapper.readTree(body);
201
202 JsonNode artifactIdNode = jsonNode.get("artifactId");
203 if (artifactIdNode != null && !artifactIdNode.isNull()) {
204 return artifactIdNode.asText();
205 }
206 throw new RuntimeException("ArtifactId not found in request body");
207 }
208
209 }
210 }
211