Go - Pass callback function to child (imported) package - go

I have a go program, MyPackage, and a logging package within this, MyPackage/logs. We have a function func Cleanup(params CleanupParams) written in MyPackage that we want to use as a callback in case of any panic within our log function implemented in MyPackage/logs. This function is already written and being used by MyPackage, so we could all the code across but this would be very messy and involve a lot of copying dependent functions.
The approach I am thinking is this: In MyPackage, we have a function func SetupLogs, and could pass this Cleanup callback function as a parameter. However this ends up being a circular dependency, just since we have reference to a function on MyPackage from our logs package. Is there a way to pass this function, maybe with type any?
package MyPackage
import . "MyPackage/logs"
func main() {
cleanupParams := ...
...
SetupLogs(Cleanup, cleanupParams)
...
}
func Cleanup(params *CleanupParams) {
...
}
And our logs package:
package MyPackage/logs
type LogCallback func(*CleanupParams)
func SetupLogs(callback LogCallback, cleanupParams *CleanupParams) {
...
go LogLoop(callback, cleanupParams)
}
func LogLoop(callback LogCallback, cleanupParams *CleanupParams) {
defer callback(cleanupParams)
for {
// Keep checking if we have been channelled another message to log
// If we are logging and have to Panic() then our callback gets run
}
}
So is there any way to call the parent function from the imported class, since we don't need to know anything about the types of the function or its parameters, we just need to push our program to make sure the method gets called?
Thank you!

Use type func() for the callback function:
func SetupLogs(callback func()) {
...
go LogLoop(callback)
}
func LogLoop(callback func()) {
defer callback()
for {
// Keep checking if we have been channelled another message to log
// If we are logging and have to Panic() then our callback gets run
}
}
Use a closure to create a func() that calls Cleanup with the parameters.
SetupLogs(func() { Cleanup(cleanupParams) })

Related

How to Mock inner methods in GoLang

