运行`go test`时出现”no such file or directory”错误。

huangapple go评论83阅读模式
英文:

go test causes no such file or directory

问题

我正在使用Go创建一个RESTful API,并使用JWT来保护我的应用程序。我正在使用ECDSA算法,因此我有私钥和公钥对。为了创建JWT令牌,我需要读取它们。

首先,这是我的项目结构:

.
├── Dockerfile
├── Makefile
├── config
│   └── config.go
├── config.json
├── data
│   ├── init.sql
│   ├── keys
│   │   ├── 256
│   │   │   ├── keys-256.md
│   │   │   ├── private-key.pem
│   │   │   └── public-key.pem
│   │   └── 512
│   │       ├── keys-512.md
│   │       ├── private-key.pem
│   │       └── public-key.pem
│   └── ....
├── go.mod
├── go.sum
├── handler
│   ├── auth.go
│   ├── auth_test.go
│   ├── healthcheck.go
│   └── healthcheck_test.go
├── main.go
└── security
    └── token
        ├── generator.go
        └── parser.go

这是我读取私钥文件的源文件,正如你所看到的,我在Go中使用了init函数,因此我将读取密钥文件一次,并在需要时重复使用它。

generator.go

package security

import (
	"crypto/ecdsa"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/golang-jwt/jwt"
    // ...
)

var privateKeyPath = "data/keys/512/private-key.pem"
var privateKey *ecdsa.PrivateKey

func init() {
    printWorkingDirectory()
	privateKey = getECDSAPrivateKey(readPrivateKeyFile())
}



func getECDSAPrivateKey(data []byte) *ecdsa.PrivateKey {
        ecdsaKey, err := jwt.ParseECPrivateKeyFromPEM(data);
	if  err != nil {
		log.Fatalf("Unable to parse ECDSA private key: %v", err)
	}
	return ecdsaKey
}

func readPrivateKeyFile() []byte {
	data, err := ioutil.ReadFile(privateKeyPath)
	if err != nil {
		log.Fatalf("Can not read private key file: %v", err)
	}
	return data;
}
func printWorkingDirectory() {
	mydir, err := os.Getwd()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Working directory: ", mydir)
}
//...

密钥路径是相对于项目的根目录的 var privateKeyPath = "data/keys/512/private-key.pem"

当我在根目录中运行 go run . 时,一切正常。

当我运行 go test ./... 时,Golang会创建一个临时目录,并在其中运行我的测试,这基本上会导致问题。以下是 go test ./... 的结果:

✗ go test -v ./...

Working directory is:  /var/folders/wk/ncyvbtdj3w57cr5j1v46x7dr39dz_l/T/go-build4211274972/b150
Initing db manger
2021/10/28 19:13:47 Can not read private key file: open data/keys/512/private-key.pem: no such file or directory
FAIL    mydomain/myprojectname/handler   1.274s

实际上,我是一名Java开发人员,对Go还不太熟悉。

在Java中,我们有 classpath,它可以解决这个问题。

我不想使用绝对路径,因为我有Dockerfile,如果我在本地计算机上使用绝对路径,那么在Docker容器中使用时会有问题。

我的问题是:

如何使用相对路径使其适用于 go rungo test 命令。

英文:

I'm creating a RESTFull API in Go and securing my application with JWT. I'm using ECDSA algorithm so I have private and public key pair. In order to create a JWT token I have to read them.

First of all this is my project structure:

.
├── Dockerfile
├── Makefile
├── config
│   └── config.go
├── config.json
├── data
│   ├── init.sql
│   ├── keys
│   │   ├── 256
│   │   │   ├── keys-256.md
│   │   │   ├── private-key.pem
│   │   │   └── public-key.pem
│   │   └── 512
│   │       ├── keys-512.md
│   │       ├── private-key.pem
│   │       └── public-key.pem
│   └── ....
├── go.mod
├── go.sum
├── handler
│   ├── auth.go
│   ├── auth_test.go
│   ├── healthcheck.go
│   └── healthcheck_test.go
│   
├── main.go
└── security
    └── token
        ├── generator.go
        └── parser.go

