Add middleware tests

This commit is contained in:
Deluan 2020-01-09 15:56:44 -05:00 committed by Deluan Quintão
parent 3379af4328
commit 6aa6c2d9a5
5 changed files with 160 additions and 121 deletions

15
api/api_suite_test.go Normal file
View file

@ -0,0 +1,15 @@
package api
import (
"testing"
"github.com/cloudsonic/sonic-server/log"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func TestSubsonicApi(t *testing.T) {
log.SetLevel(log.LevelError)
RegisterFailHandler(Fail)
RunSpecs(t, "Subsonic API Suite")
}

View file

@ -56,8 +56,7 @@ func authenticate(next http.Handler) http.Handler {
switch {
case pass != "":
if strings.HasPrefix(pass, "enc:") {
e := strings.TrimPrefix(pass, "enc:")
if dec, err := hex.DecodeString(e); err == nil {
if dec, err := hex.DecodeString(pass[4:]); err == nil {
pass = string(dec)
}
}

142
api/middlewares_test.go Normal file
View file

@ -0,0 +1,142 @@
package api
import (
"fmt"
"net/http"
"net/http/httptest"
"github.com/cloudsonic/sonic-server/conf"
"github.com/cloudsonic/sonic-server/log"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
)
func newRequest(queryParams string) *http.Request {
r := httptest.NewRequest("get", "/ping?"+queryParams, nil)
ctx := r.Context()
return r.WithContext(log.NewContext(ctx))
}
var _ = Describe("Middlewares", func() {
var next *mockHandler
var w *httptest.ResponseRecorder
BeforeEach(func() {
next = &mockHandler{}
w = httptest.NewRecorder()
})
Describe("CheckParams", func() {
It("passes when all required params are available", func() {
r := newRequest("u=user&v=1.15&c=test")
cp := checkRequiredParameters(next)
cp.ServeHTTP(w, r)
Expect(next.req.Context().Value("user")).To(Equal("user"))
Expect(next.req.Context().Value("version")).To(Equal("1.15"))
Expect(next.req.Context().Value("client")).To(Equal("test"))
Expect(next.called).To(BeTrue())
})
It("fails when user is missing", func() {
r := newRequest("v=1.15&c=test")
cp := checkRequiredParameters(next)
cp.ServeHTTP(w, r)
Expect(w.Body.String()).To(ContainSubstring(`code="10"`))
Expect(next.called).To(BeFalse())
})
It("fails when version is missing", func() {
r := newRequest("u=user&c=test")
cp := checkRequiredParameters(next)
cp.ServeHTTP(w, r)
Expect(w.Body.String()).To(ContainSubstring(`code="10"`))
Expect(next.called).To(BeFalse())
})
It("fails when client is missing", func() {
r := newRequest("u=user&v=1.15")
cp := checkRequiredParameters(next)
cp.ServeHTTP(w, r)
Expect(w.Body.String()).To(ContainSubstring(`code="10"`))
Expect(next.called).To(BeFalse())
})
})
Describe("Authenticate", func() {
BeforeEach(func() {
conf.Sonic.User = "admin"
conf.Sonic.Password = "wordpass"
conf.Sonic.DisableAuthentication = false
})
Context("Plaintext password", func() {
It("authenticates with plaintext password ", func() {
r := newRequest("u=admin&p=wordpass")
cp := authenticate(next)
cp.ServeHTTP(w, r)
Expect(next.called).To(BeTrue())
})
It("fails authentication with wrong password", func() {
r := newRequest("u=admin&p=INVALID")
cp := authenticate(next)
cp.ServeHTTP(w, r)
Expect(w.Body.String()).To(ContainSubstring(`code="40"`))
Expect(next.called).To(BeFalse())
})
})
Context("Encoded password", func() {
It("authenticates with simple encoded password ", func() {
r := newRequest("u=admin&p=enc:776f726470617373")
cp := authenticate(next)
cp.ServeHTTP(w, r)
Expect(next.called).To(BeTrue())
})
})
Context("Token based authentication", func() {
It("authenticates with token based authentication", func() {
token := "23b342970e25c7928831c3317edd0b67"
salt := "retnlmjetrymazgkt"
query := fmt.Sprintf("u=admin&t=%s&s=%s", token, salt)
r := newRequest(query)
cp := authenticate(next)
cp.ServeHTTP(w, r)
Expect(next.called).To(BeTrue())
})
It("fails if salt is missing", func() {
token := "23b342970e25c7928831c3317edd0b67"
query := fmt.Sprintf("u=admin&t=%s", token)
r := newRequest(query)
cp := authenticate(next)
cp.ServeHTTP(w, r)
Expect(w.Body.String()).To(ContainSubstring(`code="40"`))
Expect(next.called).To(BeFalse())
})
})
})
})
type mockHandler struct {
req *http.Request
called bool
}
func (mh *mockHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
mh.req = r
mh.called = true
}

View file

@ -1,117 +0,0 @@
package api_test
//
//import (
// "encoding/xml"
// "fmt"
// "testing"
//
// "context"
//
// "github.com/astaxie/beego"
// "github.com/cloudsonic/sonic-server/api"
// "github.com/cloudsonic/sonic-server/api/responses"
// "github.com/cloudsonic/sonic-server/tests"
// . "github.com/smartystreets/goconvey/convey"
//)
//
//func TestCheckParams(t *testing.T) {
// tests.Init(t, false)
//
// _, w := Get("/rest/ping.view", "TestCheckParams")
//
// Convey("Subject: CheckParams\n", t, func() {
// Convey("Status code should be 200", func() {
// So(w.Code, ShouldEqual, 200)
// })
// Convey("The errorCode should be 10", func() {
// So(w.Body.String(), ShouldContainSubstring, `error code="10" message=`)
// })
// Convey("The status should be 'fail'", func() {
// v := responses.Subsonic{}
// xml.Unmarshal(w.Body.Bytes(), &v)
// So(v.Status, ShouldEqual, "fail")
// })
// })
//}
//
//func TestAuthentication(t *testing.T) {
// tests.Init(t, false)
//
// Convey("Subject: Authentication", t, func() {
// _, w := Get("/rest/ping.view?u=INVALID&p=INVALID&c=test&v=1.0.0", "TestAuthentication")
// Convey("Status code should be 200", func() {
// So(w.Code, ShouldEqual, 200)
// })
// Convey("The errorCode should be 10", func() {
// So(w.Body.String(), ShouldContainSubstring, `error code="40" message=`)
// })
// Convey("The status should be 'fail'", func() {
// v := responses.Subsonic{}
// xml.Unmarshal(w.Body.Bytes(), &v)
// So(v.Status, ShouldEqual, "fail")
// })
// })
// Convey("Subject: Authentication Valid", t, func() {
// _, w := Get("/rest/ping.view?u=deluan&p=wordpass&c=test&v=1.0.0", "TestAuthentication")
// Convey("The status should be 'ok'", func() {
// v := responses.Subsonic{}
// xml.Unmarshal(w.Body.Bytes(), &v)
// So(v.Status, ShouldEqual, "ok")
// })
// })
// Convey("Subject: Password encoded", t, func() {
// _, w := Get("/rest/ping.view?u=deluan&p=enc:776f726470617373&c=test&v=1.0.0", "TestAuthentication")
// Convey("The status should be 'ok'", func() {
// v := responses.Subsonic{}
// xml.Unmarshal(w.Body.Bytes(), &v)
// So(v.Status, ShouldEqual, "ok")
// })
// })
// Convey("Subject: Token-based authentication", t, func() {
// salt := "retnlmjetrymazgkt"
// token := "23b342970e25c7928831c3317edd0b67"
// _, w := Get(fmt.Sprintf("/rest/ping.view?u=deluan&s=%s&t=%s&c=test&v=1.0.0", salt, token), "TestAuthentication")
// Convey("The status should be 'ok'", func() {
// v := responses.Subsonic{}
// xml.Unmarshal(w.Body.Bytes(), &v)
// So(v.Status, ShouldEqual, "ok")
// })
// })
//}
//
//type mockController struct {
// api.BaseAPIController
//}
//
//func (c *mockController) Get() {
// actualContext = c.Ctx.Input.GetData("context").(context.Context)
// c.Ctx.WriteString("OK")
//}
//
//var actualContext context.Context
//
//func TestContext(t *testing.T) {
// tests.Init(t, false)
// log.Router(r, "/rest/mocktest", &mockController{})
//
// Convey("Subject: Context", t, func() {
// _, w := GetWithHeader("/rest/mocktest?u=deluan&p=wordpass&c=testClient&v=1.0.0", "X-Request-Id", "123123", "TestContext")
// Convey("The status should be 'OK'", func() {
// resp := string(w.Body.Bytes())
// So(resp, ShouldEqual, "OK")
// })
// Convey("user should be set", func() {
// So(actualContext.Value("user"), ShouldEqual, "deluan")
// })
// Convey("client should be set", func() {
// So(actualContext.Value("client"), ShouldEqual, "testClient")
// })
// Convey("version should be set", func() {
// So(actualContext.Value("version"), ShouldEqual, "1.0.0")
// })
// Convey("context should be set", func() {
// So(actualContext.Value("requestId"), ShouldEqual, "123123")
// })
// })
//}

4
go.mod
View file

@ -19,8 +19,8 @@ require (
github.com/kennygrant/sanitize v0.0.0-20170120101633-6a0bfdde8629
github.com/koding/multiconfig v0.0.0-20170327155832-26b6dfd3a84a
github.com/nfnt/resize v0.0.0-20160724205520-891127d8d1b5
github.com/onsi/ginkgo v1.11.0 // indirect
github.com/onsi/gomega v1.8.1 // indirect
github.com/onsi/ginkgo v1.11.0
github.com/onsi/gomega v1.8.1
github.com/siddontang/go v0.0.0-20161005110831-1e9ce2a5ac40 // indirect
github.com/siddontang/ledisdb v0.0.0-20170318061737-5929802e2ea5
github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d // indirect