Beego - Endpoint Testing - go

I am testing http custom endpoint for beego
package test
import (
"github.com/astaxie/beego"
. "github.com/smartystreets/goconvey/convey"
_ "golife-api-cons/routers"
"net/http"
"net/http/httptest"
"path/filepath"
"runtime"
"testing"
)
func init() {
_, file, _, _ := runtime.Caller(1)
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".."+string(filepath.Separator))))
beego.TestBeegoInit(apppath)
}
// TestGet is a sample to run an endpoint test
func TestGet(t *testing.T) {
r, _ := http.NewRequest("GET", "/my/endpoint/fetches/data", nil)
w := httptest.NewRecorder()
beego.BeeApp.Handlers.ServeHTTP(w, r)
beego.Trace("testing", "TestGet", "Code[%d]\n%s", w.Code, w.Body.String())
Convey("Subject: Test Station Endpoint\n", t, func() {
Convey("Status Code Should Be 200", func() {
So(w.Code, ShouldEqual, 200)
})
Convey("The Result Should Not Be Empty", func() {
So(w.Body.Len(), ShouldBeGreaterThan, 0)
})
})
}
When i run using go test -v ,
I get in response dial tcp :0: getsockopt: connection refused
I am using MariaDB running on my local,
I have verified using netstat -tulpn that my database is running perfectly fine (I get a valid response if i use postman and my server is running)
One weird observation , after inclusion of line _ "golife-api-cons/routers" i get this error even before test's are ran
My test passes with response 200 OK , but without any data as i get in response the above mentioned error
EDIT
The default path by used by TestBeegoInit function used is /path/to/my/project/test
which is not the desired path , so i tried giving the absolute path too , still i am not able to connect DB.

After much trying I came to know that beego initializes its variable called as AppPath in beego/conf.go like -
AppPath, _ = filepath.Abs(filepath.Dir(os.Args[0]))
when you run your tests you run them with go test -v
but as a result the os.Args[0] is the text executable which will be /tmp/path/to/test and not path/to/app/exe
hence as a result it does not find config/app.conf which is in your app path which has db connection details.
Responsible line in beego/conf.go -
appConfigPath = filepath.Join(AppPath, "conf", "app.conf")
This all happens in beego's init function when you say
import (
"github.com/astaxie/beego"
_ "path/to/routers"
)
Hack for this is -
create a new package / file with init function which looks has -
package common
import (
"os"
"strings"
)
func init() {
cwd := os.Getenv("PWD")
rootDir := strings.Split(cwd, "tests/")
os.Args[0] = rootDir[0] // path to you dir
}
here you are changing os.Args[0] and assigning your directory path
make sure you import it before beego so now import will look like
import (
_ "path/to/common"
"github.com/astaxie/beego"
_ "path/to/routers"
)
And finally you connect to DB !

You are initializing your app as
apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".."+string(filepath.Separator))))
beego.TestBeegoInit(apppath)
}
Where file is the caller file.
TestBeegoInit is:
func TestBeegoInit(ap string) {
os.Setenv("BEEGO_RUNMODE", "test")
appConfigPath = filepath.Join(ap, "conf", "app.conf")
os.Chdir(ap)
initBeforeHTTPRun()
}
hence the location where your tests are looking for configuration is
<this_file>/../conf/app.conf
which basically is the default config file.
Basically you are not able to connect to the database. Perhaps because you are unknowingly connecting to your default database for the tests too. I suspect this is not what you are trying to do.

Related

Unable to find .env file in Go file executed via serverless function

I have a React web app calling a Go 'backend' (i.e. serverless functions) - but for whatever reason it can't access my .env file.
My overall project structure is roughly as follows:
- root
-- .env
-- src
-- api (where my functions are stored)
As a result, I figured I'd just be able to utilise a dotenv package. However, my file is returning the first err, indicating it can't find the variable.
package handler
import (
"fmt"
"log"
"net/http"
"os"
"github.com/joho/godotenv"
)
func Main(w http.ResponseWriter, r *http.Request) {
if err := godotenv.Load(); err != nil {
fmt.Println("No .env file found")
log.Panicln("No .env file found")
}
uri := os.Getenv("MONGO_URI")
fmt.Println(uri)
}
Does anyone have any suggestions as to why my app can't find my .env file, despite it existing?

Problem with Gin Gonic and Qor Admin: error 500 on heroku

