Fin/bench/parse_test.go

617 lines
11 KiB
Go

package scf_test
import (
"encoding/json"
"strconv"
"strings"
"testing"
config "git.sharkk.net/Go/SCF"
"github.com/BurntSushi/toml"
"gopkg.in/yaml.v3"
)
func BenchmarkSmallConfig(b *testing.B) {
// Small config with just a few key-value pairs
smallConfig := `
host "localhost"
port 8080
debug true
timeout 30
`
b.ResetTimer()
for i := 0; i < b.N; i++ {
reader := strings.NewReader(smallConfig)
_, err := config.Load(reader)
if err != nil {
b.Fatalf("Failed to parse small config: %v", err)
}
}
}
func BenchmarkMediumConfig(b *testing.B) {
// Medium config with nested structures and arrays
mediumConfig := `
app {
name "TestApp"
version "1.0.0"
enableLogging true
}
database {
host "db.example.com"
port 5432
credentials {
username "admin"
password "secure123"
}
}
features {
"authentication"
"authorization"
"reporting"
"analytics"
}
timeouts {
connect 5
read 10
write 10
idle 60
}
-- Comments to add some parsing overhead
endpoints {
api "/api/v1"
web "/web"
admin "/admin"
health "/health"
}
`
b.ResetTimer()
for i := 0; i < b.N; i++ {
reader := strings.NewReader(mediumConfig)
_, err := config.Load(reader)
if err != nil {
b.Fatalf("Failed to parse medium config: %v", err)
}
}
}
func BenchmarkLargeConfig(b *testing.B) {
// Simpler large config with careful bracket matching
largeConfig := `
application {
name "EnterpriseApp"
version "2.5.1"
environment "production"
debug false
maxConnections 1000
timeout 30
retryCount 3
logLevel "info"
}
-- Database cluster configuration
databases {
primary {
host "primary-db.example.com"
port 5432
maxConnections 100
credentials {
username "app_user"
password "super_secret"
ssl true
timeout 5
}
}
replica {
host "replica-db.example.com"
port 5432
maxConnections 200
credentials {
username "read_user"
password "read_only_pw"
ssl true
}
}
}
allowedIPs {
"192.168.1.1"
"192.168.1.2"
"192.168.1.3"
"192.168.1.4"
"192.168.1.5"
}
-- Add 50 numbered settings to make the config large
settings {`
// Add many numbered settings
var builder strings.Builder
builder.WriteString(largeConfig)
for i := 1; i <= 50; i++ {
builder.WriteString("\n\t\tsetting")
builder.WriteString(strconv.Itoa(i))
builder.WriteString(" ")
builder.WriteString(strconv.Itoa(i * 10))
}
// Close the settings block and add one more block
builder.WriteString(`
}
roles {
admin {
permissions {
"read"
"write"
"delete"
"admin"
}
}
user {
permissions {
"read"
"write"
}
}
}
`)
largeConfig = builder.String()
b.ResetTimer()
for i := 0; i < b.N; i++ {
reader := strings.NewReader(largeConfig)
_, err := config.Load(reader)
if err != nil {
b.Fatalf("Failed to parse large config: %v", err)
}
}
}
// JSON Benchmarks
func BenchmarkSmallConfigJSON(b *testing.B) {
smallConfigJSON := `{
"host": "localhost",
"port": 8080,
"debug": true,
"timeout": 30
}`
b.ResetTimer()
for i := 0; i < b.N; i++ {
reader := strings.NewReader(smallConfigJSON)
var result map[string]interface{}
decoder := json.NewDecoder(reader)
err := decoder.Decode(&result)
if err != nil {
b.Fatalf("Failed to parse small JSON config: %v", err)
}
}
}
func BenchmarkMediumConfigJSON(b *testing.B) {
mediumConfigJSON := `{
"app": {
"name": "TestApp",
"version": "1.0.0",
"enableLogging": true
},
"database": {
"host": "db.example.com",
"port": 5432,
"credentials": {
"username": "admin",
"password": "secure123"
}
},
"features": [
"authentication",
"authorization",
"reporting",
"analytics"
],
"timeouts": {
"connect": 5,
"read": 10,
"write": 10,
"idle": 60
},
"endpoints": {
"api": "/api/v1",
"web": "/web",
"admin": "/admin",
"health": "/health"
}
}`
b.ResetTimer()
for i := 0; i < b.N; i++ {
reader := strings.NewReader(mediumConfigJSON)
var result map[string]interface{}
decoder := json.NewDecoder(reader)
err := decoder.Decode(&result)
if err != nil {
b.Fatalf("Failed to parse medium JSON config: %v", err)
}
}
}
func BenchmarkLargeConfigJSON(b *testing.B) {
// Start building the large JSON config
largeConfigJSON := `{
"application": {
"name": "EnterpriseApp",
"version": "2.5.1",
"environment": "production",
"debug": false,
"maxConnections": 1000,
"timeout": 30,
"retryCount": 3,
"logLevel": "info"
},
"databases": {
"primary": {
"host": "primary-db.example.com",
"port": 5432,
"maxConnections": 100,
"credentials": {
"username": "app_user",
"password": "super_secret",
"ssl": true,
"timeout": 5
}
},
"replica": {
"host": "replica-db.example.com",
"port": 5432,
"maxConnections": 200,
"credentials": {
"username": "read_user",
"password": "read_only_pw",
"ssl": true
}
}
},
"allowedIPs": [
"192.168.1.1",
"192.168.1.2",
"192.168.1.3",
"192.168.1.4",
"192.168.1.5"
],
"settings": {`
var builder strings.Builder
builder.WriteString(largeConfigJSON)
// Add many numbered settings
for i := 1; i <= 50; i++ {
if i > 1 {
builder.WriteString(",")
}
builder.WriteString("\n\t\t\t\"setting")
builder.WriteString(strconv.Itoa(i))
builder.WriteString("\": ")
builder.WriteString(strconv.Itoa(i * 10))
}
// Close the settings block and add roles
builder.WriteString(`
},
"roles": {
"admin": {
"permissions": [
"read",
"write",
"delete",
"admin"
]
},
"user": {
"permissions": [
"read",
"write"
]
}
}
}`)
largeConfigJSONString := builder.String()
b.ResetTimer()
for i := 0; i < b.N; i++ {
reader := strings.NewReader(largeConfigJSONString)
var result map[string]interface{}
decoder := json.NewDecoder(reader)
err := decoder.Decode(&result)
if err != nil {
b.Fatalf("Failed to parse large JSON config: %v", err)
}
}
}
// YAML Benchmarks
func BenchmarkSmallConfigYAML(b *testing.B) {
smallConfigYAML := `
host: localhost
port: 8080
debug: true
timeout: 30
`
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result map[string]interface{}
err := yaml.Unmarshal([]byte(smallConfigYAML), &result)
if err != nil {
b.Fatalf("Failed to parse small YAML config: %v", err)
}
}
}
func BenchmarkMediumConfigYAML(b *testing.B) {
mediumConfigYAML := `
app:
name: TestApp
version: 1.0.0
enableLogging: true
database:
host: db.example.com
port: 5432
credentials:
username: admin
password: secure123
features:
- authentication
- authorization
- reporting
- analytics
timeouts:
connect: 5
read: 10
write: 10
idle: 60
# Comments to add some parsing overhead
endpoints:
api: /api/v1
web: /web
admin: /admin
health: /health
`
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result map[string]interface{}
err := yaml.Unmarshal([]byte(mediumConfigYAML), &result)
if err != nil {
b.Fatalf("Failed to parse medium YAML config: %v", err)
}
}
}
func BenchmarkLargeConfigYAML(b *testing.B) {
// Start building the large YAML config
largeConfigYAML := `
application:
name: EnterpriseApp
version: 2.5.1
environment: production
debug: false
maxConnections: 1000
timeout: 30
retryCount: 3
logLevel: info
# Database cluster configuration
databases:
primary:
host: primary-db.example.com
port: 5432
maxConnections: 100
credentials:
username: app_user
password: super_secret
ssl: true
timeout: 5
replica:
host: replica-db.example.com
port: 5432
maxConnections: 200
credentials:
username: read_user
password: read_only_pw
ssl: true
allowedIPs:
- 192.168.1.1
- 192.168.1.2
- 192.168.1.3
- 192.168.1.4
- 192.168.1.5
# Add 50 numbered settings to make the config large
settings:
`
var builder strings.Builder
builder.WriteString(largeConfigYAML)
// Add many numbered settings
for i := 1; i <= 50; i++ {
builder.WriteString(" setting")
builder.WriteString(strconv.Itoa(i))
builder.WriteString(": ")
builder.WriteString(strconv.Itoa(i * 10))
builder.WriteString("\n")
}
// Add roles
builder.WriteString(`
roles:
admin:
permissions:
- read
- write
- delete
- admin
user:
permissions:
- read
- write
`)
largeConfigYAMLString := builder.String()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result map[string]interface{}
err := yaml.Unmarshal([]byte(largeConfigYAMLString), &result)
if err != nil {
b.Fatalf("Failed to parse large YAML config: %v", err)
}
}
}
// TOML Benchmarks
func BenchmarkSmallConfigTOML(b *testing.B) {
smallConfigTOML := `
host = "localhost"
port = 8080
debug = true
timeout = 30
`
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result map[string]interface{}
err := toml.Unmarshal([]byte(smallConfigTOML), &result)
if err != nil {
b.Fatalf("Failed to parse small TOML config: %v", err)
}
}
}
func BenchmarkMediumConfigTOML(b *testing.B) {
mediumConfigTOML := `
[app]
name = "TestApp"
version = "1.0.0"
enableLogging = true
[database]
host = "db.example.com"
port = 5432
[database.credentials]
username = "admin"
password = "secure123"
features = ["authentication", "authorization", "reporting", "analytics"]
[timeouts]
connect = 5
read = 10
write = 10
idle = 60
# Comments to add some parsing overhead
[endpoints]
api = "/api/v1"
web = "/web"
admin = "/admin"
health = "/health"
`
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result map[string]interface{}
err := toml.Unmarshal([]byte(mediumConfigTOML), &result)
if err != nil {
b.Fatalf("Failed to parse medium TOML config: %v", err)
}
}
}
func BenchmarkLargeConfigTOML(b *testing.B) {
// Start building the large TOML config
largeConfigTOML := `
[application]
name = "EnterpriseApp"
version = "2.5.1"
environment = "production"
debug = false
maxConnections = 1000
timeout = 30
retryCount = 3
logLevel = "info"
# Database cluster configuration
[databases.primary]
host = "primary-db.example.com"
port = 5432
maxConnections = 100
[databases.primary.credentials]
username = "app_user"
password = "super_secret"
ssl = true
timeout = 5
[databases.replica]
host = "replica-db.example.com"
port = 5432
maxConnections = 200
[databases.replica.credentials]
username = "read_user"
password = "read_only_pw"
ssl = true
allowedIPs = ["192.168.1.1", "192.168.1.2", "192.168.1.3", "192.168.1.4", "192.168.1.5"]
# Add 50 numbered settings to make the config large
[settings]
`
var builder strings.Builder
builder.WriteString(largeConfigTOML)
// Add many numbered settings
for i := 1; i <= 50; i++ {
builder.WriteString("setting")
builder.WriteString(strconv.Itoa(i))
builder.WriteString(" = ")
builder.WriteString(strconv.Itoa(i * 10))
builder.WriteString("\n")
}
// Add roles
builder.WriteString(`
[roles.admin]
permissions = ["read", "write", "delete", "admin"]
[roles.user]
permissions = ["read", "write"]
`)
largeConfigTOMLString := builder.String()
b.ResetTimer()
for i := 0; i < b.N; i++ {
var result map[string]interface{}
err := toml.Unmarshal([]byte(largeConfigTOMLString), &result)
if err != nil {
b.Fatalf("Failed to parse large TOML config: %v", err)
}
}
}