open conf/test/conf.yaml: no such file or directory
https://github.com/cloudwego/cwgo/issues/120
https://github.com/cloudwego/cwgo/issues/29
In the code generated using Kitex, unit testing returns an error as shown in the title. The reason for this error is that biz/service
the unit testing method also requires complete framework testing instead of independent unit testing, just like spring boot needs to load the entire spring environment when performing unit testing.
See the obtained conf.yaml
source code:
func initConf() {
prefix := "conf"
confFileRelPath := filepath.Join(prefix, filepath.Join(GetEnv(), "conf.yaml"))
content, err := ioutil.ReadFile(confFileRelPath)
if err != nil {
panic(err)
}
conf = new(Config)
err = yaml.Unmarshal(content, conf)
if err != nil {
hlog.Error("parse yaml error - %v", err)
panic(err)
}
if err := validator.Validate(conf); err != nil {
hlog.Error("validate config error - %v", err)
panic(err)
}
conf.Env = GetEnv()
pretty.Printf("%+v\n", conf)
}
In the above code, GetEnv()
the intermediate path of the yaml configuration file is obtained through the method. The method body is as follows:
func GetEnv() string {
e := os.Getenv("GO_ENV")
if len(e) == 0 {
return "test"
}
return e
}
The above method is to obtain the directory of go env and has nothing to do with this project and needs to be modified. Obviously, you need to start the environment here, such as
dev
,online
,test
etc. This will be discussed in another article. Let’s start the project here.
GetEnv()
Just write one firsttest
and write the configuration in the conf file in that directory.
Then after configuring according to the above, it should become as follows:
prefix := "conf"
confFileRelPath := filepath.Join(prefix, filepath.Join("test", "conf.yaml"))
}
The path synthesized when calling this method is conf/test/conf.yaml
so obviously it cannot be found.conf
There are no structures outside the directory。
At this time, you only need to conf.yaml
set the search location to an absolute path, so that no matter which file is used, the configuration file will be queried from the absolute directory, and no error will be reported.
Go language provides os.Getwd()
methods to obtain absolute paths.
It should be noted that this method is dynamic. It does not obtain the directory where the method is located but the directory where the file that calls the method is located. Therefore this method is not possible because the path should change with the location of the method call.
So use filepath.Abs()
the method, which is to get the absolute path of a file. Here you can get the absolute path of conf and set conf.yaml
the path.
.
refers to the current directory.
But this doesn't work, because the paths obtained in go are all dynamic, and the encapsulation of os.GetWd()
or filepath.Abs()
is formal, and will only be actually called when the value is actually assigned. as follows
Called in the test environment to become the test environment address
The main function call becomes the main function address
So how to solve it?
The editor parses the path until the root path is obtained, and then configures the configuration file path through the root path. In this way, no matter which directory is called, the root path is first obtained and then the configuration file path is configured.
My thoughts are:
- Get the absolute path of the conf caller
os.Getwd()
- Since go cannot obtain the absolute path of the entire project, it is necessary to parse the path to obtain the absolute path of the project.
- Use to
filepath.Dir(currentDir)
get the upper level directory- Use the name of the last directory
filepath.Base(currentDir)
obtained3
and compare with the project root- Equality indicates that the path is an absolute path.
- By
1,2,3,4,5
calling it in any directory, no matter how the absolute address changes, you can get the project root directory.- Root directory (the comparison of the project name can be obtained from the configuration file or the main function, don’t think of me hard-coding it in the code) [Optional]
Then the modified conf initConf
code is as follows:
func initConf() {
// 主函数为最外层函数,路径为根地址,其它路径调用只可能在其子目录下
// 获取调用者路径
fakepath,err := os.Getwd()
if err != nil{
log.Fatal(errors.New("获取调用者路径失败"))
panic(err)
}
// 循环比较路径的最后一位是否为根目录
// 如果是根目录就停止,循环超20次自动停止(没有目录有这么多层)
i := 0
for {
i++
if filepath.Base(fakepath) == "food_platform" {
// 这里的food_platform是最原始根目录路径名,也就是项目最外层文件名
break
}
fakepath = filepath.Dir(fakepath)
if i >= 20 {
log.Fatal(errors.New("获取调用者路径失败"))
panic(err)
}
}
prefix := fakepath + "/cms_commodity/api/conf"
// 获取配置文件路径
confFileRelPath := filepath.Join(prefix, filepath.Join("test","conf.yaml"))
content, err := ioutil.ReadFile(confFileRelPath)
if err != nil {
panic(err)
}
conf = new(Config)
err = yaml.Unmarshal(content, conf)
if err != nil {
klog.Error("parse yaml error - %v", err)
panic(err)
}
if err := validator.Validate(conf); err != nil {
klog.Error("validate config error - %v", err)
panic(err)
}
conf.Env = GetEnv()
pretty.Printf("%+v\n", conf)
}
There are three places above that need to be modified based on actual conditions:
/test
The static one written here can be obtained from the command line usingos.Args
the andflag
library.- The condition for if judgment
food_platform
is the project name, the name of the top-level root project. This needs to be modified based on the actual situation. Of course, it can also be written in the configuration file or obtained from the command line./cms_commodity/api/conf
This is written in the code and is the path from the root directory to the configuration file. This requires that the structure of the project cannot be changed.