Skip to content

Commit 9aa41fd

Browse files
authored
HDDS-12574. Add script to find modules by test classes (#8062)
1 parent 5e28acb commit 9aa41fd

File tree

4 files changed

+340
-0
lines changed

4 files changed

+340
-0
lines changed
+239
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
1+
#!/usr/bin/env bats
2+
# Licensed to the Apache Software Foundation (ASF) under one or more
3+
# contributor license agreements. See the NOTICE file distributed with
4+
# this work for additional information regarding copyright ownership.
5+
# The ASF licenses this file to You under the Apache License, Version 2.0
6+
# (the "License"); you may not use this file except in compliance with
7+
# the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing, software
12+
# distributed under the License is distributed on an "AS IS" BASIS,
13+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
# See the License for the specific language governing permissions and
15+
# limitations under the License.
16+
17+
load find_test_class_project.sh
18+
19+
setup() {
20+
# Create a temporary directory for test files
21+
TEST_DIR=$(mktemp -d)
22+
mkdir -p "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test"
23+
mkdir -p "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test"
24+
touch "${TEST_DIR}/project1/pom.xml"
25+
touch "${TEST_DIR}/project2/pom.xml"
26+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/TestClass1.java"
27+
touch "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/TestClass2.java"
28+
29+
ORIG_DIR=$(pwd)
30+
cd "${TEST_DIR}"
31+
}
32+
33+
teardown() {
34+
cd "${ORIG_DIR}"
35+
rm -rf "${TEST_DIR}"
36+
}
37+
38+
# Test the find_project_paths_for_test_class function
39+
40+
@test "find project for simple class name" {
41+
result=$(find_project_paths_for_test_class "TestClass1" 2>/dev/null)
42+
43+
[ "$result" = "./project1" ]
44+
}
45+
46+
@test "find project for class with package" {
47+
result=$(find_project_paths_for_test_class "org.apache.ozone.test.TestClass2" 2>/dev/null)
48+
49+
[ "$result" = "./project2" ]
50+
}
51+
52+
@test "find project for wildcard class" {
53+
result=$(find_project_paths_for_test_class "TestClass*" 2>/dev/null)
54+
expected=$(echo -e "./project1\n./project2")
55+
56+
[ "$result" = "$expected" ]
57+
}
58+
59+
@test "no project for non-existent class" {
60+
result=$(find_project_paths_for_test_class "NonExistentClass" 2>/dev/null)
61+
62+
[ -z "$result" ]
63+
}
64+
65+
@test "skip abstract classes" {
66+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/AbstractTestClass.java"
67+
68+
result=$(find_project_paths_for_test_class "AbstractTestClass" 2>/dev/null)
69+
70+
[ -z "$result" ]
71+
}
72+
73+
@test "empty class name returns nothing" {
74+
result=$(find_project_paths_for_test_class "" 2>/dev/null)
75+
76+
[ -z "$result" ]
77+
}
78+
79+
@test "multiple projects with same test class name" {
80+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/CommonTest.java"
81+
touch "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/CommonTest.java"
82+
83+
result=$(find_project_paths_for_test_class "CommonTest" 2>/dev/null)
84+
85+
expected=$(echo -e "./project1\n./project2")
86+
[ "$result" = "$expected" ]
87+
}
88+
89+
@test "project without pom.xml is ignored" {
90+
mkdir -p "${TEST_DIR}/project3/src/test/java/org/apache/ozone/test"
91+
touch "${TEST_DIR}/project3/src/test/java/org/apache/ozone/test/TestClass3.java"
92+
93+
result=$(find_project_paths_for_test_class "TestClass3" 2>/dev/null)
94+
95+
[ -z "$result" ]
96+
}
97+
98+
@test "partial package name search" {
99+
result=$(find_project_paths_for_test_class "ozone.test.TestClass2" 2>/dev/null)
100+
101+
[ "$result" = "./project2" ]
102+
}
103+
104+
@test "test class in non-standard test directory" {
105+
mkdir -p "${TEST_DIR}/project1/src/test/scala/org/apache/ozone/test"
106+
touch "${TEST_DIR}/project1/src/test/scala/org/apache/ozone/test/ScalaTest.java"
107+
108+
result=$(find_project_paths_for_test_class "ScalaTest" 2>/dev/null)
109+
110+
[ "$result" = "./project1" ]
111+
}
112+
113+
@test "case sensitivity in class name" {
114+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/MixedCaseTest.java"
115+
116+
result=$(find_project_paths_for_test_class "mixedcasetest" 2>/dev/null)
117+
118+
[ -z "$result" ]
119+
}
120+
121+
@test "nested project structure" {
122+
mkdir -p "${TEST_DIR}/parent/child/src/test/java/org/apache/ozone/test"
123+
touch "${TEST_DIR}/parent/child/pom.xml"
124+
touch "${TEST_DIR}/parent/child/src/test/java/org/apache/ozone/test/NestedTest.java"
125+
126+
result=$(find_project_paths_for_test_class "NestedTest" 2>/dev/null)
127+
128+
[ "$result" = "./parent/child" ]
129+
}
130+
131+
@test "test class with numeric suffix" {
132+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/Test1.java"
133+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/Test2.java"
134+
touch "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/Test3.java"
135+
136+
result=$(find_project_paths_for_test_class "Test[1-2]" 2>/dev/null)
137+
138+
[ "$result" = "./project1" ]
139+
}
140+
141+
@test "multiple test classes matching pattern" {
142+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/TestA.java"
143+
touch "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/TestB.java"
144+
touch "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/TestC.java"
145+
146+
result=$(find_project_paths_for_test_class "Test[A-C]" 2>/dev/null)
147+
148+
expected=$(echo -e "./project1\n./project2")
149+
[ "$result" = "$expected" ]
150+
}
151+
152+
@test "test class in multiple package levels" {
153+
mkdir -p "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/deep/nested/pkg"
154+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/deep/nested/pkg/DeepTest.java"
155+
156+
result=$(find_project_paths_for_test_class "org.apache.ozone.test.deep.nested.pkg.DeepTest" 2>/dev/null)
157+
158+
[ "$result" = "./project1" ]
159+
}
160+
161+
@test "test class with same name in different packages" {
162+
mkdir -p "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/pkg1"
163+
mkdir -p "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/pkg2"
164+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/pkg1/SameNameTest.java"
165+
touch "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/pkg2/SameNameTest.java"
166+
167+
result=$(find_project_paths_for_test_class "SameNameTest" 2>/dev/null)
168+
169+
expected=$(echo -e "./project1\n./project2")
170+
[ "$result" = "$expected" ]
171+
}
172+
173+
@test "test class with package wildcard" {
174+
mkdir -p "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/pkg1"
175+
mkdir -p "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/pkg2"
176+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/pkg1/WildcardTest.java"
177+
touch "${TEST_DIR}/project2/src/test/java/org/apache/ozone/test/pkg2/WildcardTest.java"
178+
179+
result=$(find_project_paths_for_test_class "org.apache.ozone.test.pkg*.WildcardTest" 2>/dev/null)
180+
181+
expected=$(echo -e "./project1\n./project2")
182+
[ "$result" = "$expected" ]
183+
}
184+
185+
@test "test class with exact package match" {
186+
mkdir -p "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/exact"
187+
mkdir -p "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/exactmatch"
188+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/exact/ExactTest.java"
189+
touch "${TEST_DIR}/project1/src/test/java/org/apache/ozone/test/exactmatch/ExactTest.java"
190+
result=$(find_project_paths_for_test_class "org.apache.ozone.test.exact.ExactTest" 2>/dev/null)
191+
192+
[ "$result" = "./project1" ]
193+
}
194+
195+
@test "test class with trailing whitespace" {
196+
result=$(find_project_paths_for_test_class "TestClass1 " 2>/dev/null)
197+
198+
[ "$result" = "./project1" ]
199+
}
200+
201+
@test "test class project with trailing whitespace" {
202+
result=$(find_project_paths_for_test_class "apache.ozone.test.TestClass1 " 2>/dev/null)
203+
204+
[ "$result" = "./project1" ]
205+
}
206+
207+
@test "test class with leading whitespace" {
208+
result=$(find_project_paths_for_test_class " TestClass1" 2>/dev/null)
209+
210+
[ "$result" = "./project1" ]
211+
}
212+
213+
@test "test class with partial package and wildcard" {
214+
result=$(find_project_paths_for_test_class "apache.*.TestClass*" 2>/dev/null)
215+
216+
expected=$(echo -e "./project1\n./project2")
217+
[ "$result" = "$expected" ]
218+
}
219+
220+
# Test the build_maven_project_list function
221+
222+
@test "build maven project list with empty project paths" {
223+
result=$(build_maven_project_list "")
224+
225+
[ "$result" = "" ]
226+
}
227+
228+
@test "build maven project list with one project path" {
229+
result=$(build_maven_project_list "./project1")
230+
231+
[ "$result" = "-pl ./project1" ]
232+
}
233+
234+
@test "build maven project list with multiple project paths" {
235+
local project_paths=$(echo -e "./project1\n./project2")
236+
result=$(build_maven_project_list "$project_paths")
237+
238+
[ "$result" = "-pl ./project1,./project2" ]
239+
}
+98
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/usr/bin/env bash
2+
3+
# Licensed to the Apache Software Foundation (ASF) under one or more
4+
# contributor license agreements. See the NOTICE file distributed with
5+
# this work for additional information regarding copyright ownership.
6+
# The ASF licenses this file to You under the Apache License, Version 2.0
7+
# (the "License"); you may not use this file except in compliance with
8+
# the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
18+
# Function to find project paths for a given test class
19+
find_project_paths_for_test_class() {
20+
local test_class="$1"
21+
22+
if [[ -z "${test_class}" ]] || [[ "${test_class}" == "Abstract"* ]]; then
23+
return
24+
fi
25+
26+
echo "Finding project for test class: ${test_class}" >&2
27+
28+
# Trim test_class of whitespace
29+
local base_class_name=$(echo "${test_class}" | xargs)
30+
31+
# If the base name is empty after removing wildcards, use a reasonable default
32+
if [[ -z "${base_class_name}" ]]; then
33+
echo "Test class name contains only wildcards, searching in all test directories" >&2
34+
return
35+
fi
36+
37+
echo "Searching for files matching base name: ${base_class_name}" >&2
38+
39+
# Find all projects containing matching test classes - use a more flexible search approach
40+
# First try direct filename search
41+
local test_files=($(find . -path "*/src/test/*" -name "${base_class_name}.java" | sort -u))
42+
43+
# If no files found and the class name contains dots (package notation), try searching by path
44+
if [[ ${#test_files[@]} -eq 0 && "${base_class_name}" == *"."* ]]; then
45+
# Convert base class to path format
46+
local test_class_path="${base_class_name//./\/}.java"
47+
echo "No files found with direct name search, trying path-based search" >&2
48+
echo "TEST_CLASS_PATH pattern: ${test_class_path}" >&2
49+
50+
# Search by path pattern
51+
test_files=($(find . -path "*/src/test/*/${test_class_path%.*}*.java" | sort -u))
52+
fi
53+
54+
echo "Found ${#test_files[@]} matching test file(s)" >&2
55+
56+
if [[ ${#test_files[@]} -gt 0 ]]; then
57+
# Extract project paths (up to the src/test directory)
58+
local project_paths=()
59+
for test_file in "${test_files[@]}"; do
60+
echo "TEST_FILE: ${test_file}" >&2
61+
local project_path=$(dirname "${test_file}" | sed -e 's|/src/test.*||')
62+
if [[ -f "${project_path}/pom.xml" ]]; then
63+
echo "Found test in project: ${project_path}" >&2
64+
project_paths+=("${project_path}")
65+
fi
66+
done
67+
68+
printf '%s\n' "${project_paths[@]}" | sort -u
69+
else
70+
echo "Could not find project for test class pattern: ${test_class}" >&2
71+
fi
72+
}
73+
74+
# Takes a project list which is the output of `find_project_paths_for_test_class`
75+
# and returns a string that can use for maven -pl option, eg. "./project1\n./project2" -> "-pl ./project1,./project2"
76+
build_maven_project_list() {
77+
local project_paths="$1"
78+
if [[ -z "${project_paths}" ]]; then
79+
echo ""
80+
return
81+
fi
82+
83+
local comma_separated=$(echo "${project_paths}" | tr '\n' ',')
84+
comma_separated="${comma_separated%,}"
85+
echo "-pl ${comma_separated}"
86+
}
87+
88+
# If option get-pl set, write the maven -pl option value to stdout
89+
# otherwise, write the project paths to stdout
90+
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
91+
if [[ "$1" == "--get-pl" ]]; then
92+
shift
93+
project_paths=$(find_project_paths_for_test_class "$@")
94+
build_maven_project_list "${project_paths}"
95+
else
96+
find_project_paths_for_test_class "$@"
97+
fi
98+
fi

dev-support/ci/selective_ci_checks.sh

+2
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ function run_all_tests_if_environment_files_changed() {
199199
)
200200
local ignore_array=(
201201
"^dev-support/ci/pr_title_check"
202+
"^dev-support/ci/find_test_class_project"
202203
)
203204
filter_changed_files
204205

@@ -478,6 +479,7 @@ function get_count_misc_files() {
478479
start_end::group_start "Count misc. files"
479480
local pattern_array=(
480481
"^dev-support/ci/pr_title_check"
482+
"^dev-support/ci/find_test_class_project"
481483
"^.github"
482484
"^hadoop-hdds/dev-support/checkstyle"
483485
"^hadoop-ozone/dev-support/checks"

hadoop-ozone/dev-support/checks/bats.sh

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ find * \( \
3434
-path '*/src/test/shell/*' -name '*.bats' \
3535
-or -path dev-support/ci/selective_ci_checks.bats \
3636
-or -path dev-support/ci/pr_title_check.bats \
37+
-or -path dev-support/ci/find_test_class_project.bats \
3738
\) -print0 \
3839
| xargs -0 -n1 bats --formatter tap \
3940
| tee -a "${REPORT_DIR}/output.log"

0 commit comments

Comments
 (0)