diff --git a/go.mod b/go.mod index ec9f8a7ce4..8091d99cfc 100644 --- a/go.mod +++ b/go.mod @@ -55,7 +55,6 @@ require ( github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 github.com/hashicorp/golang-lru v0.5.1 github.com/imdario/mergo v0.3.16 - github.com/integralist/go-findroot v0.0.0-20160518114804-ac90681525dc github.com/jarcoal/httpmock v1.2.0 github.com/jcmturner/gokrb5/v8 v8.4.4 github.com/jmoiron/sqlx v1.3.3 diff --git a/go.sum b/go.sum index 1cabd51f1c..6dd200dd67 100644 --- a/go.sum +++ b/go.sum @@ -608,8 +608,6 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/influxdata/tdigest v0.0.1 h1:XpFptwYmnEKUqmkcDjrzffswZ3nvNeevbUSLPP/ZzIY= github.com/influxdata/tdigest v0.0.1/go.mod h1:Z0kXnxzbTC2qrx4NaIzYkE1k66+6oEDQTvL95hQFh5Y= -github.com/integralist/go-findroot v0.0.0-20160518114804-ac90681525dc h1:4IZpk3M4m6ypx0IlRoEyEyY1gAdicWLMQ0NcG/gBnnA= -github.com/integralist/go-findroot v0.0.0-20160518114804-ac90681525dc/go.mod h1:UlaC6ndby46IJz9m/03cZPKKkR9ykeIVBBDE3UDBdJk= github.com/jarcoal/httpmock v1.2.0 h1:gSvTxxFR/MEMfsGrvRbdfpRUMBStovlSRLw0Ep1bwwc= github.com/jarcoal/httpmock v1.2.0/go.mod h1:oCoTsnAz4+UoOUIf5lJOWV2QQIW5UoeUI6aM2YnWAZk= github.com/jawher/mow.cli v1.0.4/go.mod h1:5hQj2V8g+qYmLUVWqu4Wuja1pI57M83EChYLVZ0sMKk= diff --git a/tests/mq_protocol_tests/framework/avro/kafka_docker_env.go b/tests/mq_protocol_tests/framework/avro/kafka_docker_env.go index ea5006439f..5c676a243b 100644 --- a/tests/mq_protocol_tests/framework/avro/kafka_docker_env.go +++ b/tests/mq_protocol_tests/framework/avro/kafka_docker_env.go @@ -17,9 +17,7 @@ import ( "encoding/json" "io" "net/http" - "path" - "github.com/integralist/go-findroot/find" "github.com/pingcap/errors" "github.com/pingcap/log" "github.com/pingcap/tiflow/tests/mq_protocol_tests/framework" @@ -75,11 +73,11 @@ func NewKafkaDockerEnv(dockerComposeFile string) *KafkaDockerEnv { var file string if dockerComposeFile == "" { - st, err := find.Repo() + resolvedFile, err := framework.ResolveRepoPath(dockerComposeFilePath) if err != nil { - log.Fatal("Could not find git repo root", zap.Error(err)) + log.Fatal("Could not find repo-local docker-compose file", zap.Error(err)) } - file = path.Join(st.Path, dockerComposeFilePath) + file = resolvedFile } else { file = dockerComposeFile } diff --git a/tests/mq_protocol_tests/framework/canal/kafka_docker_env.go b/tests/mq_protocol_tests/framework/canal/kafka_docker_env.go index 14e300c9e2..dfff567f8a 100644 --- a/tests/mq_protocol_tests/framework/canal/kafka_docker_env.go +++ b/tests/mq_protocol_tests/framework/canal/kafka_docker_env.go @@ -18,7 +18,6 @@ import ( "io" "net/http" - "github.com/integralist/go-findroot/find" "github.com/pingcap/errors" "github.com/pingcap/log" "github.com/pingcap/tiflow/tests/mq_protocol_tests/framework" @@ -51,11 +50,11 @@ func NewKafkaDockerEnv(dockerComposeFile string) *KafkaDockerEnv { } var file string if dockerComposeFile == "" { - st, err := find.Repo() + resolvedFile, err := framework.ResolveRepoPath(dockerComposeFilePath) if err != nil { - log.Fatal("Could not find git repo root", zap.Error(err)) + log.Fatal("Could not find repo-local docker-compose file", zap.Error(err)) } - file = st.Path + dockerComposeFilePath + file = resolvedFile } else { file = dockerComposeFile } diff --git a/tests/mq_protocol_tests/framework/docker_compose_op.go b/tests/mq_protocol_tests/framework/docker_compose_op.go index b1bf9ad162..becf65d02d 100644 --- a/tests/mq_protocol_tests/framework/docker_compose_op.go +++ b/tests/mq_protocol_tests/framework/docker_compose_op.go @@ -20,7 +20,6 @@ import ( "os" "os/exec" - "github.com/integralist/go-findroot/find" "github.com/pingcap/errors" "github.com/pingcap/log" cerrors "github.com/pingcap/tiflow/pkg/errors" @@ -143,11 +142,11 @@ func execInController(controller, shellCmd string) ([]byte, error) { func (d *DockerComposeOperator) DumpStdout() error { log.Info("Dumping container logs") cmd := exec.Command("docker-compose", "-f", d.FileName, "logs", "-t") - st, err := find.Repo() + stdoutPath, err := ResolveRepoPath("/deployments/ticdc/docker-compose/logs/stdout.log") if err != nil { - log.Fatal("Could not find git repo root", zap.Error(err)) + log.Fatal("Could not find repo-local docker-compose logs directory", zap.Error(err)) } - f, err := os.Create(st.Path + "/deployments/ticdc/docker-compose/logs/stdout.log") + f, err := os.Create(stdoutPath) if err != nil { return errors.AddStack(err) } diff --git a/tests/mq_protocol_tests/framework/docker_compose_op_test.go b/tests/mq_protocol_tests/framework/docker_compose_op_test.go index 4ebad32587..7dd4001290 100644 --- a/tests/mq_protocol_tests/framework/docker_compose_op_test.go +++ b/tests/mq_protocol_tests/framework/docker_compose_op_test.go @@ -16,16 +16,17 @@ package framework import ( "testing" - "github.com/integralist/go-findroot/find" "github.com/stretchr/testify/assert" ) func TestDockerComposeOperator_SetupTearDown(t *testing.T) { - st, err := find.Repo() + // This integration-style test verifies the operator can boot and tear down + // the avro compose stack after resolving its compose file from the repo tree. + fileName, err := ResolveRepoPath(DockerComposeFilePathPrefix + "docker-compose-avro.yml") assert.NoError(t, err) d := &DockerComposeOperator{ - FileName: st.Path + "/docker-compose-avro.yml", + FileName: fileName, Controller: "controller0", } d.Setup() diff --git a/tests/mq_protocol_tests/framework/mysql/docker_env.go b/tests/mq_protocol_tests/framework/mysql/docker_env.go index 3e0e4047d1..22ec292005 100644 --- a/tests/mq_protocol_tests/framework/mysql/docker_env.go +++ b/tests/mq_protocol_tests/framework/mysql/docker_env.go @@ -16,7 +16,6 @@ package mysql import ( "database/sql" - "github.com/integralist/go-findroot/find" "github.com/pingcap/errors" "github.com/pingcap/log" "github.com/pingcap/tiflow/tests/mq_protocol_tests/framework" @@ -46,11 +45,11 @@ func NewDockerEnv(dockerComposeFile string) *DockerEnv { } var file string if dockerComposeFile == "" { - st, err := find.Repo() + resolvedFile, err := framework.ResolveRepoPath(dockerComposeFilePath) if err != nil { - log.Fatal("Could not find git repo root", zap.Error(err)) + log.Fatal("Could not find repo-local docker-compose file", zap.Error(err)) } - file = st.Path + dockerComposeFilePath + file = resolvedFile } else { file = dockerComposeFile } diff --git a/tests/mq_protocol_tests/framework/repo_path.go b/tests/mq_protocol_tests/framework/repo_path.go new file mode 100644 index 0000000000..51cc839de3 --- /dev/null +++ b/tests/mq_protocol_tests/framework/repo_path.go @@ -0,0 +1,68 @@ +// Copyright 2026 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package framework + +import ( + "fmt" + "os" + "path/filepath" + "runtime" + "strings" +) + +// ResolveRepoPath returns an absolute path under the tiflow repository +// without relying on git metadata. This keeps repo-local test assets +// discoverable from symlinked checkouts and git worktrees. +func ResolveRepoPath(rel string) (string, error) { + normalizedRel := filepath.FromSlash(strings.TrimPrefix(rel, "/")) + for _, base := range repoPathCandidates() { + dir := base + for dir != "." && dir != string(filepath.Separator) { + if isRepoRoot(dir) { + return filepath.Join(dir, normalizedRel), nil + } + parent := filepath.Dir(dir) + if parent == dir { + break + } + dir = parent + } + } + + return "", fmt.Errorf("cannot resolve repo path for %q", rel) +} + +func repoPathCandidates() []string { + var candidates []string + if _, file, _, ok := runtime.Caller(0); ok { + candidates = append(candidates, filepath.Dir(file)) + } + if wd, err := os.Getwd(); err == nil { + candidates = append(candidates, wd) + } + return candidates +} + +func isRepoRoot(dir string) bool { + for _, marker := range []string{ + filepath.Join(dir, "go.mod"), + filepath.Join(dir, "deployments", "ticdc", "docker-compose"), + filepath.Join(dir, "tests", "mq_protocol_tests", "framework"), + } { + if _, err := os.Stat(marker); err != nil { + return false + } + } + return true +} diff --git a/tests/mq_protocol_tests/framework/repo_path_test.go b/tests/mq_protocol_tests/framework/repo_path_test.go new file mode 100644 index 0000000000..43ac7ab4dd --- /dev/null +++ b/tests/mq_protocol_tests/framework/repo_path_test.go @@ -0,0 +1,32 @@ +// Copyright 2026 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// See the License for the specific language governing permissions and +// limitations under the License. + +package framework + +import ( + "os" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestResolveRepoPath(t *testing.T) { + // This regression test verifies repo-local compose assets can be found + // without invoking git, so worktree and symlinked checkouts stay stable. + composePath, err := ResolveRepoPath(DockerComposeFilePathPrefix + "docker-compose-avro.yml") + require.NoError(t, err) + + info, statErr := os.Stat(composePath) + require.NoError(t, statErr) + require.False(t, info.IsDir()) +}