I'am writting a script to interrract with a smart contract:
package main
import (
"context"
"fmt"
"log"
"github.com/ethereum/go-ethereum"
"github.com/joho/godotenv"
)
var myenv map[string]string
const envLoc = ".env"
func loadEnv() {
var err error
if myenv, err = godotenv.Read(envLoc); err != nil {
log.Printf("could not load env from %s: %v", envLoc, err)
}
}
func main() {
loadEnv()
ctx := context.Background()
client, err := ethclient.Dial(os.Getenv("GATEWAY"))
if err != nil {
log.Fatalf("could not connect to Ethereum gateway: %v\n", err)
}
defer client.Close()
accountAddress := common.HexToAddress("786af135e476c3b6061482e90c6273b8ee78c159")
balance, _ := client.BalanceAt(ctx, accountAddress, nil)
fmt.Printf("Balance: %d\n", balance)
}
I get undefined ethclient and undefined common.
I don't understant why I get these errors? it used to work normally
Make sure to import the correct packages. Here's a working example:
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/joho/godotenv"
)
func main() {
err := godotenv.Load()
if err != nil {
log.Fatal("Error loading .env file")
}
ctx := context.Background()
fmt.Println(os.Getenv("GATEWAY"))
client, err := ethclient.Dial(os.Getenv("GATEWAY"))
if err != nil {
log.Fatalf("could not connect to Ethereum gateway: %v\n", err)
}
defer client.Close()
accountAddress := common.HexToAddress("786af135e476c3b6061482e90c6273b8ee78c159")
balance, _ := client.BalanceAt(ctx, accountAddress, nil)
fmt.Printf("Balance: %d\n", balance)
}
You're not importing packages your code is using.
Add import "github.com/ethereum/go-ethereum/ethclient"
I am not sure where common package should be, but you're missing import for it as well.
Related
Trying to create a Lambda to interact with my DynamoDB.
This specific Lambda is to put/write an item to the DB:
package main
import (
"fmt"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/dynamodb"
"github.com/aws/aws-sdk-go/service/dynamodb/dynamodbattribute"
)
type Item struct {
Email string `json:"email"`
Password string `json:"password"`
Rname string `json:"rname"`
}
func Put() error {
// Create a session - London Region
session, err := session.NewSession(&aws.Config{
Region: aws.String("eu-west-2")},
)
if err != nil {
fmt.Println(err)
}
svc := dynamodb.New(session)
// Create instance of Item Struct
item := Item{
Email: "123#mail.com",
Password: "12345678",
Rname: "abcde",
}
// Marshall Item
av, err := dynamodbattribute.MarshalMap(item)
if err != nil {
fmt.Println("Got error marshalling map:")
fmt.Println(err)
}
// Create Item
input := &dynamodb.PutItemInput{
Item: av,
TableName: aws.String("accountsTable"),
}
_, err = svc.PutItem(input)
if err != nil {
fmt.Println("Got error calling PutItem:")
fmt.Println(err)
}
return err
}
func main() {
lambda.Start(Put())
}
However getting the error:
{
"errorMessage": "handler is nil",
"errorType": "errorString"
}
I have changed the handler in run time settings to main too so don't think that would be the issue.
Building with:
GOOS=linux GOARCH=amd64 CGO_ENABLED=0 go build -a main.go
and putting the zip of the executable into AWS via console (no IAC's)
Any help would be greatly appreciated to resolve this error! Thanks.
You need to pass function handle not function result to lambda.Start
Please update your main function with👇
func main() {
lambda.Start(Put)
}
I have a file in my project as :
package handlers
import (
"github.com/gorilla/mux"
)
type IHandlerProvider interface {
GetRouter() *mux.Router
}
type HandlerProvider struct{}
func (h HandlerProvider) GetRouter() *mux.Router {
r := mux.NewRouter()
r.HandleFunc("/health", Health).Methods("GET")
return r
}
What is the right way to unit test this? For instance:
package handlers
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestGetRouterOk(t *testing.T) {
var subject IHandlerProvider = HandlerProvider{}
router := subject.GetRouter()
assert.NotNil(t, router)
}
I can assert the object not being null, but how can I test the routes are correct?
If you want to test that the router is returning expected handler (vs test behaviour), you can do something like the following:
r := mux.NewRouter()
r.HandleFunc("/a", handlerA).Methods("GET")
r.HandleFunc("/b", handlerB).Methods("GET")
req, err := httptest.NewRequest("GET", "http://example.com/a", nil)
require.NoError(err, "create request")
m := &mux.RouteMatch{}
require.True(r.Match(req, m), "no match")
v1 := reflect.ValueOf(m.Handler)
v2 := reflect.ValueOf(handlerA)
require.Equal(v1.Pointer(), v2.Pointer(), "wrong handler")
You could use httptest package.
handlers.go:
package handlers
import (
"net/http"
"github.com/gorilla/mux"
)
type IHandlerProvider interface {
GetRouter() *mux.Router
}
type HandlerProvider struct {}
func Health(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("ok"))
}
func (h HandlerProvider) GetRouter() *mux.Router {
r := mux.NewRouter()
r.HandleFunc("/health", Health).Methods("GET")
return r
}
handlers_test.go:
package handlers
import (
"testing"
"bytes"
"io/ioutil"
"net/http/httptest"
)
func TestGetRouterOk(t *testing.T) {
assertResponseBody := func(t *testing.T, s *httptest.Server, expectedBody string) {
resp, err := s.Client().Get(s.URL+"/health")
if err != nil {
t.Fatalf("unexpected error getting from server: %v", err)
}
if resp.StatusCode != 200 {
t.Fatalf("expected a status code of 200, got %v", resp.StatusCode)
}
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
t.Fatalf("unexpected error reading body: %v", err)
}
if !bytes.Equal(body, []byte(expectedBody)) {
t.Fatalf("response should be ok, was: %q", string(body))
}
}
var subject IHandlerProvider = HandlerProvider{}
router := subject.GetRouter()
s := httptest.NewServer(router)
defer s.Close()
assertResponseBody(t, s, "ok")
}
unit test result:
=== RUN TestGetRouterOk
--- PASS: TestGetRouterOk (0.00s)
PASS
ok github.com/mrdulin/golang/src/stackoverflow/64584472 0.097s
coverage:
As far as I can tell I'm following structure needed for 'go test' flawlessly. I don't see a discrepancy from tests I could run in other packages. 'go build' works fine.
I'm getting
./HelloTemplate_test.go:3: imported and not used: "testing"
./HelloTemplate_test.go:5: undefined: Testing in Testing.T
What am I missing?
HelloTemplate.go
package templateprint
import "testing"
func TestRunTempl(t *Testing.T) {
sweaters := Inventory{"wool", 17}
tmpl := "{{.Count}} items are made of {{.Material}}"
err := RunTempl(tmpl, sweaters)
if err != nil {
t.Error("Template failed ")
}
}
HelloTemplate_test.go
package templateprint
import (
"os"
"text/template"
)
type Inventory struct {
Material string
Count uint
}
func RunTempl(templ string, inv Inventory) error {
tmpl, err := template.New("test").Parse(templ)
if err != nil {
return (err)
}
err = tmpl.Execute(os.Stdout, inv)
if err != nil {
return (err)
}
return nil
}
You are using an incorrect type in your test function:
// testing.T, not Testing.T
// T is a type defined in testing module
func TestRunTempl(t *testing.T) {
sweaters := Inventory{"wool", 17}
tmpl := "{{.Count}} items are made of {{.Material}}"
err := RunTempl(tmpl, sweaters)
if err != nil {
t.Error("Template failed ")
}
}
I have the following function:
func GetDataFromFile(path string) ([]byte, error) {
_, err := os.Stat(path)
if err != nil {
return nil, err
}
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
return data, nil
}
I want to do tests for functions ioutil.ReadFile and os.Stat(path) when they throw errors.
I know that I can create non-exist path for os.Stat(path), but how to test such kind functions without "workarounds" and guessing how functions are working?
Regards.
I agree with abhink here, I would not expect you to test this particular function. But in practice, similar situation happens often.
My best solution is to use a factory to create GetDataFromFile. In this case, you inject the dependencies.
main.go
package main
import (
"io/ioutil"
"os"
)
func getDataFromFileFactory(
stat func(filename string) (os.FileInfo, error),
readFile func(filename string) ([]byte, error),
) func(path string) ([]byte, error) {
return func(path string) ([]byte, error) {
_, err := stat(path)
if err != nil {
return nil, err
}
data, err := readFile(path)
if err != nil {
return nil, err
}
return data, nil
}
}
var GetDataFromFile = getDataFromFileFactory(os.Stat, ioutil.ReadFile)
func main() {}
main_test.go
package main
import (
"errors"
"os"
"testing"
)
func TestGetDataFromFile(t *testing.T) {
stat := func(filename string) (os.FileInfo, error) {
return nil, errors.New("err msg")
}
readfile := func(filename string) ([]byte, error) {
t.Error("should not call this function")
return nil, nil
}
getDataFromFile := getDataFromFileFactory(stat, readfile)
if _, err := getDataFromFile("foo"); err.Error() != "err msg" {
t.Error("expected an error to be thrown")
}
}
Is there any specific reason you want to test these library functions?
You should only concern yourself with testing your own code and logic. Libraries are tested by those who create and maintain them and you should use them fully expecting to perform as per their documentation. Any genuine deviation from expected behavior should be reported to the authors/maintainers of the library.
As for testing GetDataFromFile, it would be perfectly legitimate to test it by supplying incorrect path. For more specific errors you can also read up on the input parameters that would cause them and call the functions with those arguments.
I want to download files in parallel in go, but my code never exits:
package main
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"sync"
)
func download_file(file_path string, wg sync.WaitGroup) {
defer wg.Done()
resp, _ := http.Get(file_path)
defer resp.Body.Close()
filename := filepath.Base(file_path)
file, _ := os.Create(filename)
defer file.Close()
size, _ := io.Copy(file, resp.Body)
fmt.Println(filename, size, resp.Status)
}
func main() {
var wg sync.WaitGroup
file_list := []string{
"http://i.imgur.com/dxGb2uZ.jpg",
"http://i.imgur.com/RSU6NxX.jpg",
"http://i.imgur.com/hUWgS2S.jpg",
"http://i.imgur.com/U8kaix0.jpg",
"http://i.imgur.com/w3cEYpY.jpg",
"http://i.imgur.com/ooSCD9T.jpg"}
fmt.Println(len(file_list))
for _, url := range file_list {
wg.Add(1)
fmt.Println(wg)
go download_file(url, wg)
}
wg.Wait()
}
What's the reason? I've looked here: Golang download multiple files in parallel using goroutines but I found no solution.
What is the best way to debug such code?
As Tim Cooper said you need to pass the WaitGroup as a pointer. If you run the go vet tool on your code it will give you this warning:
$ go vet ex.go
ex.go:12: download_file passes Lock by value: sync.WaitGroup contains sync.Mutex
exit status 1
I recommend using an editor that can do this for you when you save a file. For example go-plus for Atom.
As for the code I think you should restructure it like this:
package main
import (
"fmt"
"io"
"net/http"
"os"
"path/filepath"
"sync"
)
func downloadFile(filePath string) error {
resp, err := http.Get(filePath)
if err != nil {
return err
}
defer resp.Body.Close()
name := filepath.Base(filePath)
file, err := os.Create(name)
if err != nil {
return err
}
defer file.Close()
size, err := io.Copy(file, resp.Body)
if err != nil {
return err
}
fmt.Println(name, size, resp.Status)
return nil
}
func main() {
var wg sync.WaitGroup
fileList := []string{
"http://i.imgur.com/dxGb2uZ.jpg",
"http://i.imgur.com/RSU6NxX.jpg",
"http://i.imgur.com/hUWgS2S.jpg",
"http://i.imgur.com/U8kaix0.jpg",
"http://i.imgur.com/w3cEYpY.jpg",
"http://i.imgur.com/ooSCD9T.jpg"}
fmt.Println("downloading", len(fileList), "files")
for _, url := range fileList {
wg.Add(1)
go func(url string) {
err := downloadFile(url)
if err != nil {
fmt.Println("[error]", url, err)
}
wg.Done()
}(url)
}
wg.Wait()
}
I don't like passing WaitGroups around and prefer to keep functions simple, blocking and sequential and then stitch together the concurrency at a higher level. This gives you the option of doing it all sequentially without having to change downloadFile.
I also added error handling and fixed names so they are camelCase.
Adding to Calab's response, there's absolutely nothing wrong with your approach, all you had to do is to pass a pointer to the sync.WaitGroup.
func download_file(file_path string, wg *sync.WaitGroup) {
defer wg.Done()
......
}
.....
go download_file(url, &wg)
.....
playground