Add CI/publish workflows, tracer tests, fix Go version in CLAUDE.md
All checks were successful
CI / test (push) Successful in 54s
All checks were successful
CI / test (push) Successful in 54s
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
23
.gitea/workflows/ci.yml
Normal file
23
.gitea/workflows/ci.yml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
name: CI
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main]
|
||||||
|
pull_request:
|
||||||
|
branches: [main]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
- name: Vet
|
||||||
|
run: go vet ./...
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: go test -race -count=1 ./...
|
||||||
39
.gitea/workflows/publish.yml
Normal file
39
.gitea/workflows/publish.yml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
name: Publish
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags: ["v*"]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-go@v5
|
||||||
|
with:
|
||||||
|
go-version-file: go.mod
|
||||||
|
|
||||||
|
- name: Vet
|
||||||
|
run: go vet ./...
|
||||||
|
|
||||||
|
- name: Test
|
||||||
|
run: go test -race -count=1 ./...
|
||||||
|
|
||||||
|
- name: Publish to Gitea Package Registry
|
||||||
|
run: |
|
||||||
|
VERSION=${GITHUB_REF#refs/tags/}
|
||||||
|
MODULE=$(go list -m)
|
||||||
|
|
||||||
|
# Create module zip with required prefix: module@version/
|
||||||
|
git archive --format=zip --prefix="${MODULE}@${VERSION}/" HEAD -o module.zip
|
||||||
|
|
||||||
|
# Gitea Go Package Registry API
|
||||||
|
curl -s -f \
|
||||||
|
-X PUT \
|
||||||
|
-H "Authorization: token ${{ secrets.PUBLISH_TOKEN }}" \
|
||||||
|
-H "Content-Type: application/zip" \
|
||||||
|
--data-binary @module.zip \
|
||||||
|
"${{ github.server_url }}/api/packages/pkg/go/upload?module=${MODULE}&version=${VERSION}"
|
||||||
|
env:
|
||||||
|
PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }}
|
||||||
@@ -12,7 +12,7 @@ go vet ./... # static analysis
|
|||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- **Module**: `git.codelab.vc/pkg/obsx`, Go 1.24, depends on OpenTelemetry and Prometheus client_golang
|
- **Module**: `git.codelab.vc/pkg/obsx`, Go 1.25.7, depends on OpenTelemetry and Prometheus client_golang
|
||||||
- **Single package** `obsx`
|
- **Single package** `obsx`
|
||||||
|
|
||||||
### Core patterns
|
### Core patterns
|
||||||
|
|||||||
124
tracer_test.go
Normal file
124
tracer_test.go
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
package obsx
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||||
|
"go.opentelemetry.io/otel/sdk/trace/tracetest"
|
||||||
|
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setupTestTracer(t *testing.T) *tracetest.InMemoryExporter {
|
||||||
|
t.Helper()
|
||||||
|
exp := tracetest.NewInMemoryExporter()
|
||||||
|
tp := sdktrace.NewTracerProvider(sdktrace.WithSyncer(exp))
|
||||||
|
otel.SetTracerProvider(tp)
|
||||||
|
t.Cleanup(func() { _ = tp.Shutdown(context.Background()) })
|
||||||
|
return exp
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetupTracer_SetsGlobalProvider(t *testing.T) {
|
||||||
|
prev := otel.GetTracerProvider()
|
||||||
|
t.Cleanup(func() { otel.SetTracerProvider(prev) })
|
||||||
|
|
||||||
|
cfg := TracerConfig{
|
||||||
|
ServiceName: "test-service",
|
||||||
|
Endpoint: "localhost:4317",
|
||||||
|
}
|
||||||
|
|
||||||
|
shutdown, err := SetupTracer(context.Background(), cfg)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("SetupTracer returned error: %v", err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() { _ = shutdown(context.Background()) })
|
||||||
|
|
||||||
|
tp := otel.GetTracerProvider()
|
||||||
|
if _, ok := tp.(*sdktrace.TracerProvider); !ok {
|
||||||
|
t.Errorf("expected *sdktrace.TracerProvider, got %T", tp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetupTracer_DefaultSampler(t *testing.T) {
|
||||||
|
cfg := TracerConfig{Sampler: 0}
|
||||||
|
cfg.defaults()
|
||||||
|
|
||||||
|
if cfg.Sampler != 1.0 {
|
||||||
|
t.Errorf("expected default sampler=1.0, got %f", cfg.Sampler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetupTracer_NegativeSampler(t *testing.T) {
|
||||||
|
cfg := TracerConfig{Sampler: -0.5}
|
||||||
|
cfg.defaults()
|
||||||
|
|
||||||
|
if cfg.Sampler != 1.0 {
|
||||||
|
t.Errorf("expected default sampler=1.0 for negative value, got %f", cfg.Sampler)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSetupTracer_ServiceVersion(t *testing.T) {
|
||||||
|
prev := otel.GetTracerProvider()
|
||||||
|
t.Cleanup(func() { otel.SetTracerProvider(prev) })
|
||||||
|
|
||||||
|
exp := tracetest.NewInMemoryExporter()
|
||||||
|
|
||||||
|
res, err := resource.New(context.Background(),
|
||||||
|
resource.WithAttributes(
|
||||||
|
semconv.ServiceName("version-test"),
|
||||||
|
semconv.ServiceVersion("1.2.3"),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("resource.New returned error: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tp := sdktrace.NewTracerProvider(
|
||||||
|
sdktrace.WithSyncer(exp),
|
||||||
|
sdktrace.WithResource(res),
|
||||||
|
)
|
||||||
|
otel.SetTracerProvider(tp)
|
||||||
|
t.Cleanup(func() { _ = tp.Shutdown(context.Background()) })
|
||||||
|
|
||||||
|
_, span := StartSpan(context.Background(), "test-span")
|
||||||
|
span.End()
|
||||||
|
|
||||||
|
spans := exp.GetSpans()
|
||||||
|
if len(spans) == 0 {
|
||||||
|
t.Fatal("expected at least one span")
|
||||||
|
}
|
||||||
|
|
||||||
|
found := false
|
||||||
|
for _, attr := range spans[0].Resource.Attributes() {
|
||||||
|
if string(attr.Key) == "service.version" && attr.Value.AsString() == "1.2.3" {
|
||||||
|
found = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("service.version=1.2.3 not found in resource attributes: %v", spans[0].Resource.Attributes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestStartSpan_CreatesSpan(t *testing.T) {
|
||||||
|
prev := otel.GetTracerProvider()
|
||||||
|
t.Cleanup(func() { otel.SetTracerProvider(prev) })
|
||||||
|
|
||||||
|
exp := setupTestTracer(t)
|
||||||
|
|
||||||
|
ctx, span := StartSpan(context.Background(), "my-operation")
|
||||||
|
if ctx == nil {
|
||||||
|
t.Fatal("StartSpan returned nil context")
|
||||||
|
}
|
||||||
|
span.End()
|
||||||
|
|
||||||
|
spans := exp.GetSpans()
|
||||||
|
if len(spans) == 0 {
|
||||||
|
t.Fatal("expected at least one span")
|
||||||
|
}
|
||||||
|
if spans[0].Name != "my-operation" {
|
||||||
|
t.Errorf("expected span name 'my-operation', got %q", spans[0].Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user