mirror of
https://git.mirrors.martin98.com/https://github.com/SigNoz/signoz
synced 2025-07-31 04:41:57 +08:00

All necessary changes so that whatever initalize SQL commans run, they are moved to bun so that it works with both sqlite and postgres.
250 lines
7.5 KiB
Go
250 lines
7.5 KiB
Go
package opamp
|
|
|
|
import (
|
|
"fmt"
|
|
"testing"
|
|
|
|
"github.com/knadh/koanf"
|
|
"github.com/knadh/koanf/parsers/yaml"
|
|
"github.com/knadh/koanf/providers/rawbytes"
|
|
_ "github.com/mattn/go-sqlite3"
|
|
"github.com/open-telemetry/opamp-go/protobufs"
|
|
"github.com/pkg/errors"
|
|
"github.com/stretchr/testify/require"
|
|
"go.signoz.io/signoz/pkg/query-service/app/opamp/model"
|
|
"go.signoz.io/signoz/pkg/query-service/utils"
|
|
"golang.org/x/exp/maps"
|
|
)
|
|
|
|
func TestOpAMPServerToAgentCommunicationWithConfigProvider(t *testing.T) {
|
|
require := require.New(t)
|
|
|
|
tb := newTestbed(t)
|
|
|
|
require.Equal(
|
|
0, len(tb.testConfigProvider.ConfigUpdateSubscribers),
|
|
"there should be no agent config subscribers at the start",
|
|
)
|
|
tb.StartServer()
|
|
require.Equal(
|
|
1, len(tb.testConfigProvider.ConfigUpdateSubscribers),
|
|
"Opamp server should have subscribed to updates from config provider after being started",
|
|
)
|
|
|
|
// Server should always respond with a RemoteConfig when an agent connects.
|
|
// Even if there are no recommended changes to the agent's initial config
|
|
require.False(tb.testConfigProvider.HasRecommendations())
|
|
agent1Conn := &MockOpAmpConnection{}
|
|
agent1Id := "testAgent1"
|
|
tb.opampServer.OnMessage(
|
|
agent1Conn,
|
|
&protobufs.AgentToServer{
|
|
InstanceUid: agent1Id,
|
|
EffectiveConfig: &protobufs.EffectiveConfig{
|
|
ConfigMap: initialAgentConf(),
|
|
},
|
|
},
|
|
)
|
|
lastAgent1Msg := agent1Conn.LatestMsgFromServer()
|
|
require.NotNil(
|
|
lastAgent1Msg,
|
|
"Server should always send a remote config to the agent when it connects",
|
|
)
|
|
require.Equal(
|
|
RemoteConfigBody(lastAgent1Msg),
|
|
string(initialAgentConf().ConfigMap[model.CollectorConfigFilename].Body),
|
|
)
|
|
|
|
tb.testConfigProvider.ZPagesEndpoint = "localhost:55555"
|
|
require.True(tb.testConfigProvider.HasRecommendations())
|
|
agent2Id := "testAgent2"
|
|
agent2Conn := &MockOpAmpConnection{}
|
|
tb.opampServer.OnMessage(
|
|
agent2Conn,
|
|
&protobufs.AgentToServer{
|
|
InstanceUid: agent2Id,
|
|
EffectiveConfig: &protobufs.EffectiveConfig{
|
|
ConfigMap: initialAgentConf(),
|
|
},
|
|
},
|
|
)
|
|
lastAgent2Msg := agent2Conn.LatestMsgFromServer()
|
|
require.NotNil(
|
|
lastAgent2Msg,
|
|
"server should recommend a config to agent when it connects",
|
|
)
|
|
|
|
recommendedEndpoint, err := GetStringValueFromYaml(
|
|
[]byte(RemoteConfigBody(lastAgent2Msg)), "extensions.zpages.endpoint",
|
|
)
|
|
require.Nil(err)
|
|
require.Equal(
|
|
tb.testConfigProvider.ZPagesEndpoint, recommendedEndpoint,
|
|
"server should send recommended config to agent when it connects",
|
|
)
|
|
|
|
agent2Conn.ClearMsgsFromServer()
|
|
tb.opampServer.OnMessage(agent2Conn, &protobufs.AgentToServer{
|
|
InstanceUid: agent2Id,
|
|
EffectiveConfig: &protobufs.EffectiveConfig{
|
|
ConfigMap: NewAgentConfigMap(
|
|
[]byte(RemoteConfigBody(lastAgent2Msg)),
|
|
),
|
|
},
|
|
RemoteConfigStatus: &protobufs.RemoteConfigStatus{
|
|
Status: protobufs.RemoteConfigStatuses_RemoteConfigStatuses_APPLIED,
|
|
LastRemoteConfigHash: lastAgent2Msg.RemoteConfig.ConfigHash,
|
|
},
|
|
})
|
|
expectedConfId := tb.testConfigProvider.ZPagesEndpoint
|
|
require.True(tb.testConfigProvider.HasReportedDeploymentStatus(expectedConfId, agent2Id),
|
|
"Server should report deployment success to config provider on receiving update from agent.",
|
|
)
|
|
require.True(tb.testConfigProvider.ReportedDeploymentStatuses[expectedConfId][agent2Id])
|
|
require.Nil(
|
|
agent2Conn.LatestMsgFromServer(),
|
|
"Server should not recommend a RemoteConfig if agent is already running it.",
|
|
)
|
|
|
|
// Server should rollout latest config to all agents when notified of a change by config provider
|
|
agent1Conn.ClearMsgsFromServer()
|
|
agent2Conn.ClearMsgsFromServer()
|
|
tb.testConfigProvider.ZPagesEndpoint = "localhost:66666"
|
|
tb.testConfigProvider.NotifySubscribersOfChange()
|
|
for _, agentConn := range []*MockOpAmpConnection{agent1Conn, agent2Conn} {
|
|
lastMsg := agentConn.LatestMsgFromServer()
|
|
|
|
recommendedEndpoint, err := GetStringValueFromYaml(
|
|
[]byte(RemoteConfigBody(lastMsg)), "extensions.zpages.endpoint",
|
|
)
|
|
require.Nil(err)
|
|
require.Equal(tb.testConfigProvider.ZPagesEndpoint, recommendedEndpoint)
|
|
}
|
|
|
|
lastAgent2Msg = agent2Conn.LatestMsgFromServer()
|
|
tb.opampServer.OnMessage(agent2Conn, &protobufs.AgentToServer{
|
|
InstanceUid: agent2Id,
|
|
RemoteConfigStatus: &protobufs.RemoteConfigStatus{
|
|
Status: protobufs.RemoteConfigStatuses_RemoteConfigStatuses_FAILED,
|
|
LastRemoteConfigHash: lastAgent2Msg.RemoteConfig.ConfigHash,
|
|
},
|
|
})
|
|
expectedConfId = tb.testConfigProvider.ZPagesEndpoint
|
|
require.True(tb.testConfigProvider.HasReportedDeploymentStatus(expectedConfId, agent2Id),
|
|
"Server should report deployment failure to config provider on receiving update from agent.",
|
|
)
|
|
require.False(tb.testConfigProvider.ReportedDeploymentStatuses[expectedConfId][agent2Id])
|
|
|
|
lastAgent1Msg = agent1Conn.LatestMsgFromServer()
|
|
agent1Conn.ClearMsgsFromServer()
|
|
response := tb.opampServer.OnMessage(agent1Conn, &protobufs.AgentToServer{
|
|
InstanceUid: agent1Id,
|
|
RemoteConfigStatus: &protobufs.RemoteConfigStatus{
|
|
Status: protobufs.RemoteConfigStatuses_RemoteConfigStatuses_APPLIED,
|
|
LastRemoteConfigHash: lastAgent1Msg.RemoteConfig.ConfigHash,
|
|
},
|
|
})
|
|
require.Nil(response.RemoteConfig)
|
|
require.Nil(
|
|
agent1Conn.LatestMsgFromServer(),
|
|
"server should not recommend a config if agent is reporting back with status on a broadcasted config",
|
|
)
|
|
|
|
require.Equal(1, len(tb.testConfigProvider.ConfigUpdateSubscribers))
|
|
tb.opampServer.Stop()
|
|
require.Equal(
|
|
0, len(tb.testConfigProvider.ConfigUpdateSubscribers),
|
|
"Opamp server should have unsubscribed to config provider updates after shutdown",
|
|
)
|
|
}
|
|
|
|
type testbed struct {
|
|
testConfigProvider *MockAgentConfigProvider
|
|
opampServer *Server
|
|
t *testing.T
|
|
}
|
|
|
|
func newTestbed(t *testing.T) *testbed {
|
|
testDB := utils.NewQueryServiceDBForTests(t)
|
|
_, err := model.InitDB(testDB.SQLxDB())
|
|
if err != nil {
|
|
t.Fatalf("could not init opamp model: %v", err)
|
|
}
|
|
|
|
testConfigProvider := NewMockAgentConfigProvider()
|
|
opampServer := InitializeServer(nil, testConfigProvider)
|
|
|
|
return &testbed{
|
|
testConfigProvider: testConfigProvider,
|
|
opampServer: opampServer,
|
|
t: t,
|
|
}
|
|
}
|
|
|
|
func (tb *testbed) StartServer() {
|
|
testListenPath := GetAvailableLocalAddress()
|
|
err := tb.opampServer.Start(testListenPath)
|
|
require.Nil(tb.t, err, "should be able to start opamp server")
|
|
}
|
|
|
|
// Test helper
|
|
func GetStringValueFromYaml(
|
|
serializedYaml []byte, path string,
|
|
) (string, error) {
|
|
if len(serializedYaml) < 1 {
|
|
return "", fmt.Errorf("yaml data is empty")
|
|
}
|
|
|
|
k := koanf.New(".")
|
|
err := k.Load(rawbytes.Provider(serializedYaml), yaml.Parser())
|
|
if err != nil {
|
|
return "", errors.Wrap(err, "could not unmarshal collector config")
|
|
}
|
|
|
|
return k.String("extensions.zpages.endpoint"), nil
|
|
}
|
|
|
|
// Returns body of a ServerToAgent.RemoteConfig or ""
|
|
func RemoteConfigBody(msg *protobufs.ServerToAgent) string {
|
|
if msg == nil {
|
|
return ""
|
|
}
|
|
|
|
collectorConfFiles := msg.RemoteConfig.Config.ConfigMap
|
|
if len(collectorConfFiles) < 1 {
|
|
return ""
|
|
}
|
|
return string(maps.Values(collectorConfFiles)[0].Body)
|
|
}
|
|
|
|
func NewAgentConfigMap(body []byte) *protobufs.AgentConfigMap {
|
|
return &protobufs.AgentConfigMap{
|
|
ConfigMap: map[string]*protobufs.AgentConfigFile{
|
|
model.CollectorConfigFilename: {
|
|
Body: body,
|
|
ContentType: "text/yaml",
|
|
},
|
|
},
|
|
}
|
|
|
|
}
|
|
|
|
func initialAgentConf() *protobufs.AgentConfigMap {
|
|
return NewAgentConfigMap(
|
|
[]byte(`
|
|
receivers:
|
|
otlp:
|
|
processors:
|
|
batch:
|
|
exporters:
|
|
otlp:
|
|
service:
|
|
pipelines:
|
|
logs:
|
|
receivers: [otlp]
|
|
processors: [batch]
|
|
exporters: [otlp]
|
|
`),
|
|
)
|
|
}
|