go test flag: flag provided but not defined - go

Hi I am using a flag when testing in go:
file_test.go
var ip = flag.String("ip", "noip", "test")
I am only using this in one test file. And it works fine when only testing that one test file, but when I run:
go test ./... -ip 127.0.0.1 alle of the other test file saying: flag provided but not defined.
Have you seen this?
Regards

flag.Parse() is being called before your flag is defined.
You have to make sure that all flag definitions happen before calling flag.Parse(), usually by defining all flags inside init() functions.

If you've migrated to golang 13, it changed the order of the test initializer,
so it could lead to something like
flag provided but not defined: -test.timeout
as a possible workaround, you can use
var _ = func() bool {
testing.Init()
return true
}()
that would call test initialization before the application one. More info can be found on the original thread:
https://github.com/golang/go/issues/31859#issuecomment-489889428

do not call flag.Parse() in any init()

I'm very late to the party; but is this broken (again) on Go 1.19.5?
I hit the same errors reported on this thread and the same solution reported above (https://github.com/golang/go/issues/31859#issuecomment-489889428) fixes it.
I see a call to flags.Parse() was added back in go_test.go in v1.18
https://go.googlesource.com/go/+/f7248f05946c1804b5519d0b3eb0db054dc9c5d6%5E%21/src/cmd/go/go_test.go
I am only just learning Go so it'd be nice to have some verification from people more skilled before I report this elsewhere.

If you get this, when running command via docker-compose then you do incorrect quoting. Eg.
services:
app:
...
image: kumina/openvpn-exporter:latest
command: [
"--openvpn.status_paths", "/etc/openvpn_exporter/openvpn-status.log",
"--openvpn.status_paths /etc/openvpn_exporter/openvpn-status.log",
]
First is correct, second is wrong, because whole line counted as one parameter. You need to split them by passing two separate strings, like in first line.

Related

Golang Cobra multiple flags with no value

I'm new to Golang, and i'm trying out my first CLI application, using the Cobra framework.
My plan is to have few commands, with many flags.
These flags, don't have to have a value attached to them, since they can simply be -r to restart the device.
Currently, i have the following working, but i keep thinking, that this cannot be the correct way to do it.
So any help is appreciated.
The logic is currently, that each command, get's a default value attached to it, and then i look for this, in the run command, and triggers my function, once it captures it.
My "working code" looks like below.
My init function, in the command contains the following.
chargerCmd.Flags().StringP("UpdateFirmware", "u", "", "Updeates the firmware of the charger")
chargerCmd.Flags().Lookup("UpdateFirmware").NoOptDefVal = "yes"
chargerCmd.Flags().StringP("reboot", "r", "", "Reboots the charger")
chargerCmd.Flags().Lookup("reboot").NoOptDefVal = "yes"
And the run section looks like this.
Run: func(cmd *cobra.Command, args []string) {
input, _ := cmd.Flags().GetString("UpdateFirmware")
if input == "yes" {
fmt.Println("Updating firmware")
UpdateFirmware(os.Getenv("Test"), os.Getenv("Test2"))
}
input, _ = cmd.Flags().GetString("reboot")
if input == "yes" {
fmt.Println("Rebooting Charger")
}
},
Maybe to make the usage a bit cleaner, as stated in the comment from Burak - you can better differentiate between commands and flags. With cobra you have the root command and sub-commands attached to the root command. Additionaly each command can accept flags.
In your case, charger is the root commands and you want two sub-commands: update_firmware and reboot.
So as an example to reboot the charger, you would execute the command:
$ charger reboot
In the code above, you are trying to define sub-commands as flags, which is possible, but likely not good practice.
Instead, the project should be set-up something like this: https://github.com/hesamchobanlou/stackoverflow/tree/main/74934087
You can then move the UpdateFirmware(...) operation within the respective command definition under cmd/update_firmware.go instead of trying to check each flag variation on the root chargerCmd.
If that does not help, provide some more details on why you think your approach might not be correct?

panic: testing: Verbose called before Init

Trying to run
https://github.com/adonovan/gopl.io/blob/master/ch8/cake/cake_test.go
but got
panic: testing: Verbose called before Init
goroutine 1 [running]:
testing.Verbose(...)
/usr/lib/go-1.17/src/testing/testing.go:453
.../cake_test.init()
It says the error comes from cake_test.init(), yet the cake_test.go file doesn't contain init():
$ grep init cake_test.go | wc
0 0 0
What exactly is the problem?
This happens because the testing package itself has a init to process test flags and you are callind Verbose to create a global variable
https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/testing/testing.go;l=548
To avoid this you can:
Use a ponter to function to capture testing.Verbose and use inside functions, after all initializations ( Verbose will be type func() bool) but I think this is complex
Add a helper that creates a new default on each test with a safe call to testing.Verbose
Create a constructor (instead a test helper) that fill with the most common options and you can set the value of Verbose on each test
Create a two constructors, a second one that receive the value of Verbose
Also, Consider create a method Debug with same signature of Println, to call fmt.Println if Verbose is true
If you have a constructor, you can create a second field: Logger, with is a ponter to function with same signature as Println and you initialize with fmt.Println and in the tests you can set as t.Log to have a better experience
Of course perhaps some suggestions are more advanced than others, feel free to play a little bit and choose the best ones

golang test fails on flags parse for test.v

In my go program, the main method does:
port := flag.Int("port", 8080, "Port number to start service on")
flag.Parse()
I have a dummy test that looks as:
func TestName(t *testing.T) {
fmt.Println("Hello there")
}
when I run my tests (from the goland or the command line) I got the following error stuck:
/usr/local/go/bin/go tool test2json -t /private/var/folders/7v/p2t5phhn6cn9hqwjnn_p95_80000gn/T/___TestName_in_github_tools....test -test.v -test.paniconexit0 -test.run ^\QTestName\E$
flag provided but not defined: -test.v
Usage of /private/var/folders/7v/p2t5phhn6cn9hqwjnn_p95_80000gn/T/___TestName_in_github_tools.....test:
-port int
Port number to start service on (default 8080)
When I remove the lines of the flag in the main, the test executes normally
Any idea on how to fix this, please?
Thanks in advance
When you run go test, go actually compiles your code into an executable, and executes it.
If you add options to go test -- for example : go test -v -- these options are actually passed to the test executable, prefixed with test -- so -v is turned into -test.v.
(this is a reason why several comments ask for the exact command line you use to run your tests : since the error is about -test.v, there probably is something that adds -v to some go test ... invocation)
It looks like flag.Parse() is trying to parse some arguments which are actually intended for your test executable, not for your code.
This is probably because it is called too early, before the test executable has had a chance to alter the os.Args slice to remove some specific flags.
Check what triggers a call to flag.Parse() : if it is executed from an init() block, this would count as "too early".
The behavior of go test options is documented in go help testflag :
Each of these flags is also recognized with an optional 'test.' prefix,
as in -test.v. When invoking the generated test binary (the result of
'go test -c') directly, however, the prefix is mandatory.
The 'go test' command rewrites or removes recognized flags,
as appropriate, both before and after the optional package list,
before invoking the test binary.
For instance, the command
go test -v -myflag testdata -cpuprofile=prof.out -x
will compile the test binary and then run it as
pkg.test -test.v -myflag testdata -test.cpuprofile=prof.out

Find dead code in Golang monorepo

My team has all our Golang code in a monorepo.
Various package subdirectories with library code.
Binaries/services/tools under cmd
We've had it for a while and are doing some cleanup. Are there any tools or techniques that can find functions not used by the binaries under cmd?
I know go vet can find private functions that are unused in a package. However I suspect we also have exported library functions that aren't used either.
UPD 2020: The unused tool has been incorporated into staticcheck.
Unfortunately, v0.0.1-2020.1.4 will probably be the last to support this
feature. Dominik explains that it is because the check consumes a lot of
resources and is hard to get right.
To get that version:
env GO111MODULE=on go get honnef.co/go/tools/cmd/staticcheck#v0.0.1-2020.1.4
To use it:
$ staticcheck --unused.whole-program=true -- ./...
./internal/pkg/a.go:5:6: type A is unused (U1001)
Original answer below.
Dominik Honnef's unused tool might be what you're looking for:
Optionally via the -exported flag, unused can analyse all arguments as a
single program and report unused exported identifiers. This can be useful for
checking "internal" packages, or large software projects that do not export
an API to the public, but use exported methods between components.
Try running go build -gcflags -live. This passes the -live flag to the compiler (go tool compile), instructing it to output debugging messages about liveness analysis. Unfortunately, it only prints when it's found live code, not dead code, but you could in theory look to see what doesn't show up in the output.
Here's an example from compiling the following program stored in dead.go:
package main
import "fmt"
func main() {
if true {
fmt.Println(true)
} else {
fmt.Println(false)
}
}
Output of go build -gcflags -live:
# _/tmp/dead
./dead.go:7: live at call to convT2E: autotmp_5
./dead.go:7: live at call to Println: autotmp_5
If I'm reading this correctly, the second line states that the implicit call to convT2E (which converts non-interface types to interface types, since fmt.Println takes arguments of type interface{}) is live, and the third line states that the call to fmt.Println is live. Note that it doesn't say that the fmt.Println(false) call is live, so we can deduce that it must be dead.
I know that's not a perfect answer, but I hope it helps.
It is a bit dirty, but it works for me.
I had a lot of structs which I did not want to test manually, so I wrote a script that renames the struct then runs all the tests (ci/test.sh) and renames it back if any test failed:
#!/bin/sh
set -e
git grep 'struct {' | grep type | while read line; do
file=$(echo $line | awk -F ':' '{print $1}')
struct=$(echo $line | awk '{print $2}')
sed "s/$struct struct/_$struct struct/g" -i $file
echo "testing for struct $struct changed in file $file"
if ! ./ci/test.sh; then
sed "s/_$struct struct/$struct struct/g" -i $file
fi
done
It's not an open source solution, but it works.
If you guys are using Goland, you should consider using its code-inspections feature, includes useful features:
Reports unused constant
Reports unused exported functions
Reports unused exported types in the main package and in tests
Reports unused unexported functions
Reports global variables that are defined but are never used in code
Reports unused function parameters
Reports unused types
(It looks like the implementation of this feature is black box, jetbrains does not open source this feature)
Go-related detection tools seem to place more emphasis on accuracy, and they want to do their best to minimize error reporting. And using Goland's code-inspections feature may require more self-judgment. :)
Interests: Paid users only, not working for Jetbrains, simply think this feature works well.
A reliable but inelegant method I've used is to rename or comment out functions you suspect might not be used and then recompile everything -- no errors means you didn't need them.
If they are needed, it shows you where these functions are called so it's good for getting familiar with a code base and seeing how things connect.

flag package in Go - do I have to always set default value?

Is it possible not to set default value in flag package in Go? For example, in flag package you can write out the following line:
filename := flag.String("file", "test.csv", "Filename to cope with")
In the above code, I don't want to necessarily set default value, which is test.csv in this case, and instead always make users specify their own filename, and if it's not specified then I want to cause an error and exit the program.
One of the way I came up with is that I first check the value of filename after doing flag.Parse(), and if that value is test.csv then I have the program exits with the appropriate error message. However, I don't want to write such redundant code if it can be evaded - and even if it can't, I'd like to hear any better way to cope with the issue here.
You can do those kind of operations in Python's argparse module by the way - I just want to implement the similar thing if I can...
Also, can I implement both short and long arguments (in other words both -f and -file argument?) in flag package?
Thanks.
I think it's idiomatic to design your flag values in such a way which implies "not present" when equal to the zero value of their respective types. For example:
optFile := flag.String("file", "", "Source file")
flag.Parse()
fn := *optFile
if fn == "" {
fn = "/dev/stdin"
}
f, err := os.Open(fn)
...
Ad the 2nd question: IINM, the flag package by design doesn't distinguish between -flag and --flag. IOW, you can have both -f and --file in your flag set and write any version of - or -- before both f and file. However, considering another defined flag -g, the flag package will not recognize -gf foo as being equvalent of -g -f foo.
When I have a flag that cannot have a default value I often use the value REQUIRED or something similar. I find this makes the --help easier to read.
As for why it wasn't baked in, I suspect it just wasn't considered important enough. The default wouldn't fit every need. However, the --help flag is similar; it doesn't fit every need, but it's good enough most of the time.
That's not to say the required flags are a bad idea. If you're passionate enough a flagutil package could be nice. Wrap the current flag api, make Parse return an error that describes the missing flag and add a RequiredInt and RequiredIntVar etc. If it turns out to be useful / popular it could be merged with the official flag package.
This is how I implemented command argument parser.
Since there are already plenty of similar projects, I decided not to add more choices without strong impetus.
Here is an example of how it can be used, which might inspired somebody, or someone might be interested.
# minarg.go
package main
import (
"fmt"
"self/argp"
)
func main() {
p := argp.New(nil)
p.Bool("continue",nil,"-v","-g")
f := func(m, arg string) {
switch m {
case "__init__":
case "__defer__":
p.Set("server", p.GetString("-s") + ":" + p.GetString("-p"))
default:
arg, _ := p.Shift()
p.Set(m, arg)
}
}
p.Mode(f,"__init__","__defer__","-s","-p","-nstat","-n")
p.Default("-s","127.0.0.1", "-p","1080", "-nstat","100", "-n","5")
p.Env("-s","SERVER", "-p","PORT")
p.Parse()
fmt.Println(p.Vars)
}
The output is
$ go run minarg.go
&map[-g:{false continue <nil>} -n:5 -nstat:100 -p:1080 -s:127.0.0.1 -v:{false continue <nil>} server:127.0.0.1:1080]
$ export PORT=80
$ go run minarg.go -s 0.0.0.0 -n 3 -vg
&map[-g:{true continue <nil>} -n:3 -nstat:100 -p:80 -s:0.0.0.0 -v:{true continue <nil>} server:0.0.0.0:80]

Resources