mirror of
https://github.com/elyby/chrly.git
synced 2025-05-31 14:11:51 +05:30
Add stats reporter events listener, restore all events for http layer, rework authentication middleware and authenticator interface
This commit is contained in:
85
eventsubscribers/stats_reporter.go
Normal file
85
eventsubscribers/stats_reporter.go
Normal file
@@ -0,0 +1,85 @@
|
||||
package eventsubscribers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/mono83/slf"
|
||||
|
||||
"github.com/elyby/chrly/dispatcher"
|
||||
)
|
||||
|
||||
type StatsReporter struct {
|
||||
Reporter slf.StatsReporter
|
||||
Prefix string
|
||||
}
|
||||
|
||||
func (s *StatsReporter) ConfigureWithDispatcher(d dispatcher.EventDispatcher) {
|
||||
d.Subscribe("skinsystem:before_request", s.handleBeforeRequest)
|
||||
d.Subscribe("skinsystem:after_request", s.handleAfterRequest)
|
||||
|
||||
d.Subscribe("authenticator:success", s.incCounterHandler("authentication.challenge")) // TODO: legacy, remove in v5
|
||||
d.Subscribe("authenticator:success", s.incCounterHandler("authentication.success"))
|
||||
d.Subscribe("authentication:error", s.incCounterHandler("authentication.challenge")) // TODO: legacy, remove in v5
|
||||
d.Subscribe("authentication:error", s.incCounterHandler("authentication.failed"))
|
||||
}
|
||||
|
||||
func (s *StatsReporter) handleBeforeRequest(req *http.Request) {
|
||||
var key string
|
||||
m := req.Method
|
||||
p := req.URL.Path
|
||||
if p == "/skins" {
|
||||
key = "skins.get_request"
|
||||
} else if strings.HasPrefix(p, "/skins/") {
|
||||
key = "skins.request"
|
||||
} else if p == "/cloaks" {
|
||||
key = "capes.get_request"
|
||||
} else if strings.HasPrefix(p, "/cloaks/") {
|
||||
key = "capes.request"
|
||||
} else if strings.HasPrefix(p, "/textures/signed/") {
|
||||
key = "signed_textures.request"
|
||||
} else if strings.HasPrefix(p, "/textures/") {
|
||||
key = "textures.request"
|
||||
} else if m == http.MethodPost && p == "/api/skins" {
|
||||
key = "api.skins.post.request"
|
||||
} else if m == http.MethodDelete && strings.HasPrefix(p, "/api/skins/") {
|
||||
key = "api.skins.delete.request"
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
s.incCounter(key)
|
||||
}
|
||||
|
||||
func (s *StatsReporter) handleAfterRequest(req *http.Request, code int) {
|
||||
var key string
|
||||
m := req.Method
|
||||
p := req.URL.Path
|
||||
if m == http.MethodPost && p == "/api/skins" && code == http.StatusCreated {
|
||||
key = "api.skins.post.success"
|
||||
} else if m == http.MethodPost && p == "/api/skins" && code == http.StatusBadRequest {
|
||||
key = "api.skins.post.validation_failed"
|
||||
} else if m == http.MethodDelete && strings.HasPrefix(p, "/api/skins/") && code == http.StatusNoContent {
|
||||
key = "api.skins.delete.success"
|
||||
} else if m == http.MethodDelete && strings.HasPrefix(p, "/api/skins/") && code == http.StatusNotFound {
|
||||
key = "api.skins.delete.not_found"
|
||||
} else {
|
||||
return
|
||||
}
|
||||
|
||||
s.incCounter(key)
|
||||
}
|
||||
|
||||
func (s *StatsReporter) incCounterHandler(name string) func(...interface{}) {
|
||||
return func(...interface{}) {
|
||||
s.incCounter(name)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *StatsReporter) incCounter(name string) {
|
||||
s.Reporter.IncCounter(s.key(name), 1)
|
||||
}
|
||||
|
||||
func (s *StatsReporter) key(name string) string {
|
||||
return strings.Join([]string{s.Prefix, name}, ".")
|
||||
}
|
178
eventsubscribers/stats_reporter_test.go
Normal file
178
eventsubscribers/stats_reporter_test.go
Normal file
@@ -0,0 +1,178 @@
|
||||
package eventsubscribers
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"github.com/elyby/chrly/dispatcher"
|
||||
"github.com/elyby/chrly/tests"
|
||||
)
|
||||
|
||||
type StatsReporterTestCase struct {
|
||||
Topic string
|
||||
Args []interface{}
|
||||
ExpectedCalls [][]interface{}
|
||||
}
|
||||
|
||||
var statsReporterTestCases = []*StatsReporterTestCase{
|
||||
// Before request
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("GET", "http://localhost/skins/username", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.skins.request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("GET", "http://localhost/skins?name=username", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.skins.get_request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("GET", "http://localhost/cloaks/username", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.capes.request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("GET", "http://localhost/cloaks?name=username", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.capes.get_request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("GET", "http://localhost/textures/username", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.textures.request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("GET", "http://localhost/textures/signed/username", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.signed_textures.request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("POST", "http://localhost/api/skins", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.post.request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("DELETE", "http://localhost/api/skins/username", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.delete.request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("DELETE", "http://localhost/api/skins/id:1", nil)},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.delete.request", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:before_request",
|
||||
Args: []interface{}{httptest.NewRequest("GET", "http://localhost/unknown", nil)},
|
||||
ExpectedCalls: nil,
|
||||
},
|
||||
// After request
|
||||
{
|
||||
Topic: "skinsystem:after_request",
|
||||
Args: []interface{}{httptest.NewRequest("POST", "http://localhost/api/skins", nil), 201},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.post.success", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:after_request",
|
||||
Args: []interface{}{httptest.NewRequest("POST", "http://localhost/api/skins", nil), 400},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.post.validation_failed", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:after_request",
|
||||
Args: []interface{}{httptest.NewRequest("DELETE", "http://localhost/api/skins/username", nil), 204},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.delete.success", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:after_request",
|
||||
Args: []interface{}{httptest.NewRequest("DELETE", "http://localhost/api/skins/username", nil), 404},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.delete.not_found", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:after_request",
|
||||
Args: []interface{}{httptest.NewRequest("DELETE", "http://localhost/api/skins/id:1", nil), 204},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.delete.success", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:after_request",
|
||||
Args: []interface{}{httptest.NewRequest("DELETE", "http://localhost/api/skins/id:1", nil), 404},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.api.skins.delete.not_found", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "skinsystem:after_request",
|
||||
Args: []interface{}{httptest.NewRequest("DELETE", "http://localhost/unknown", nil), 404},
|
||||
ExpectedCalls: nil,
|
||||
},
|
||||
// Authenticator
|
||||
{
|
||||
Topic: "authenticator:success",
|
||||
Args: []interface{}{},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.authentication.challenge", int64(1)},
|
||||
{"IncCounter", "mock_prefix.authentication.success", int64(1)},
|
||||
},
|
||||
},
|
||||
{
|
||||
Topic: "authentication:error",
|
||||
Args: []interface{}{errors.New("error")},
|
||||
ExpectedCalls: [][]interface{}{
|
||||
{"IncCounter", "mock_prefix.authentication.challenge", int64(1)},
|
||||
{"IncCounter", "mock_prefix.authentication.failed", int64(1)},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func TestStatsReporter_handleHTTPRequest(t *testing.T) {
|
||||
for _, c := range statsReporterTestCases {
|
||||
t.Run(c.Topic, func(t *testing.T) {
|
||||
wdMock := &tests.WdMock{}
|
||||
if c.ExpectedCalls != nil {
|
||||
for _, c := range c.ExpectedCalls {
|
||||
topicName, _ := c[0].(string)
|
||||
wdMock.On(topicName, c[1:]...).Once()
|
||||
}
|
||||
}
|
||||
|
||||
reporter := &StatsReporter{
|
||||
Reporter: wdMock,
|
||||
Prefix: "mock_prefix",
|
||||
}
|
||||
|
||||
d := dispatcher.New()
|
||||
reporter.ConfigureWithDispatcher(d)
|
||||
d.Emit(c.Topic, c.Args...)
|
||||
|
||||
wdMock.AssertExpectations(t)
|
||||
})
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user