Skip to content

Commit

Permalink
[beater] Restructure beater package and some more test
Browse files Browse the repository at this point in the history
Create several packages inside the beater directory to better organize
http framework logic. Adapt tests and code to new structure.

related to elastic#2489
  • Loading branch information
simitt committed Aug 5, 2019
1 parent e0136d5 commit 62b7d1c
Show file tree
Hide file tree
Showing 95 changed files with 1,635 additions and 1,070 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.

package beater
package sourcemap

import (
"strings"
Expand All @@ -30,8 +30,8 @@ import (
"github.com/elastic/apm-server/utility"
)

// AssetHandler returns a request.Handler for managing asset requests.
func AssetHandler(dec decoder.ReqDecoder, processor asset.Processor, cfg transform.Config, report publish.Reporter) request.Handler {
// Handler returns a request.Handler for managing asset requests.
func Handler(dec decoder.ReqDecoder, processor asset.Processor, cfg transform.Config, report publish.Reporter) request.Handler {
return func(c *request.Context) {
if c.Request.Method != "POST" {
c.Result.SetDefault(request.IDResponseErrorsMethodNotAllowed)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.

package beater
package sourcemap

import (
"context"
Expand All @@ -37,7 +37,7 @@ import (
"github.com/elastic/apm-server/transform"
)

func TestNewAssetHandler(t *testing.T) {
func TestAssetHandler(t *testing.T) {

testcases := map[string]testcaseT{
"method": {
Expand Down Expand Up @@ -136,7 +136,7 @@ func (tc *testcaseT) setup() {
}
c := &request.Context{}
c.Reset(tc.w, tc.r)
h := AssetHandler(tc.dec, tc.processor, transform.Config{}, tc.reporter)
h := Handler(tc.dec, tc.processor, transform.Config{}, tc.reporter)
h(c)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,20 @@
// specific language governing permissions and limitations
// under the License.

package beater
package agent

import (
"fmt"
"net/http"
"strings"
"time"

"github.com/elastic/beats/libbeat/monitoring"

"github.com/elastic/beats/libbeat/common"

"github.com/pkg/errors"

"github.com/elastic/apm-server/agentcfg"
"github.com/elastic/apm-server/beater/config"
"github.com/elastic/apm-server/beater/headers"
"github.com/elastic/apm-server/beater/request"
"github.com/elastic/apm-server/convert"
Expand All @@ -53,33 +52,10 @@ var (

minKibanaVersion = common.MustNewVersion("7.3.0")
errCacheControl = fmt.Sprintf("max-age=%v, must-revalidate", errMaxAgeDuration.Seconds())

//TODO: change logic for acm specific monitoring counters
//will be done in a follow up PR to avoid changing logic here
//serverMetrics = monitoring.Default.NewRegistry("apm-server.server.acm", monitoring.PublishExpvar)
//counter = func(s request.ResultID) *monitoring.Int {
// return monitoring.NewInt(serverMetrics, string(s))
//}

// reflects current behavior
countRequest = IntakeResultIDToMonitoringInt(request.IDRequestCount)

mapping = map[request.ResultID]*monitoring.Int{
request.IDRequestCount: countRequest,
}
)

// ACMResultIDToMonitoringInt takes a request.ResultID and maps it to a monitoring counter. If no mapping is found,
// nil is returned.
func ACMResultIDToMonitoringInt(id request.ResultID) *monitoring.Int {
if i, ok := mapping[id]; ok {
return i
}
return nil
}

// AgentConfigHandler returns a request.Handler for managing ACM requests.
func AgentConfigHandler(kbClient kibana.Client, config *AgentConfig) request.Handler {
// Handler returns a request.Handler for managing agent central configuration requests.
func Handler(kbClient kibana.Client, config *config.AgentConfig) request.Handler {
cacheControl := fmt.Sprintf("max-age=%v, must-revalidate", config.Cache.Expiration.Seconds())
fetcher := agentcfg.NewFetcher(kbClient, config.Cache.Expiration)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.

package beater
package agent

import (
"crypto/md5"
Expand All @@ -34,6 +34,7 @@ import (

"github.com/elastic/apm-server/agentcfg"
"github.com/elastic/apm-server/beater/beatertest"
"github.com/elastic/apm-server/beater/config"
"github.com/elastic/apm-server/beater/headers"
"github.com/elastic/apm-server/beater/request"
"github.com/elastic/apm-server/convert"
Expand Down Expand Up @@ -168,12 +169,12 @@ var (
)

func TestAgentConfigHandler(t *testing.T) {
var cfg = AgentConfig{Cache: &Cache{Expiration: 4 * time.Second}}
var cfg = config.AgentConfig{Cache: &config.Cache{Expiration: 4 * time.Second}}

for name, tc := range testcases {

runTest := func(t *testing.T, body string, tokenSet bool) {
h := AgentConfigHandler(tc.kbClient, &cfg)
h := Handler(tc.kbClient, &cfg)
w := httptest.NewRecorder()
r := httptest.NewRequest(tc.method, target(tc.queryParams), nil)
for k, v := range tc.requestHeader {
Expand Down Expand Up @@ -206,8 +207,8 @@ func TestAgentConfigHandler(t *testing.T) {
}
}
func TestAgentConfigHandler_NoKibanaClient(t *testing.T) {
cfg := AgentConfig{Cache: &Cache{Expiration: time.Nanosecond}}
h := AgentConfigHandler(nil, &cfg)
cfg := config.AgentConfig{Cache: &config.Cache{Expiration: time.Nanosecond}}
h := Handler(nil, &cfg)

w := httptest.NewRecorder()
ctx := &request.Context{}
Expand All @@ -228,8 +229,8 @@ func TestAgentConfigHandler_PostOk(t *testing.T) {
},
}, mockVersion, true)

var cfg = AgentConfig{Cache: &Cache{Expiration: time.Nanosecond}}
h := AgentConfigHandler(kb, &cfg)
var cfg = config.AgentConfig{Cache: &config.Cache{Expiration: time.Nanosecond}}
h := Handler(kb, &cfg)

w := httptest.NewRecorder()
r := httptest.NewRequest(http.MethodPost, "/config", convert.ToReader(m{
Expand All @@ -241,16 +242,6 @@ func TestAgentConfigHandler_PostOk(t *testing.T) {
assert.Equal(t, http.StatusOK, w.Code, w.Body.String())
}

func TestACMResultIdToMonitoringInt(t *testing.T) {
for _, id := range beatertest.AllRequestResultIDs() {
if id == request.IDRequestCount {
assert.NotNil(t, ACMResultIDToMonitoringInt(id))
} else {
assert.Nil(t, ACMResultIDToMonitoringInt(id))
}
}
}

func target(params map[string]string) string {
t := "/config"
if len(params) == 0 {
Expand Down
51 changes: 51 additions & 0 deletions beater/api/config/agent/monitoring.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package agent

import (
"github.com/elastic/beats/libbeat/monitoring"

"github.com/elastic/apm-server/beater/api/intake"
"github.com/elastic/apm-server/beater/request"
)

var (

//TODO: change logic for acm specific monitoring counters
//will be done in a follow up PR to avoid changing logic here
//serverMetrics = monitoring.Default.NewRegistry("apm-server.server.acm", monitoring.PublishExpvar)
//counter = func(s request.ResultID) *monitoring.Int {
// return monitoring.NewInt(serverMetrics, string(s))
//}

// reflects current behavior
countRequest = intake.ResultIDToMonitoringInt(request.IDRequestCount)

mapping = map[request.ResultID]*monitoring.Int{
request.IDRequestCount: countRequest,
}
)

// ResultIDToMonitoringInt takes a request.ResultID and maps it to a monitoring counter. If no mapping is found,
// nil is returned.
func ResultIDToMonitoringInt(id request.ResultID) *monitoring.Int {
if i, ok := mapping[id]; ok {
return i
}
return nil
}
38 changes: 38 additions & 0 deletions beater/api/config/agent/monitoring_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.

package agent

import (
"testing"

"github.com/stretchr/testify/assert"

"github.com/elastic/apm-server/beater/beatertest"
"github.com/elastic/apm-server/beater/request"
)

func TestResultIdToMonitoringInt(t *testing.T) {
for _, id := range beatertest.AllRequestResultIDs() {
counter := ResultIDToMonitoringInt(id)
if id == request.IDRequestCount {
assert.NotNil(t, counter, string(id))
} else {
assert.Nil(t, counter, string(id))
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
// specific language governing permissions and limitations
// under the License.

package beater
package api

import (
"net/http"
Expand All @@ -28,86 +28,90 @@ import (

"github.com/stretchr/testify/require"

"github.com/elastic/apm-server/beater/api/config/agent"
"github.com/elastic/apm-server/beater/api/intake"
"github.com/elastic/apm-server/beater/beatertest"
"github.com/elastic/apm-server/beater/config"
"github.com/elastic/apm-server/beater/headers"
"github.com/elastic/apm-server/beater/request"
"github.com/elastic/apm-server/tests"
)

func TestAgentConfigHandler_RequireAuthorizationMiddleware(t *testing.T) {
func TestConfigAgentHandler_AuthorizationMiddleware(t *testing.T) {
t.Run("Unauthorized", func(t *testing.T) {
cfg := cfgEnabledACM()
cfg := configEnabledConfigAgent()
cfg.SecretToken = "1234"
rec := requestToACMHandler(t, cfg)
rec := requestToConfigAgentHandler(t, cfg)

assert.Equal(t, http.StatusUnauthorized, rec.Code)
tests.AssertApproveResult(t, acmApprovalPath(t.Name()), rec.Body.Bytes())
tests.AssertApproveResult(t, approvalPathConfigAgent(t.Name()), rec.Body.Bytes())
})

t.Run("Authorized", func(t *testing.T) {
cfg := cfgEnabledACM()
cfg := configEnabledConfigAgent()
cfg.SecretToken = "1234"
h, err := agentConfigHandler(cfg, beatertest.NilReporter)
h, err := configAgentHandler(cfg, beatertest.NilReporter)
require.NoError(t, err)
c, rec := beatertest.DefaultContextWithResponseRecorder()
c.Request.Header.Set(headers.Authorization, "Bearer 1234")
h(c)

assert.Equal(t, http.StatusServiceUnavailable, rec.Code)
tests.AssertApproveResult(t, acmApprovalPath(t.Name()), rec.Body.Bytes())
tests.AssertApproveResult(t, approvalPathConfigAgent(t.Name()), rec.Body.Bytes())
})
}

func TestAgentConfigHandler_KillSwitchMiddleware(t *testing.T) {
func TestConfigAgentHandler_KillSwitchMiddleware(t *testing.T) {
t.Run("Off", func(t *testing.T) {
rec := requestToACMHandler(t, DefaultConfig(beatertest.MockBeatVersion()))
rec := requestToConfigAgentHandler(t, config.DefaultConfig(beatertest.MockBeatVersion()))

assert.Equal(t, http.StatusForbidden, rec.Code)
tests.AssertApproveResult(t, acmApprovalPath(t.Name()), rec.Body.Bytes())
tests.AssertApproveResult(t, approvalPathConfigAgent(t.Name()), rec.Body.Bytes())

})

t.Run("On", func(t *testing.T) {
rec := requestToACMHandler(t, cfgEnabledACM())
rec := requestToConfigAgentHandler(t, configEnabledConfigAgent())

assert.Equal(t, http.StatusServiceUnavailable, rec.Code)
tests.AssertApproveResult(t, acmApprovalPath(t.Name()), rec.Body.Bytes())
tests.AssertApproveResult(t, approvalPathConfigAgent(t.Name()), rec.Body.Bytes())
})
}

func TestAgentConfigHandler_PanicMiddleware(t *testing.T) {
h, err := agentConfigHandler(DefaultConfig(beatertest.MockBeatVersion()), beatertest.NilReporter)
func TestConfigAgentHandler_PanicMiddleware(t *testing.T) {
h, err := configAgentHandler(config.DefaultConfig(beatertest.MockBeatVersion()), beatertest.NilReporter)
require.NoError(t, err)
rec := &beatertest.WriterPanicOnce{}
c := &request.Context{}
c.Reset(rec, httptest.NewRequest(http.MethodGet, "/", nil))
h(c)
assert.Equal(t, http.StatusInternalServerError, rec.StatusCode)
tests.AssertApproveResult(t, acmApprovalPath(t.Name()), rec.Body.Bytes())
tests.AssertApproveResult(t, approvalPathConfigAgent(t.Name()), rec.Body.Bytes())
}

func TestAgentConfigHandler_MonitoringMiddleware(t *testing.T) {
h, err := agentConfigHandler(DefaultConfig(beatertest.MockBeatVersion()), beatertest.NilReporter)
func TestConfigAgentHandler_MonitoringMiddleware(t *testing.T) {
h, err := configAgentHandler(config.DefaultConfig(beatertest.MockBeatVersion()), beatertest.NilReporter)
require.NoError(t, err)
c, _ := beatertest.DefaultContextWithResponseRecorder()
c, _ := beatertest.ContextWithResponseRecorder(http.MethodPost, "/")

expected := map[request.ResultID]int{request.IDRequestCount: 1}
equal, result := beatertest.CompareMonitoringInt(h, c, expected, serverMetrics, ACMResultIDToMonitoringInt)
equal, result := beatertest.CompareMonitoringInt(h, c, expected, intake.MonitoringRegistry, agent.ResultIDToMonitoringInt)
assert.True(t, equal, result)

}

func requestToACMHandler(t *testing.T, cfg *Config) *httptest.ResponseRecorder {
h, err := agentConfigHandler(cfg, beatertest.NilReporter)
func requestToConfigAgentHandler(t *testing.T, cfg *config.Config) *httptest.ResponseRecorder {
h, err := configAgentHandler(cfg, beatertest.NilReporter)
require.NoError(t, err)
c, rec := beatertest.DefaultContextWithResponseRecorder()
h(c)
return rec
}

func cfgEnabledACM() *Config {
cfg := DefaultConfig(beatertest.MockBeatVersion())
func configEnabledConfigAgent() *config.Config {
cfg := config.DefaultConfig(beatertest.MockBeatVersion())
cfg.Kibana = common.MustNewConfigFrom(map[string]interface{}{"enabled": "true"})
return cfg
}

func acmApprovalPath(f string) string { return "test_integration/acm/" + f }
func approvalPathConfigAgent(f string) string { return "config/agent/test_approved/integration/" + f }
Loading

0 comments on commit 62b7d1c

Please sign in to comment.