I want to create an admin panel for my project and i used Qor admin with Gin. When i tested it on localhost it didnt cause any errors or exeptions, but when i commit it to heroku i`ll get 500 error; I use Gorm v1 as an ORM. How can i fix the error?
This is main project file is:
package main
import (
"net/http"
"os"
"github.com/gin-gonic/gin"
"github.com/qor/admin"
)
func main() {
connect()
Admin := admin.New(&admin.AdminConfig{DB: db})
adminServer := http.NewServeMux()
Admin.MountTo("/admin", adminServer)
Admin.AddResource(&User{})
app := gin.Default()
//app.LoadHTMLGlob("views/*")
app.MaxMultipartMemory = 140 << 20
gin.SetMode(gin.ReleaseMode)
Controller(app)
port := os.Getenv("PORT")
if port == "" {
port = "5000"
}
app.Any("/admin/*resources", gin.WrapH(adminServer))
app.Run(":" + port)
}
And what i get as a result when i try to open AP:
And what i get as a result when i try to open AP:
I found the method: You can just put the folder from the qor/admin repository into your project folder by path <project_folder>/app/views/qor. In the folder named qor, there must be .tmpl files and static-content folders.

How to prevent Kubernetes go-client-discovery pkg sending error to stderr

I am using the go discovery client pkg (k8s.io/client-go/discovery, v0.22.2) to list all supported resources in a cluster ->
discoveryClient, err := discovery.NewDiscoveryClientForConfig(GetK8sConfig())
if err != nil {
// do something
}
resourceList, err := discoveryClient.ServerPreferredResources()
When I run this code I get the following error ->
I1213 09:19:15.932915 38142 request.go:665] Waited for 1.008601388s due to client-side throttling, not priority and fairness, request: GET:https://35.225.61.23/apis/scheduling.k8s.io/v1beta1?timeout=32s
Now, I don't mind the error, what bothers me is that I can't prevent this error from being printed.
Any idea how to stop the discovery client from sending errors to the stderr?
The client use the klog library that implement the default logging conventions. You could read more in the readme.
You should initialize the library with different values in your main. As example :
import (
"bytes"
"flag"
"fmt"
"k8s.io/klog/v2"
)
func main() {
klog.InitFlags(nil)
flag.Set("logtostderr", "false")
flag.Set("alsologtostderr", "false")
flag.Parse()
Another approach, if you want to sue Zap logger with json payload as output, you can do something like:
import (
...
"github.com/go-logr/zapr"
"go.uber.org/zap"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/klog/v2"
...
)
func main() {
flag.Parse()
if logger, err := zap.NewProduction(); err == nil {
klog.SetLogger(zapr.NewLogger(logger))
}
From:
W0630 12:59:05.205701 1 client_config.go:614] Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.
to
{"level":"info","ts":1625058100.1339207,"caller":"v2/klog.go:921","msg":"Neither --kubeconfig nor --master was specified. Using the inClusterConfig. This might not work.\n"}

Given two absolute URI, find the relative path between them

Is there a function in go standard library that lets me do this
a = 'www.my.com/your/stuff'
b = 'www.my.com/your/stuff/123/4'
function(b,a) // /123/4
or
function(URL(b),URL(a)) // /123/4
The following is probably defined in this case
function(a,b) // error ? or ../../
I'm aware that I can use path package for this. But it cannot work in many cases where there is query param, file extension etc.
Basically I'm looking for a path.resolve counterpart for URL
It turns out that the path/filepath package can do this for you. If you ignore the fact that these are URLs and instead treat them like paths, you can use filepath.Rel():
package main
import (
"fmt"
"path/filepath"
)
func main() {
base := "www.my.com/your/stuff"
target := "www.my.com/your/stuff/123/4"
rel, _ := filepath.Rel(base, target)
fmt.Println(rel) // prints "123/4"
}
Playground: https://play.golang.org/p/nnF9zfFAFfc
If you want to treat these paths as actual URLs, you should probably use the net/url package to first parse the path as a URL, then extract the path and use filepath.Rel() on that. This allows you to properly deal with things like queries in the URL string, which would trip up filepath, like so:
package main
import (
"fmt"
"path/filepath"
"net/url"
)
func main() {
url1, _ := url.Parse("http://www.my.com/your/stuff")
url2, _ := url.Parse("http://www.my.com/your/stuff/123/4?query=test")
base := url1.Path
target := url2.Path
rel, _ := filepath.Rel(base, target)
fmt.Println(base) // "/your/stuff"
fmt.Println(target) // "/your/stuff/123/4"
fmt.Println(rel) // "123/4"
}
Playground: https://play.golang.org/p/gnZfk0t8GOZ
As a bonus, filepath.Rel() is smart enough to handle relative paths in the other direction, too:
rel, _ = filepath.Rel(target, base) // rel is now "../.."

Can not run tests from non-root folder

I have a tests which looks like:
package tst
import (
"testing"
"github.com/demas/cowl-go/pkg/postgres"
"log"
"os"
"fmt"
"github.com/jmoiron/sqlx"
"github.com/demas/cowl-go/pkg/quzx-crawler"
"github.com/SlyMarbo/rss"
"time"
_ "github.com/lib/pq"
)
func TestMain(m *testing.M) {
prepare()
retCode := m.Run()
os.Exit(retCode)
}
func prepare() {
connectionString := fmt.Sprintf("user=%s password=%s host=%s port=%s dbname=%s sslmode=disable",
os.Getenv("DBUSER"),
os.Getenv("DBPASS"),
os.Getenv("DBHOST"),
os.Getenv("DBPORT"),
os.Getenv("DBNAME"))
db, err := sqlx.Open("postgres", connectionString)
if err != nil {
log.Fatal(err)
}
db.Exec(`DELETE FROM Settings`)
db.Exec(`DELETE FROM HackerNews`)
// ....
}
Tests works fine if I keep in the root project folder, but if I move them to tst folder I get error message:
D:\development\gopath\src\github.com\demas\cowl-go\tst>go test -v
2017/03/31 16:30:06 sql: unknown driver "postgres" (forgotten import?)
exit status 1
FAIL github.com/demas/cowl-go/tst 0.085s
Why ?
As already mentioned by #JimB in the comments, the error means that you're trying to open a db connection, using sqlx.Open, without first importing a db driver. This can be fixed by, in your case, adding this _ "github.com/lib/pq" import spec.
If, even after adding that import, you're still seeing the same error, then that means that one of your dependencies is also trying to open a db connection without first importing the necessary driver.
Please note that while log.Fatal is a nice and clean way to stop your program it can sometimes be lacking, as you already know. You might want to consider using panic instead, its output is much more chaotic but, on the other hand, you'll get the line number and file name that caused the panic and eventually you'll learn to parse it quickly.

Resources