1
0
Fork 0
telegraf/plugins/common/adx/adx_test.go
Daniel Baumann 4978089aab
Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 07:26:29 +02:00

219 lines
6.6 KiB
Go

package adx
import (
"bufio"
"context"
"encoding/json"
"io"
"testing"
"time"
"github.com/Azure/azure-kusto-go/kusto"
"github.com/Azure/azure-kusto-go/kusto/ingest"
"github.com/stretchr/testify/require"
"github.com/influxdata/telegraf"
"github.com/influxdata/telegraf/config"
serializers_json "github.com/influxdata/telegraf/plugins/serializers/json"
"github.com/influxdata/telegraf/testutil"
)
func TestInitBlankEndpointData(t *testing.T) {
plugin := Config{
Endpoint: "",
Database: "mydb",
}
_, err := plugin.NewClient("TestKusto.Telegraf", nil)
require.Error(t, err)
require.Equal(t, "endpoint configuration cannot be empty", err.Error())
}
func TestQueryConstruction(t *testing.T) {
const tableName = "mytable"
const expectedCreate = `.create-merge table ['mytable'] (['fields']:dynamic, ['name']:string, ['tags']:dynamic, ['timestamp']:datetime);`
const expectedMapping = `` +
`.create-or-alter table ['mytable'] ingestion json mapping 'mytable_mapping' '[{"column":"fields", ` +
`"Properties":{"Path":"$[\'fields\']"}},{"column":"name", "Properties":{"Path":"$[\'name\']"}},{"column":"tags", ` +
`"Properties":{"Path":"$[\'tags\']"}},{"column":"timestamp", "Properties":{"Path":"$[\'timestamp\']"}}]'`
require.Equal(t, expectedCreate, createTableCommand(tableName).String())
require.Equal(t, expectedMapping, createTableMappingCommand(tableName).String())
}
func TestGetMetricIngestor(t *testing.T) {
plugin := Client{
logger: testutil.Logger{},
client: kusto.NewMockClient(),
cfg: &Config{
Database: "mydb",
IngestionType: QueuedIngestion,
},
ingestors: map[string]ingest.Ingestor{"test1": &fakeIngestor{}},
}
ingestor, err := plugin.getMetricIngestor(t.Context(), "test1")
require.NoError(t, err)
require.NotNil(t, ingestor)
}
func TestGetMetricIngestorNoIngester(t *testing.T) {
plugin := Client{
logger: testutil.Logger{},
client: kusto.NewMockClient(),
cfg: &Config{
IngestionType: QueuedIngestion,
},
ingestors: map[string]ingest.Ingestor{"test1": &fakeIngestor{}},
}
ingestor, err := plugin.getMetricIngestor(t.Context(), "test1")
require.NoError(t, err)
require.NotNil(t, ingestor)
}
func TestPushMetrics(t *testing.T) {
plugin := Client{
logger: testutil.Logger{},
client: kusto.NewMockClient(),
cfg: &Config{
Database: "mydb",
Endpoint: "https://ingest-test.westus.kusto.windows.net",
IngestionType: QueuedIngestion,
},
ingestors: map[string]ingest.Ingestor{"test1": &fakeIngestor{}},
}
metrics := []byte(`{"fields": {"value": 1}, "name": "test1", "tags": {"tag1": "value1"}, "timestamp": "2021-01-01T00:00:00Z"}`)
require.NoError(t, plugin.PushMetrics(ingest.FileFormat(ingest.JSON), "test1", metrics))
}
func TestPushMetricsOutputs(t *testing.T) {
testCases := []struct {
name string
inputMetric []telegraf.Metric
metricsGrouping string
createTables bool
ingestionType string
}{
{
name: "Valid metric",
inputMetric: testutil.MockMetrics(),
createTables: true,
metricsGrouping: TablePerMetric,
},
{
name: "Don't create tables'",
inputMetric: testutil.MockMetrics(),
createTables: false,
metricsGrouping: TablePerMetric,
},
{
name: "SingleTable metric grouping type",
inputMetric: testutil.MockMetrics(),
createTables: true,
metricsGrouping: SingleTable,
},
{
name: "Valid metric managed ingestion",
inputMetric: testutil.MockMetrics(),
createTables: true,
metricsGrouping: TablePerMetric,
ingestionType: ManagedIngestion,
},
}
var expectedMetric = map[string]interface{}{
"metricName": "test1",
"fields": map[string]interface{}{
"value": 1.0,
},
"tags": map[string]interface{}{
"tag1": "value1",
},
"timestamp": float64(time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC).UnixNano() / int64(time.Second)),
}
for _, tC := range testCases {
t.Run(tC.name, func(t *testing.T) {
ingestionType := "queued"
if tC.ingestionType != "" {
ingestionType = tC.ingestionType
}
serializer := &serializers_json.Serializer{
TimestampUnits: config.Duration(time.Nanosecond),
TimestampFormat: time.RFC3339Nano,
}
cfg := &Config{
Endpoint: "https://someendpoint.kusto.net",
Database: "databasename",
MetricsGrouping: tC.metricsGrouping,
TableName: "test1",
CreateTables: tC.createTables,
IngestionType: ingestionType,
Timeout: config.Duration(20 * time.Second),
}
client, err := cfg.NewClient("telegraf", &testutil.Logger{})
require.NoError(t, err)
// Inject the ingestor
ingestor := &fakeIngestor{}
client.ingestors["test1"] = ingestor
tableMetricGroups := make(map[string][]byte)
mockmetrics := testutil.MockMetrics()
for _, m := range mockmetrics {
metricInBytes, err := serializer.Serialize(m)
require.NoError(t, err)
tableMetricGroups[m.Name()] = append(tableMetricGroups[m.Name()], metricInBytes...)
}
format := ingest.FileFormat(ingest.JSON)
for tableName, tableMetrics := range tableMetricGroups {
require.NoError(t, client.PushMetrics(format, tableName, tableMetrics))
createdFakeIngestor := ingestor
require.EqualValues(t, expectedMetric["metricName"], createdFakeIngestor.actualOutputMetric["name"])
require.EqualValues(t, expectedMetric["fields"], createdFakeIngestor.actualOutputMetric["fields"])
require.EqualValues(t, expectedMetric["tags"], createdFakeIngestor.actualOutputMetric["tags"])
timestampStr := createdFakeIngestor.actualOutputMetric["timestamp"].(string)
parsedTime, err := time.Parse(time.RFC3339Nano, timestampStr)
parsedTimeFloat := float64(parsedTime.UnixNano()) / 1e9
require.NoError(t, err)
require.InDelta(t, expectedMetric["timestamp"].(float64), parsedTimeFloat, testutil.DefaultDelta)
}
})
}
}
func TestAlreadyClosed(t *testing.T) {
plugin := Client{
logger: testutil.Logger{},
cfg: &Config{
IngestionType: QueuedIngestion,
},
client: kusto.NewMockClient(),
}
require.NoError(t, plugin.Close())
}
type fakeIngestor struct {
actualOutputMetric map[string]interface{}
}
func (f *fakeIngestor) FromReader(_ context.Context, reader io.Reader, _ ...ingest.FileOption) (*ingest.Result, error) {
scanner := bufio.NewScanner(reader)
scanner.Scan()
firstLine := scanner.Text()
err := json.Unmarshal([]byte(firstLine), &f.actualOutputMetric)
if err != nil {
return nil, err
}
return &ingest.Result{}, nil
}
func (*fakeIngestor) FromFile(_ context.Context, _ string, _ ...ingest.FileOption) (*ingest.Result, error) {
return &ingest.Result{}, nil
}
func (*fakeIngestor) Close() error {
return nil
}