Running go tests from root project folder - go

I have to take over a go project from a colleague and I've never touched Go before and it doesn't have tests so I've started to add them but I cannot run them.
The go command for running tests is go test but it doesn't seem to run at the root level.
My project structure is:
/project/main.go
/project/engine/*.go
/project/api/*.go
If I cd into either engine or api, and run go test it works but not in the root folder.
cd /project
go test
? /project [no test files]
Is there anyway to run all tests from the root?

You can use the ... (ellipsis) operator to test all subpackages of the current package. Like that: go test ./....
There are other solutions that you might want to try later if you do something more sophisticated, like using the list tool. Like that (for example): go test $(go list ./... | grep [regex]). That's useful to exclude the vendor directory from your tests.
Another thing you may want to know about is the gt command that can be found here https://godoc.org/rsc.io/gt and add caching to the go test command.
Finally, don't hesitate to read https://blog.golang.org/cover to get informations about code-coverage analysis in golang.

I find this irritating that go test ./... when run from project root will actually run from pkg/pkg_name/ folder. There is a way you can set the tests to project root by setting cwd in the init() helper function.
I found the solution here You could try the following snippet in your _file:
func init() {
_, filename, _, _ := runtime.Caller(0)
dir := path.Join(path.Dir(filename), "../..") // change to suit test file location
err := os.Chdir(dir)
if err != nil {
panic(err)
}
}
This snippet above works for my tests in pkg/$name/$name_test.go.

just running sudo go test -v ./... will probably fail because you probably do not have your root environment setup for GO just like you set the non-root env.
You can go and reset everything in the root, or do this easy step:
sudo -E go test -v ./...
This will run as root but keep your env settings.

Related

How do you call a Go function in VSCode?

I have VSCode and the Go plugin installed. I am trying to call this function:
package main
import "fmt"
func printHello() {
fmt.Println("hello world")
}
First, I opened the VSCode Command Palette and chose Go: Test file, which threw a No tests found. Current file is not a test file. error.
Then I opened the VSCode Command Palette and chose Go: Test function at cursor - this threw the same error.
Then I created a sibling file with a _test.go naming convention:
package main
import (
"testing"
)
func TestHello(t *testing.T) {
msg, err := printHello()
}
This threw a build error: c:\path\to\my_test.go:8:18: main() used as value.
Then I added a simple return statement, which threw the following error:
go: cannot find main module, but found .git/config in c:\path\to\my_folder
to create a module there, run:
cd ..\.. && go mod init
I right-clicked the function name itself and chose the Go: Debug Test at Cursor function, and the Go: Generate unit tests for function option, which in-turn prompted me to install several other VSCode plugins, and prompted me to upgrade Go itself. The previous two Command Palette options started to fail with ENOENT errors, so I restarted VSCode, and got a new test function. I opened up the VSCode Debug Console but it wouldn't let me start a session there.
I right-clicked the parent folder and chose the Open in Integrated Terminal option, which started a WSL session - cd ..\.. && go mod init threw errors related to GOPATH:
me#COMPUTER:/mnt/c/path/to/my_folder$ go mod init
-bash: /c/go/bin/go.exe: No such file or directory
I tried determining what the WSL GOPATH was pointing to via Go: Show current GOPATH - it actually turned out that both the WSL and VSCode GOPATHs were incorrect.
I opened up a normal Command Prompt which had the correct GOPATH and I fired off go mod init which errored out (the previous guidance from VSCode was incorrect):
go: cannot determine module path for source directory C:\path\to\my_folder (outside GOPATH, module path must be specified)
Example usage:
'go mod init example.com/m' to initialize a v0 or v1 module
'go mod init example.com/m/v2' to initialize a v2 module
Run 'go help mod init' for more information.
I decided on a v2 Go module initialization (I don't know why one would opt for v0 or v1), which created a go.mod in the root directory of my project, but now I am seeing the following package-related errors:
gopls requires a module at the root of your workspace.
You can work with multiple modules by opening each one as a workspace folder.
Improvements to this workflow will be coming soon, and you can learn more here:
https://github.com/golang/tools/blob/master/gopls/doc/workspace.md.
How do I call a Go function in VSCode?
The answer turns out to be:
You need to create a *_test.go unit test harness and install more adjacent VSCode plugins.
You need to run go mod init blah somewhere outside of VSCode. blah is the name of your module. VSCode is unreliable with respect to the GOPATH.
There is a gotcha here where if you run go mod init main, this is valid but VSCode will throw misleading errors later on (see https://appliedgo.net/testmain/). You have to name it something else.
You need to re-open the VSCode workspace in a way such that go.mod is in the root of the workspace, or else VSCode runs into relative pathing errors.

How to read env files by runnnig Go application?

I have an application which is developed in Go. I have a config.env file and get some critical variables from it by using the godotenv library. Here is the code:
func InitializeEnvVars() error {
err := godotenv.Load("./config.env")
return err
}
When I build my project with go build . on MacOS and I want to run the application, the app gives an error about reading the .env file:
2021/03/07 17:42:21 [ERROR]: Error loading .env file
But when I run my app with go run main.go command, everything works well.
How can I solve this problem?
As per the comments godotenv.Load("./config.env") will attempt to load the .env file from the working directory. The method used to set the working directory depends upon how you are starting the application (i.e. command line/gui).
If you would prefer that the .env be loaded from the folder holding the executable then try the following (note that there are some caveats).
ex, err := os.Executable()
if err != nil {
panic(fmt.Sprintf("Failed to get executable path: %s", err))
}
envPath := filepath.Join(filepath.Dir(ex), ".env")
err = godotenv.Load(envPath)
You can find the solution below step by step:
Create a folder like cmd
Move executable file to the folder
Create env file with written named in the code into this folder
Open terminal (zsh - MacOS) and run this command: open <executableFileName>
Output file should be in separated folder.

File paths for running golang code for debug vs run

I have a golang code on Linux VM which I am remotely debugging using VS Code. Below is my folder structure
MainFolder
|__Config
|__Other folders
Other Files
When I run the code using VS debugger, it runs properly and my code is able to find the path to files. But when I use the terminal to the code (I have workspace configured and need other project to run, and one project to debug) using go run ./folder, it gives some path like /tmp/go-build2342342342/b001/ when absolute path is populated. Any idea why it works this way and how to make the behavior consistent for properly getting the path?
Below is the code converting relative path to absolute
dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
if err != nil {
log.Fatal(err)
}
var path = filepath.Join(dir, relPath)
absPath, err := filepath.Abs(path)
Go binaries are compiled, even when run via go run. When you go run a package, os.Args[0] is set to the path of the compiled binary within the build cache, not the directory containing the source code for that binary.
To determine the path to source files, you must either pass the source location explicitly (as a flag or explicit argument), or invoke go run in a well-known directory and use os.Getwd to located it.
However, for run-time debugging information specifically, see the runtime and runtime/debug packages.

Unable to use the same relative path in my program AND my unit tests

In my Go Project I use a function that opens a specific file and returns its content. The file is stored in another directory but still inside my project directory.
package infrastructure
func openKey() ([]byte, error) {
if path, err := filepath.Abs("../security/key.rsa"); err != nil {
return nil, err
}
return ioutil.ReadFile(path)
}
This function works if I call it from a unit test. But if I call the same function in my program, I've this error:
2015/08/13 15:47:54 open
/me/go/src/github.com/myaccount/security/key.rsa: no such file
or directory
The correct absolute path of the file is:
/me/go/src/github.com/myaccount/myrepo/security/key.rsa
Both code that use the openKey function (from my program and unit test) are in the same package: infrastructure
Here is how I execute my program:
go install && ../../../../bin/myproject
And how I execute my unit tests:
go test ./...
And finally the directory structure of my project:
go/src/github.com/myaccount/myrepo/:
- main.go
- security:
- key.rsa // The file that I want to open
- ...
- infrastructure
- openFile.go // The file with the func `openKey``
- server.go // The file with the func that call the func `openKey`
- openFile_test.go // The unit test that calls the func `openKey`
Edit:
Here are the absolute paths of where the binary of my program is located:
/Users/me/Documents/DeĢveloppement/Jean/go/bin
And where my unit tests are located:
/var/folders/tj/8ywtc7pj3rs_j0y6zzldwh5h0000gn/T/go-build221890578/github.com/myaccount/myrepo/infrastructure/_test
Any suggestion?
Thanks!
First, you shouldn't use the same files when running your tests than when running your application in production. Because the test files are accessible to everyone that has access to the repository, which is a security fail.
As said in the comments, the problem is that when running your tests, the working directory is these of the source code (in fact, go copy the whole bunch into a temp directory prior to running the tests), while when you run the program for real, the working directory is the one you are running the command from, hence the wrong relative path.
What I would advise is to use a configuration option to get a the file from which load your file (or a base directory to use with your paths). Either using an environment variable (I strongly encourage you to do that, see the 12factors manofesto for details), a configuration file, a command-line flag, etc.
The go test ./... command changes the current directory to go/src/github.com/myaccount/myrepo/infrastructure before running the tests in that directory. So all relative paths in the tests are relative to the infrastructure directory.
A simple, robust way to allow testing would be to change the signature of your function.
func openKey(relPath string) ([]byte, error) {
if path, err := filepath.Abs(relPath); err != nil {
return nil, err
}
return ioutil.ReadFile(path)
}
This gives you freedom to place key.rsa anywhere during testing, you can for example make a copy of it and store it in infrastructure
An even more elegant and robust way would be to use io.Reader
func openKey(keyFile io.Reader) ([]byte, error) {
return ioutil.ReadAll(keyFile)
}
since you can pass it a strings.Reader for testing. This means that you can test your code without having to rely on the filesystem at all. But that's probably overkill in this case.

goconvey Please run goconvey from within your $GOPATH cannot import absolute path

I'm setting up go and trying to get a simple project working with http://goconvey.co/
I have my $GOPATH set to /Users/joe/Desktop/playground/go
and when I run
$ go get github.com/smartystreets/goconvey
it downloads all good to my GOPATH
so when I create a project here
/Users/joe/Desktop/playground/go/some-project
and run goconvey I get
2015/02/04 14:41:05 shell.go:93: Please run goconvey from within your $GOPATH
My testing code is
package main
import (
. "github.com/smartystreets/goconvey/convey"
"testing"
)
func TestStuff(t *testing.T) {
Convey("Truth", t, func() {
Convey("is falsey", func() {
So(false, ShouldBeFalse)
})
})
}
I don't know why it connot find the files.
When I run go test it works perfectly.
Help?
All go code needs to be within $GOPATH/src/ for the GoConvey UI to work.
So, if your $GOPATH is set to
/Users/joe/Desktop/playground/go
then you will need to put your project at
/Users/joe/Desktop/playground/go/src/some-project
Your code is currently at
/Users/joe/Desktop/playground/go/some-project
Having said all that, the error message should probably be modified to read something like this:
Please run goconvey from within $GOPATH/src (also, symlinks might be problematic).
The name of the variable referenced by #VonC is probably a slight misnomer in this case.

Resources