9150f466e5
Characterization tests capturing current behavior before refactoring. Covers auth, config, logging, proxy, ratelimit, server, and telemetry packages with race-safe concurrent access tests.
179 lines
3.9 KiB
Go
179 lines
3.9 KiB
Go
package telemetry
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
otellog "go.opentelemetry.io/otel/log"
|
|
sdklog "go.opentelemetry.io/otel/sdk/log"
|
|
)
|
|
|
|
func TestMapSeverity(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want otellog.Severity
|
|
}{
|
|
{"trace", otellog.SeverityTrace},
|
|
{"debug", otellog.SeverityDebug},
|
|
{"info", otellog.SeverityInfo},
|
|
{"warn", otellog.SeverityWarn},
|
|
{"warning", otellog.SeverityWarn},
|
|
{"error", otellog.SeverityError},
|
|
{"fatal", otellog.SeverityFatal},
|
|
{"panic", otellog.SeverityFatal2},
|
|
{"unknown", otellog.SeverityInfo},
|
|
{"", otellog.SeverityInfo},
|
|
{"INFO", otellog.SeverityInfo}, // uppercase falls to default
|
|
{"PANIC", otellog.SeverityInfo}, // uppercase falls to default
|
|
{"gibberish", otellog.SeverityInfo},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run("level_"+tc.input, func(t *testing.T) {
|
|
got := mapSeverity(tc.input)
|
|
if got != tc.want {
|
|
t.Errorf("mapSeverity(%q) = %v, want %v", tc.input, got, tc.want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func newTestBridge(t *testing.T) *LogBridge {
|
|
t.Helper()
|
|
provider := sdklog.NewLoggerProvider()
|
|
t.Cleanup(func() {
|
|
_ = provider.Shutdown(t.Context())
|
|
})
|
|
return &LogBridge{provider: provider}
|
|
}
|
|
|
|
func TestLogBridgeWrite(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
input interface{} // will be marshaled to JSON; use string for raw input
|
|
raw string // if non-empty, use this directly instead of marshaling input
|
|
}{
|
|
{
|
|
name: "valid_json_with_message_level_and_extras",
|
|
input: map[string]interface{}{
|
|
"message": "request handled",
|
|
"level": "info",
|
|
"method": "GET",
|
|
"status": float64(200),
|
|
},
|
|
},
|
|
{
|
|
name: "message_only_no_level",
|
|
input: map[string]interface{}{
|
|
"message": "hello world",
|
|
},
|
|
},
|
|
{
|
|
name: "level_only_no_message",
|
|
input: map[string]interface{}{
|
|
"level": "error",
|
|
},
|
|
},
|
|
{
|
|
name: "empty_json_object",
|
|
input: map[string]interface{}{},
|
|
},
|
|
{
|
|
name: "string_float64_bool_attributes",
|
|
input: map[string]interface{}{
|
|
"message": "test",
|
|
"level": "debug",
|
|
"str_val": "hello",
|
|
"num_val": float64(3.14),
|
|
"bool_val": true,
|
|
},
|
|
},
|
|
{
|
|
name: "complex_nested_object_attribute",
|
|
input: map[string]interface{}{
|
|
"message": "nested",
|
|
"level": "warn",
|
|
"nested": map[string]interface{}{"foo": "bar", "n": float64(1)},
|
|
},
|
|
},
|
|
{
|
|
name: "time_field_skipped_in_attributes",
|
|
input: map[string]interface{}{
|
|
"message": "with time",
|
|
"level": "info",
|
|
"time": "2025-01-01T00:00:00Z",
|
|
"extra": "kept",
|
|
},
|
|
},
|
|
{
|
|
name: "malformed_json",
|
|
raw: "this is not json at all",
|
|
},
|
|
{
|
|
name: "malformed_json_partial",
|
|
raw: `{"broken":`,
|
|
},
|
|
{
|
|
name: "array_attribute_marshaled_as_string",
|
|
input: map[string]interface{}{
|
|
"message": "arrays",
|
|
"tags": []interface{}{"a", "b"},
|
|
},
|
|
},
|
|
{
|
|
name: "null_value_attribute",
|
|
input: map[string]interface{}{
|
|
"message": "nulls",
|
|
"val": nil,
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
bridge := newTestBridge(t)
|
|
|
|
var p []byte
|
|
if tc.raw != "" {
|
|
p = []byte(tc.raw)
|
|
} else {
|
|
var err error
|
|
p, err = json.Marshal(tc.input)
|
|
if err != nil {
|
|
t.Fatalf("failed to marshal test input: %v", err)
|
|
}
|
|
}
|
|
|
|
n, err := bridge.Write(p)
|
|
if n != len(p) {
|
|
t.Errorf("Write() returned n=%d, want %d", n, len(p))
|
|
}
|
|
if err != nil {
|
|
t.Errorf("Write() returned err=%v, want nil", err)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestLogBridgeWriteAlwaysReturnsLenAndNil(t *testing.T) {
|
|
bridge := newTestBridge(t)
|
|
|
|
inputs := [][]byte{
|
|
[]byte(`{"message":"ok","level":"info"}`),
|
|
[]byte(`not json`),
|
|
[]byte(`{}`),
|
|
[]byte(``),
|
|
[]byte(`[]`),
|
|
}
|
|
|
|
for _, p := range inputs {
|
|
n, err := bridge.Write(p)
|
|
if n != len(p) {
|
|
t.Errorf("Write(%q) n=%d, want %d", string(p), n, len(p))
|
|
}
|
|
if err != nil {
|
|
t.Errorf("Write(%q) err=%v, want nil", string(p), err)
|
|
}
|
|
}
|
|
}
|