Skip to content

Commit 8a15e1d

Browse files
authored
Allow yaml-test load template from json to add dependencies (#3452)
now users can put dependencies in src/test/proto, and `load schema template` command will automatically load these dependencies.
1 parent 8c6c6f4 commit 8a15e1d

13 files changed

+337
-225
lines changed

yaml-tests/src/main/java/com/apple/foundationdb/relational/yamltests/command/CommandUtil.java

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
import com.apple.foundationdb.relational.recordlayer.metadata.RecordLayerSchemaTemplate;
2828
import com.apple.foundationdb.relational.yamltests.generated.schemainstance.SchemaInstanceOuterClass;
2929

30+
import com.google.gson.JsonArray;
31+
import com.google.gson.JsonElement;
32+
import com.google.gson.JsonObject;
33+
import com.google.gson.JsonParser;
3034
import com.google.protobuf.Descriptors;
3135
import com.google.protobuf.util.JsonFormat;
3236
import org.apache.commons.lang3.tuple.ImmutablePair;
@@ -39,10 +43,15 @@
3943
import java.lang.reflect.Method;
4044
import java.nio.charset.StandardCharsets;
4145
import java.nio.file.Files;
46+
import java.nio.file.Path;
4247
import java.nio.file.Paths;
48+
import java.util.ArrayList;
4349
import java.util.HashMap;
50+
import java.util.List;
4451
import java.util.Map;
4552
import java.util.StringTokenizer;
53+
import java.util.regex.Matcher;
54+
import java.util.regex.Pattern;
4655

4756
/**
4857
* Util class for yaml-tests commands.
@@ -93,13 +102,39 @@ public static Map<String, IndexState> fromIndexStateProto(Map<String, SchemaInst
93102

94103
private static RecordMetaData loadRecordMetaDataFromJson(String jsonFileName) {
95104
RecordMetaDataProto.MetaData.Builder builder = RecordMetaDataProto.MetaData.newBuilder();
105+
List<String> deps = new ArrayList<>();
96106
try {
97-
String json = Files.readString(Paths.get(jsonFileName), StandardCharsets.UTF_8);
98-
JsonFormat.parser().ignoringUnknownFields().merge(json, builder);
107+
String jsonStr = Files.readString(Paths.get(jsonFileName), StandardCharsets.UTF_8);
108+
JsonFormat.parser().ignoringUnknownFields().merge(jsonStr, builder);
109+
JsonObject obj = JsonParser.parseString(jsonStr).getAsJsonObject();
110+
JsonArray dependencyArray = obj.getAsJsonObject("records").getAsJsonArray("dependency");
111+
for (JsonElement element : dependencyArray) {
112+
String curDep = element.getAsString();
113+
if (!"record_metadata.proto".equals(curDep) && !"record_metadata_options.proto".equals(curDep)) {
114+
deps.add(curDep);
115+
}
116+
}
99117
} catch (IOException e) {
100118
throw new RuntimeException(e);
101119
}
102-
return RecordMetaData.build(builder.build());
120+
121+
List<Descriptors.FileDescriptor> fileDescriptors = new ArrayList<>();
122+
for (String dep: deps) {
123+
try {
124+
String fullClassName = getFullClassName(dep);
125+
Class<?> act = Class.forName(fullClassName);
126+
Method method = act.getMethod("getDescriptor");
127+
fileDescriptors.add((Descriptors.FileDescriptor) method.invoke(null));
128+
} catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException |
129+
IOException | ClassNotFoundException e) {
130+
throw new RuntimeException(e);
131+
}
132+
}
133+
134+
return RecordMetaData.newBuilder()
135+
.addDependencies(fileDescriptors.toArray(new Descriptors.FileDescriptor[0]))
136+
.setRecords(builder.build())
137+
.getRecordMetaData();
103138
}
104139

105140
private static Pair<String, String> parseLoadTemplateString(String loadCommandString) {
@@ -115,6 +150,48 @@ private static Pair<String, String> parseLoadTemplateString(String loadCommandSt
115150
return new ImmutablePair<>(first, second);
116151
}
117152

153+
private static String getFullClassName(String protoFileName) throws IOException {
154+
String fullProtoFileName = "src/test/proto/" + protoFileName;
155+
final Path path = Paths.get(fullProtoFileName);
156+
String content = Files.readString(path);
157+
158+
// Match 'package my.package.name;'
159+
Pattern packagePattern = Pattern.compile("package\\s+([\\w\\.]+);");
160+
Matcher packageMatcher = packagePattern.matcher(content);
161+
162+
String protoPackage;
163+
if (packageMatcher.find()) {
164+
protoPackage = packageMatcher.group(1);
165+
} else {
166+
throw new IllegalArgumentException("unable to find package name in proto file:" + fullProtoFileName);
167+
}
168+
169+
// Match 'option java_package = "com.example";'
170+
Pattern javaPackagePattern = Pattern.compile("option\\s+java_package\\s*=\\s*\"([^\"]+)\";");
171+
Matcher javaPackageMatcher = javaPackagePattern.matcher(content);
172+
173+
String javaPackage = null;
174+
if (javaPackageMatcher.find()) {
175+
javaPackage = javaPackageMatcher.group(1);
176+
}
177+
178+
// Final package name: java_package if exists, otherwise proto package
179+
String effectivePackage = javaPackage != null ? javaPackage : protoPackage;
180+
181+
// Match java_outer_classname
182+
Pattern outerClassPattern = Pattern.compile("option\\s+java_outer_classname\\s*=\\s*\"([^\"]+)\";");
183+
Matcher outerClassMatcher = outerClassPattern.matcher(content);
184+
185+
String outerClassName;
186+
if (outerClassMatcher.find()) {
187+
outerClassName = outerClassMatcher.group(1);
188+
} else {
189+
// fallback: default outer class if not explicitly defined
190+
outerClassName = protoFileName.replace(".proto", "").replaceAll("[^A-Za-z0-9]", "");
191+
}
192+
return effectivePackage + "." + outerClassName;
193+
}
194+
118195
/**
119196
* Utility class that encapsulates <a href="https://en.wikipedia.org/wiki/ANSI_escape_code">ANSI escape sequences</a> for colors.
120197
*/

yaml-tests/src/main/resources/standard_tests_metadata.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
{
22
"records": {
33
"dependency": [
4-
"record_metadata_options.proto"
4+
"record_metadata_options.proto",
5+
"test_student.proto"
56
],
67
"message_type": [
78
{
@@ -32,6 +33,12 @@
3233
"name": "COL2",
3334
"number": 3,
3435
"type": "TYPE_INT64"
36+
},
37+
{
38+
"name": "student",
39+
"number": 4,
40+
"type": "TYPE_MESSAGE",
41+
"type_name": "com.apple.foundationdb.relational.yamltests.generated.teststudent.Student"
3542
}
3643
]
3744
}

yaml-tests/src/test/java/YamlIntegrationTests.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,13 +55,13 @@ public void standardTestsWithProto(YamlTest.Runner runner) throws Exception {
5555
}
5656

5757
@TestTemplate
58-
public void fieldIndexTestsProto(YamlTest.Runner runner) throws Exception {
59-
runner.runYamsql("field-index-tests-proto.yamsql");
58+
public void standardTestsWithMetaData(YamlTest.Runner runner) throws Exception {
59+
runner.runYamsql("standard-tests-metadata.yamsql");
6060
}
6161

6262
@TestTemplate
63-
public void standardTestsWithMetaData(YamlTest.Runner runner) throws Exception {
64-
runner.runYamsql("standard-tests-metadata.yamsql");
63+
public void fieldIndexTestsProto(YamlTest.Runner runner) throws Exception {
64+
runner.runYamsql("field-index-tests-proto.yamsql");
6565
}
6666

6767
@TestTemplate

yaml-tests/src/main/proto/standard_tests.proto renamed to yaml-tests/src/test/proto/standard_tests.proto

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,13 @@ package com.apple.foundationdb.relational.yamltests.generated.standardtests;
3131
option java_outer_classname = "StandardTestsProto";
3232

3333
import "record_metadata_options.proto";
34+
import "test_student.proto";
3435

3536
message T1 {
3637
int64 ID = 1 [(com.apple.foundationdb.record.field).primary_key = true];
3738
int64 COL1 = 2;
3839
int64 COL2 = 3;
40+
com.apple.foundationdb.relational.yamltests.generated.teststudent.Student student = 4;
3941
}
4042

4143
message RecordTypeUnion {
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* test_student.proto
3+
*
4+
* This source file is part of the FoundationDB open source project
5+
*
6+
* Copyright 2021-2024 Apple Inc. and the FoundationDB project authors
7+
*
8+
* Licensed under the Apache License, Version 2.0 (the "License");
9+
* you may not use this file except in compliance with the License.
10+
* You may obtain a copy of the License at
11+
*
12+
* http://www.apache.org/licenses/LICENSE-2.0
13+
*
14+
* Unless required by applicable law or agreed to in writing, software
15+
* distributed under the License is distributed on an "AS IS" BASIS,
16+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17+
* See the License for the specific language governing permissions and
18+
* limitations under the License.
19+
*/
20+
21+
syntax = "proto3";
22+
23+
// make sure to use this package naming convention:
24+
// com.apple.foundationdb.relational.yamltests.generated.<name_of_test_suite>
25+
// adding "generated" is important to exclude the generated Java file from Jacoco reports.
26+
// suffixing the namespace with your test name is important for segregating similarly-named
27+
// generated-Java-classes (such as RecordTypeUnion) into separate packages, otherwise you
28+
// get an error from `protoc`.
29+
package com.apple.foundationdb.relational.yamltests.generated.teststudent;
30+
31+
option java_outer_classname = "TestStudentProto";
32+
33+
message Student {
34+
int64 ID = 1;
35+
string name = 2;
36+
}

yaml-tests/src/test/resources/disabled-planner-rewrites/standard-tests-metadata.yamsql

Lines changed: 16 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -32,19 +32,19 @@ setup:
3232
connect: "jdbc:embed:/FRL/STANDARD_METADATA_YAML?schema=TEST"
3333
steps:
3434
- query: INSERT INTO T1
35-
VALUES (1, 10, 1),
36-
(2, 10, 2),
37-
(3, 10, 3),
38-
(4, 10, 4),
39-
(5, 10, 5),
40-
(6, 20, 6),
41-
(7, 20, 7),
42-
(8, 20, 8),
43-
(9, 20, 9),
44-
(10, 20, 10),
45-
(11, 20, 11),
46-
(12, 20, 12),
47-
(13, 20, 13)
35+
VALUES (1, 10, 1, (1, 'Albert')),
36+
(2, 10, 2, (2, 'Bob')),
37+
(3, 10, 3, (3, 'Charles')),
38+
(4, 10, 4, (4, 'Dan')),
39+
(5, 10, 5, (5, 'Evelyn')),
40+
(6, 20, 6, (6, 'Fiona')),
41+
(7, 20, 7, (7, 'George')),
42+
(8, 20, 8, (8, 'Harry')),
43+
(9, 20, 9, (9, 'Isabelle')),
44+
(10, 20, 10, (10, 'Jay')),
45+
(11, 20, 11, (11, 'Kelly')),
46+
(12, 20, 12, (12, 'Liam')),
47+
(13, 20, 13, (13, 'Monica'))
4848
---
4949
test_block:
5050
connect: "jdbc:embed:/FRL/STANDARD_METADATA_YAML?schema=TEST"
@@ -54,31 +54,17 @@ test_block:
5454
DISABLE_PLANNER_REWRITING: true
5555
tests:
5656
-
57-
- query: select * from (select * from (select * from T1) as x where ID = 5) as y;
57+
- query: select id, col1, col2 from (select * from (select * from T1) as x where ID = 5) as y;
5858
- result: [{ID: !l 5, !l 10, !l 5}]
5959
-
60-
- query: select * from (select * from (select * from T1) as x) as y where ID = 5;
60+
- query: select id, col1, col2 from (select * from (select * from T1) as x) as y where ID = 5;
6161
- result: [{ID: !l 5, !l 10, !l 5}]
6262
-
6363
- query: select count(*) from (select * from (select * from (select * from T1 where ID = 5) as x) as y) as z;
64-
- supported_version: 4.1.9.0
6564
- explain: "SCAN([EQUALS promote(@c23 AS LONG)]) | MAP (_ AS _0) | AGG (count_star(*) AS _0) | ON EMPTY NULL | MAP (coalesce_long(_._0._0, promote(0l AS LONG)) AS _0)"
6665
- result: [{!l 1}]
6766
-
68-
# Copy of above query to simulate force continuations mode, which does not work prior to 4.1.9.0 due to
69-
# https://github.com/FoundationDB/fdb-record-layer/issues/3096. Can remove once we no longer with testing mixed-mode
70-
# capabilities with versions older than 4.1.9.0
71-
- query: select count(*) from (select * from (select * from (select * from T1 where ID = 5) as x) as y) as z;
72-
- maxRows: 1
73-
- initialVersionLessThan: 4.1.9.0
74-
- result: [{!l 1}]
75-
- result: [{!l 0}]
76-
- result: [{!l 1}] # ad infinitum
77-
- initialVersionAtLeast: 4.1.9.0
78-
- result: [{!l 1}]
79-
- result: []
80-
-
81-
- query: select * from (select * from (select * from (select * from T1 where ID > 10) as x) as y) as z;
67+
- query: select id, col1, col2 from (select * from (select * from (select * from T1 where ID > 10) as x) as y) as z;
8268
- result: [{ID: !l 11, !l 20, !l 11}, {ID: !l 12, !l 20, !l 12}, {ID: !l 13, !l 20, !l 13}]
8369
---
8470
setup:

0 commit comments

Comments
 (0)