Send channel through a channel with Go - concurrency

I'd like to send a pointer to a channel through a channel. Is it possible in Go? How to define function that accepts such channel?
I tried:
func test() (chan *chan)
func test() (chan chan)

There is always some type associated with a channel. Let's assume that the type is T. A channel of T is:
chan T
A pointer to a channel of T is:
*chan T
A channel of pointer to channel of T is:
chan *chan T
A function accepting the channel of pointer to channel of T is:
func f(c chan *chan T) { }
Because channels are reference types, you probably don't need to use a pointer. Try using
func (f c chan chan T) { }
playground example

Related

How to compare/match closures in mocks?

TL;DR: mocked method accepts closure. I wonder how to create custom matcher (https://godoc.org/github.com/golang/mock/gomock#Matcher): closure itself in turn is working with private structure - meaning I can't even call the closure in my test to check it against expectations.
I'm working on a small app using Slack API with help of nlopes/slack (https://github.com/nlopes/slack).
For testing, I'm mocking nlopes/slack with gomock. For that I've created interface
type slackAPI interface {
OpenConversation(*slack.OpenConversationParameters) (*slack.Channel, bool, bool, error)
PostMessage(channelID string, options ...slack.MsgOption) (string, string, error)
GetUserByEmail(email string) (*slack.User, error)
}
I have no problem testing OpenConversation or GetUserByEmail, e.g.
slackAPIClient.
EXPECT().
GetUserByEmail("some#email.com").
Return(slackUserJohndoe, nil).
Times(1)
Things get more complicated when it comes to PostMessage. In main code the call looks like
_, _, err := slackAPIClient.PostMessage(channel.ID, slack.MsgOptionText(message, false))
And slack.MsgOptionText (from nlopes/slack) is actually returning closure:
func MsgOptionText(text string, escape bool) MsgOption {
return func(config *sendConfig) error {
if escape {
text = slackutilsx.EscapeMessage(text)
}
config.values.Add("text", text)
return nil
}
}
Since method is accepting closure, I need to create custom gomock matcher (https://godoc.org/github.com/golang/mock/gomock#Matcher). Custom matcher itself is not a problem, it would look something like
type higherOrderFunctionEqMatcher struct {
x interface{}
}
func (e hofEqMatcher) Matches(x interface{}) bool {
//return m.x == x
return true
}
func (e hofEqMatcher) String(x interface{}) string {
return fmt.Sprintf("is equal %v", e.x)
}
However, since MsgOptionText uses nlopes/slack private structure sendConfig, I wonder how can I even work with that in scope of my test to check equality to expectations.
How should I tackle such problem?
Bearing in mind that
in Golang you can't compare functions
in this precise case I can't do indirect test by calling closure itself (since it's using private 3rd party lib's structure as an argument)
the solution I've found is to mock slack.MsgOptionText(message, false), which in turn returns closure for PostMessage(channelID string, options ...slack.MsgOption):
type slackMsgCreator interface {
MsgOptionText(string, bool) slack.MsgOption
}
type slackMsgCreatorInst struct{}
func (s slackMsgCreatorInst) MsgOptionText(text string, escape bool) slack.MsgOption {
return slack.MsgOptionText(text, escape)
}
...
slackMsgCreator.
EXPECT().
MsgOptionText("Dear John Doe, message goes here", false).
Return(slack.MsgOptionText("Dear John Doe, message goes here", false)).
Times(1)
And, as for PostMessage - as was advised in comments, the only thing that I could check is that closure is not nil:
slackAPIClient.
EXPECT().
PostMessage("ABCDE", Not(Nil())).
AnyTimes()

Testing a method that accepts callback function that doesn't return a value in Golang

I'm trying to test the following function:
// SendRequestAsync sends request asynchronously, accepts callback
// func, which it invokes
//
// Parameters:
// - `context` : some context
// - `token` : some token
// - `apiURL` : the URL to hit
// - `callType` : the type of request to make. This should be one of
// the HTTP verbs (`"GET"`, `"POST"`, `"PUT"`, `"DELETE"`, ...)
// - `callBack` : the func to invoke upon completion
// - `callBackCustomData`: the data to invoke `callBack` with
//
// Since this is an async request, it doesn't return anything.
func (a *APICoreSt) SendRequestAsync(context interface{}, token string, apiURL string, callType APIType, header map[string]string, jsonBody []byte,
callBack OnCompletion, callBackCustomData interface{}) {
go func(data interface{}) {
callBack(a.SendRequest(context, token, apiURL, callType, header, jsonBody), data)
}(callBackCustomData)
}
where OnCompletion is defined by:
type OnCompletion func(result CallResultSt, data interface{})
My mind instantly thinks to create a spy callback. To do so, I forked this framework, came up with the following:
// outside the test function
type MySpy struct {
*spies.Spy
}
func (my *MySpy) Callback(res CallResultSt, data interface{}) {
my.Called(res, data)
fmt.Println("Hello world")
return
}
//in the test function
spy := new(MySpy)
//...some table-driven test logic the generator came up with, containing my data
spy.MatchMethod("Callback", spies.AnyArgs)
assert.NotEmpty(t, spies.CallsTo("Callback"))
and it greeted me with
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
panic: runtime error: invalid memory address or nil pointer dereference
How do I remedy this, and test this method?
I would ditch the spy stuff. This task is simple enough that you shouldn't need an external dependency to handle it. You could instead make your own "spy" that has a channel it passes args into when the function is called. In your test, you then attempt to receive from the channel. That will force the test to wait for the callback function to be called. You may also consider adding a timeout period so that the test can fail instead of blocking forever if the function is never called.
// outside the test function
type MySpy struct {
Args chan MySpyArgs
}
type MySpyArgs struct {
Res CallResultSt
Data interface{}
}
func (my *MySpy) Callback(res CallResultSt, data interface{}) {
my.Args <- MySpyArgs{Res: res, Data: data}
}
//in the test function
spyChan := make(chan MySpyArgs)
spy := &MySpy{spyChan}
//...some table-driven test logic the generator came up with, containing my data
args := <-spyChan
// can now assert arguments were as you expected, etc.
A crude working example: https://play.golang.org/p/zUYpjXdkz-4.
And if you want to use a timeout:
...
select {
case args := <-spyChan:
// assertions on args
case <-time.After(5 * time.Second):
// prevent blocking for over 5 seconds and probably fail the test
}

How to handle infinite go-loops

As a hobby project, I am working on an alternate futures and promises implementation based on "From Events to Futures and Promises and back". The original author uses channels/events under the hood, which is why I am using core.async. A future, expressed in pseudo Go syntax, looks as follows:
func future(func f() (T, bool)) Future <T> {
ch = newChannel ()
spawn(func() {
x := f()
for { syncEvt(sndEvt(ch, x)) }
})
return rcvEvt(ch)
}
Using valid Go syntax, type definitions and a get function:
type Comp struct {
value interface{}
ok bool
}
type Future chan Comp
func future(f func() (interface{}, bool)) Future {
future := make(chan Comp)
go func() {
v, o := f()
c := Comp{v, o}
for {
future <- c
}
}()
return future
}
func (ft Future) get() (interface{}, bool) {
c := <-ft
return c.value, c.ok
}
Now, when I port this to Clojure, I was thinking to implement it as followed:
(defrecord Comp [value ok])
(defn future [f]
(let [future (chan)]
(go-loop [comp (f)]
(>! future comp)
(recur comp))
future))
(defn get [future]
(<!! future))
Since I'm pretty new to Clojure (and core.async), I worry about the infinite go-loop. Will the IOC thread ever be released? Should I provide some kind of poison pill to stop the loop (though I think this would be pretty error-prone)? Any suggestions?
Go blocks in Clojure are not like they are in Go. In core.async go blocks exist as callbacks attached onto channels, and as such they live as long as the channel itself lives. So think of go blocks as being syntactic sugar over callbacks and it'll all star to make sense.
This video tutorial goes into a bit more detail: https://www.youtube.com/watch?v=VrwVc-saWLw

Golang Mocking - problems with type collision

I'm mocking out a DataStore and it's Get/Set functionality. The trouble I'm having is: cannot use s (type *MockStore) as type *datastore.Storage in argument to EventHandler
This is caused by my EventHandler function needing to be passed a *datastore.Storage as an argument type. I want to Test (http test) EvenHandler() using the MockStore I've created instead of the real datastore. I'm using the golang testify mock package.
Some Code Examples
type MockStore struct{
mock.Mock
}
func (s *MockStore) Get() ...
func EventHandler(w http.ResponseWriter, r *http.Request, bucket *datastore.Storage){
//Does HTTP stuff and stores things in a data store
// Need to mock out the data store get/sets
}
// Later in my Tests
ms := MockStore
EventHandler(w,r,ms)
A few things:
Create an interface that will be implemented both by datastore.Storage and your mock store.
Use the above interface as the argument type in EventHandler (not a pointer to the interface).
Pass a pointer to your MockStore to EventHandler, as the Get method is defined for a pointer to the struct.
Your updated code should be something like the following:
type Store interface {
Get() (interface{}, bool) // change as needed
Set(interface{}) bool
}
type MockStore struct {
mock.Mock
}
func (s *MockStore) Get() ...
func EventHandler(w http.ResponseWriter, r *http.Request,bucket datastore.Storage){
//Does HTTP stuff and stores things in a data store
// Need to mock out the data store get/sets
}
// Later in my Tests
ms := &MockStore{}
EventHandler(w,r,ms)

Standard ML: Naming datatypes of function arguments possible?

I'm new to ML and with to have a function that receives a special pre-defined datatype, and able to reference to its entire argument datatype, rather its components.
Here's a stupid example:
datatype frame = Frame of string list * string list
(* Type: fn : string * frame -> frame *)
val lookup_variable_value_in_frame =
fn (string(var), Frame(variables, values)) =>
...
Frame(variables, values)
... ;
1) I want to return the given frame. Must I build another Frame ?
2) I wish to pass the given frame to another function, must I provide a new Frame(variables, values) again ?
I wish I could write somthing like this:
val lookup_variable_value_in_frame =
fn (string(var), frame : Frame(variables, values)) => ...
then I'll be able to use the frame or its components .
Thank you.
Your datatype has already has a name, which is frame. You don't have to build another frame for returning or passing to another function. The first option is using explicit type annotation:
(* Type: fn : string * frame -> frame *)
val lookup_variable_value_in_frame =
fn (var: string, f: frame) =>
...
f
... ;
This option is not common, it should used only when you need types less generic than they are inferred by the type checker. Another option is using as keyword to make another binding to the value:
val lookup_variable_value_in_frame =
fn (var, f as Frame(variables, values)) =>
...(* using f, variables or values here *)
Note that there is no such thing like string(var) in SML, either use var or var: string for explicit type annotation.