This is the source file where I read private key file as you can see I'm using init function in go so I'll read the key file once and use it every time I need it.

generator.go

package security

import (
	"crypto/ecdsa"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"strconv"
	"time"

	"github.com/golang-jwt/jwt"
    // ...
)

var privateKeyPath = "data/keys/512/private-key.pem"
var privateKey *ecdsa.PrivateKey

func init() {
    printWorkingDirectory()
	privateKey = getECDSAPrivateKey(readPrivateKeyFile())
}



func getECDSAPrivateKey(data []byte) *ecdsa.PrivateKey {
        ecdsaKey, err := jwt.ParseECPrivateKeyFromPEM(data);
	if  err != nil {
		log.Fatalf("Unable to parse ECDSA private key: %v", err)
	}
	return ecdsaKey
}

func readPrivateKeyFile() []byte {
	data, err := ioutil.ReadFile(privateKeyPath)
	if err != nil {
		log.Fatalf("Can not read private key file: %v", err)
	}
	return data;
}
func printWorkingDirectory() {
	mydir, err := os.Getwd()
	if err != nil {
		fmt.Println(err)
	}
	fmt.Println("Working directory: ", mydir)
}
//...

Key path is relative to root directory of project var privateKeyPath = "data/keys/512/private-key.pem"

When I run go run . in the root directory, everything fine.

When I run go test ./... Golang creates a temporary directory and runs my test in there basically this causes a problem.
Here is the result of go test ./...:

✗ go test -v ./...

Working directory is:  /var/folders/wk/ncyvbtdj3w57cr5j1v46x7dr39dz_l/T/go-build4211274972/b150
Initing db manger
2021/10/28 19:13:47 Can not read private key file: open data/keys/512/private-key.pem: no such file or directory
FAIL    mydomain/myprojectname/handler   1.274s

Actually I'm a Java Developer and I'm new in Go

Simply in Java we have classpath and it saves the day.

I don't want to use absolute path because I have Dockerfile and if I use absolute path in my local computer it will hurt me in docker container.

My question is:

How can I use a relative path which works with go run and go test commands.

答案1

得分: 1

你面临的问题是,当你运行go run或者运行你构建的应用程序时,工作目录是从你的环境继承的。但是当测试一个包时,工作目录始终是包目录。

一个快速的解决方案是,在你的security目录中将data目录复制一份作为测试装置,这样你也可以在测试中使用特定的密钥。

一个更好的解决方案是思考如何在生产环境中加载密钥。你的security包中的init()函数非常不灵活,因为:

  1. 在生产环境中,你的密钥必须位于相对于工作目录的特定位置。
  2. 你无法影响测试中init()函数的行为,因为init()函数总是在测试开始之前运行。

我的建议是,不要使用init()函数,而是在你从main实例化security包中的类/类时,将字面上的密钥或密钥的路径传递给它们。这样,在生产环境中,你的密钥可以位于任何位置,而你的测试可以指定使用源代码树中与该包目录相关的密钥。

英文:

The problem you are facing is because when you run go run, or for that matter when you run your built application, the working directory is inherited from your environment. But when a package is tested, the working directory is always the package directory.

One quick solution would be to have a copy of your data directory inside your security directory as a test fixture, this would also allow you to use a specific key for testing.

A better solution is to think about how you will load your key in production. This init() function in your security package is quite inflexible because:

  1. In production, your key must be in a specific location relative to the working directory only.
  2. You cannot influence the behaviour of the init() function in tests because init() is always run before tests start.

My recommendation would be that rather than using init(), you pass either the literal key, or a path to the key into class/classes in the security package from main when you instantiate them. This way your key can be located anywhere when in production and your tests can be directed to use a key in the source tree relative to that package's directory.

huangapple
  • 本文由 发表于 2021年10月29日 00:29:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/69757788.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定