e.g
type test struct { // few fields}
func (t *test) createresource(res1 string,res2 string)error {
//doing some task
t.createsubresource(res1)
}
func (t *test)createsubresource(res1 string)error{
//perform some task
}
I want to write test function for createresource , how can I mock t.createsubresource(res1) call. This is legacy code and I don't have permission to modify any above function.
Your mock can be done using interfaces, as for example:
main.go
package main
type TestInterface interface {
CreateResource(res1 string, res2 string) error
CreateSubresource (res1 string) error
}
func main() {
DoSomething(new(Test))
}
func DoSomething(t TestInterface) {
t.CreateResource()
}
main_test.go
package main
import "testing"
type TestMock struct {}
func (tm *TestMock) CreateResource(res1 string, res2 string) error {
return nil
}
func (tm *TestMock) CreateSubresource(res1 string) error {
return nil
}
func TestDoSomething(t *testing.T) {
err := DoSomething(new(TestMock))
//... do your assertions
}
Why does it works like that?
Calling a function that depends on a specific structure does not allow you to inject alternatives to it, that's why a solution using interface needs to be created. By having an interface, just implement a new structure that matches that interface and pass it as a dependency injection to the procedure that will be tested.
Also, check this out:
There is no easy way, by default, to just point your original structure and tell Go to make a mock from it. Maybe some 3rd party lib can do it (but I didn't saw that yet).
In go, public and private declarations are defined by the first letter as uppercase. By the lower cases declarations in your sample I've noticed that everything is private.
Usually it is not a good practice to test private methods. There are a lot of discussions about this topic, you can take a look in this one here
There are also some support libs to make assertions and mocks like for example stretchr/testify, please make a research first.
I hope that it helps you.

How do I improve the testability of go library methods

I'm writing some code that uses a library called Vault. In this library we have a Client. My code makes use of this Client but I want to be able to easily test the code that uses it. I use only a couple methods from the library so I ended up creating an interface:
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
Now if my code is pointed at this interface everything is easily testable.. Except let's look at the Logical() method. It returns a struct here. My issue is that this Logical struct also has methods on it that allow you to Read, Write, ex:
func (c *Logical) Read(path string) (*Secret, error) {
return c.ReadWithData(path, nil)
}
and these are being used in my project as well to do something like:
{{ VaultClient defined above }}.Logical().Write("something", something)
Here is the issue. The Logical returned from the call to .Logical() has a .Write and .Read method that I can't reach to mock. I don't want all the logic within those methods to run in my tests.
Ideally I'd like to be able to do something similar to what I did above and create an interface for Logical as well. I'm relatively new to Golang, but I'm struggling with the best approach here. From what I can tell that's not possible. Embedding doesn't work like inheritance so it seems like I have to return a Logical. That leaves my code unable to be tested as simply as I would like because all the logic within a Logical's methods can't be mocked.
I'm sort of at a loss here. I have scoured Google for an answer to this but nobody ever talks about this scenario. They only go as far as I went with the initial interface for the client.
Is this a common scenario? Other libraries I've used don't return structs like Logical. Instead they typically just return a bland struct that holds data and has no methods.
package usecasevaultclient
// usecase.go
type VaultClient interface {
Logical() *api.Logical
SetToken(v string)
NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
}
type vaultClient struct {
repo RepoVaultClient
}
// create new injection
func NewVaultClient(repo RepoVaultClient) VaultClient {
return &vaultClient{repo}
}
func(u *vaultClient) Logical() *api.Logical {
// do your logic and call the repo of
u.repo.ReadData()
u.repo.WriteData()
}
func(u *vaultClient) SetToken(v string) {}
func(u *vaultClient) NewLifetimeWatcher(i *api.LifetimeWatcherInput) (*api.LifetimeWatcher, error)
// interfaces.go
type RepoVaultClient interface {
ReadData() error
WriteData() error
}
// repo_vaultclient_mock.go
import "github.com/stretchr/testify/mock"
type MockRepoVaultClient struct {
mock.Mock
}
func (m *MockRepoVaultClient) ReadData() error {
args := m.Called()
return args.Error(0)
}
func (m *MockRepoVaultClient) WriteData() error {
args := m.Called()
return args.Error(0)
}
// vaultClient_test.go
func TestLogicalShouldBeSuccess(t *testing.T) {
mockRepoVaultClient = &MockRepoVaultClient{}
useCase := NewVaultClient(mockRepoVaultClient)
mockRepoVaultClient.On("ReadData").Return(nil)
mockRepoVaultClient.On("WriteData").Return(nil)
// your logics gonna make this response as actual what u implemented
response := useCase.Logical()
assert.Equal(t, expected, response)
}
if you want to test the interface of Logical you need to mock the ReadData and WriteData , with testify/mock so u can defined the respond of return of those methods and you can compare it after you called the new injection of your interface

Pointer reference not stored in a struct in my go program

I am new to go-lang and I try to figure out how to work properly with structs and dependency injection. I am a bit stuck because I am not able to properly store a reference to another struct.
Here's my method that generates a CommandController. There is a valid reference to iris.Application.
func ProvideCommandController(application *iris.Application, commandRepository command.CommandRepository) (*interfaces.CommandController, error) {
commandController := interfaces.CommandController{}
commandController.Init(application, commandRepository)
commandController.Start()
return &commandController, nil
}
The struct looks like this:
type CommandController struct {
commandRepository command.CommandRepository
app *iris.Application
}
func (c CommandController) Init(app *iris.Application, repository command.CommandRepository) {
c.app = app
c.commandRepository = repository
}
func (c CommandController) Start() {
c.app.Get("/command", c.readAll)
c.app.Get("/command/{id:string}/execute", c.executeCommand)
c.app.Run(iris.Addr(":8080"))
}
When the ProvideCommandController function gets executed I can debug and observe that all references look good. Unfortunately, commandController.Start()fails because of c.app is nil.
What piece of understanding do I miss? Somehow, the stored reference get's deleted between the Init and the Start function call.
Thanks in advance :)
Change
func (c CommandController) Init(app *iris.Application, repository command.CommandRepository)
to
func (c *CommandController) Init(app *iris.Application, repository command.CommandRepository)
since Init receives c by value in your version, any changes it makes to c don't appear outside of the Init method.

How to access flags outside of main package?

We parse flags in main.go which is in main package, of course. Then we have another package where we want to read some flag's value.
flags.Args() work fine, it will return all non-flag values.
But I cannot figure out to how read already parsed value for a flag in a package other than main.
Is it possible?
Thanks
Amer
I had the same requirement recently and I wanted a solution that avoided calling flag.Parse repeatedly in init functions.
Perusing the flag package I found Lookup(name string) which returns a Flag which has a Value. Every built in Value implements the flag.Getter interface. The call chain looks like this:
flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
If you mistype the flag name or use the wrong type you get a runtime error. I wrapped the lookup in a function that I call directly where needed since the lookup and get methods are fast and the function is not called often. So the main package declares the flag.
// main.go
package main
import "flag"
var httplog = flag.Bool("httplog", false, "Log every HTTP request and response.")
func main() {
flag.Parse()
// ...
}
And the utility package, which is decoupled from main except for the flag name, reads the flag value.
// httpdiag.go
package utility
import "flag"
func logging() bool {
return flag.Lookup("httplog").Value.(flag.Getter).Get().(bool)
}
You can define the var storing the flag in the separate package, as an exported variable, then call the flag parsing in the main package to use that variable, like this:
mypackage/const.go
var (
MyExportedVar string
)
mainpackage/main.go
func init() {
flag.StringVar(&mypackage.MyExportedVar, "flagName", "defaultValue", "usage")
flag.Parse()
}
This way, everybody can access that flag, including that package itself.
Note:
this only works for exported variables.
You can define the flag in that package and call flag.Parse() in func init(), flag.Parse can be called multiple times.
However, if you want to access the flag's value from multiple packages you have to expose it or create an exposed function to check it.
for example:
// pkgA
var A = flag.Bool("a", false, "why a?")
func init() {
flag.Parse()
}
// main package
func main() {
flag.Parse()
if *pkgA.A {
// stuff
}
}
Also you can use FlagSet.Parse(os.Args) if you want to reparse the args.
When you parse your flags, parse them into global variables which start with an initial Capital so they are public, eg
package main
var Species = flag.String("species", "gopher", "the species we are studying")
func main() {
flag.Parse()
}
Then in your other package you can refer to them as
package other
import "/path/to/package/main"
func Whatever() {
fmt.Println(main.Species)
}

How can I invoke a variable method on a struct

I want to invoke a variable method on a struct like this example
type controller struct{}
func (c *controller) Index() {
fmt.Println("index controller")
}
func invokeIt(action string) {
(&controller{}).action // don't work duh
(&controller{})["action"] // this is Go not js
// how can I invoke it?
}
thx for the replies.
DHH, are you porting Rails to Go :) ?
Jokes aside, this is exactly what reflect is for. For example:
type Foo struct{}
func (Foo) FooM() { fmt.Println("Foom") }
func main() {
foo := Foo{}
reflect.ValueOf(foo).MethodByName("FooM").Call(nil)
}
Playground: http://play.golang.org/p/5ZGwlHLEmj
EDIT: A more idiomatic way to do it would be to use interfaces, (as someone else had proposed, but then have deleted their answer). So if you want to, say, define something that can do CRUD, in Go you'd usually go with
type Resources interface {
Index()
New()
Show(id int)
// ...
}
And maybe an Invoke method in order to invoke non-standard methods on this thing using reflect like above. reflect is very powerful and also a good way to shoot yourself in the foot, so it's never a good idea to overuse it.

Resources