AdGuardHome/internal/home/upgrade_test.go
Dimitry Kolyshev 5a195b441c Pull request: log-yaml-conf
Updates #4897.

Squashed commit of the following:

commit 8a961157c9930bf4859ce2209e5016ce94987e12
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Jul 5 10:13:24 2023 +0400

    home: imp code

commit 509c07eed06311d773bc3e34b3ca28d9f14186fe
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Jul 4 17:33:31 2023 +0400

    all: fix

commit f032e28f98552f238721491c998fca2d7d4b9802
Merge: ee0113435 c46516475
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Jul 4 17:31:29 2023 +0400

    Merge remote-tracking branch 'origin/master' into log-yaml-conf

    # Conflicts:
    #	CHANGELOG.md

commit ee011343512e82d4e21cb402759d0284523ba02a
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Jul 4 12:31:42 2023 +0400

    all: changelog

commit 07f4c4a244b1b6200d3056cde5ebced6254084a7
Merge: 2042c0753 97af062f7
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Tue Jul 4 12:25:21 2023 +0400

    Merge remote-tracking branch 'origin/master' into log-yaml-conf

commit 2042c0753ec29de6045c3f1de6d075cb93d6ec27
Merge: a1d3a5130 8004b135b
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Mon Jul 3 16:25:26 2023 +0400

    Merge remote-tracking branch 'origin/master' into log-yaml-conf

commit a1d3a51307e80f9e509bd6f3bee1a7b17bf1ffe6
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Fri Jun 30 11:11:32 2023 +0400

    home: imp code

commit 2392a3b02620b8c38e88afb4d75988be85fe1338
Merge: 4224fbed7 39f5c50ac
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jun 29 16:46:47 2023 +0400

    home: imp code

commit 4224fbed7113e94bee44d0ab0272e8302a8086f3
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jun 29 16:39:35 2023 +0400

    home: imp code

commit 5ce708cc50bed83e64f062e599fc8b6143d0d44d
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jun 29 12:48:42 2023 +0400

    all: docs

commit 4b6d898a888818410f59b843c3ca1a685aafec82
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jun 29 12:20:54 2023 +0400

    home: imp code

commit 431b44eda71f488c747c3efa4da0a6c222b1cf06
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Thu Jun 29 12:03:17 2023 +0400

    home: imp tests

commit 53a5c31060018c37953beb27d80c46f92bbe14af
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Jun 28 17:40:49 2023 +0400

    home: imp docs

commit bfa57d9f21e3326baafd3a52e91d54396d8e03fa
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Jun 28 15:49:40 2023 +0400

    home: log conf

commit 49e06dca9dc2ceb2647b7e36dac145ccf78a6c3f
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Jun 28 15:41:02 2023 +0400

    home: log conf

commit 9be432dea7cec8ae0c0d3ee1f73c58c76376d07e
Author: Dimitry Kolyshev <dkolyshev@adguard.com>
Date:   Wed Jun 28 10:45:01 2023 +0400

    home: log conf
2023-07-06 10:09:04 +03:00

1381 lines
27 KiB
Go

package home
import (
"testing"
"time"
"github.com/AdguardTeam/AdGuardHome/internal/filtering"
"github.com/AdguardTeam/golibs/testutil"
"github.com/AdguardTeam/golibs/timeutil"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TODO(a.garipov): Cover all migrations, use a testdata/ dir.
func TestUpgradeSchema1to2(t *testing.T) {
diskConf := testDiskConf(1)
err := upgradeSchema1to2(diskConf)
require.NoError(t, err)
require.Equal(t, diskConf["schema_version"], 2)
_, ok := diskConf["coredns"]
require.False(t, ok)
newDNSConf, ok := diskConf["dns"]
require.True(t, ok)
oldDNSConf := testDNSConf(1)
assert.Equal(t, oldDNSConf, newDNSConf)
oldExcludedEntries := []string{"coredns", "schema_version"}
newExcludedEntries := []string{"dns", "schema_version"}
oldDiskConf := testDiskConf(1)
assertEqualExcept(t, oldDiskConf, diskConf, oldExcludedEntries, newExcludedEntries)
}
func TestUpgradeSchema2to3(t *testing.T) {
diskConf := testDiskConf(2)
err := upgradeSchema2to3(diskConf)
require.NoError(t, err)
require.Equal(t, diskConf["schema_version"], 3)
dnsMap, ok := diskConf["dns"]
require.True(t, ok)
newDNSConf, ok := dnsMap.(yobj)
require.True(t, ok)
bootstrapDNS := newDNSConf["bootstrap_dns"]
switch v := bootstrapDNS.(type) {
case []string:
require.Len(t, v, 1)
require.Equal(t, "8.8.8.8:53", v[0])
default:
t.Fatalf("wrong type for bootstrap dns: %T", v)
}
excludedEntries := []string{"bootstrap_dns"}
oldDNSConf := testDNSConf(2)
assertEqualExcept(t, oldDNSConf, newDNSConf, excludedEntries, excludedEntries)
excludedEntries = []string{"dns", "schema_version"}
oldDiskConf := testDiskConf(2)
assertEqualExcept(t, oldDiskConf, diskConf, excludedEntries, excludedEntries)
}
func TestUpgradeSchema5to6(t *testing.T) {
const newSchemaVer = 6
testCases := []struct {
in yobj
want yobj
wantErr string
name string
}{{
in: yobj{
"clients": []yobj{},
},
want: yobj{
"clients": []yobj{},
"schema_version": newSchemaVer,
},
wantErr: "",
name: "no_clients",
}, {
in: yobj{
"clients": []yobj{{"ip": "127.0.0.1"}},
},
want: yobj{
"clients": []yobj{{
"ids": []string{"127.0.0.1"},
"ip": "127.0.0.1",
}},
"schema_version": newSchemaVer,
},
wantErr: "",
name: "client_ip",
}, {
in: yobj{
"clients": []yobj{{"mac": "mac"}},
},
want: yobj{
"clients": []yobj{{
"ids": []string{"mac"},
"mac": "mac",
}},
"schema_version": newSchemaVer,
},
wantErr: "",
name: "client_mac",
}, {
in: yobj{
"clients": []yobj{{"ip": "127.0.0.1", "mac": "mac"}},
},
want: yobj{
"clients": []yobj{{
"ids": []string{"127.0.0.1", "mac"},
"ip": "127.0.0.1",
"mac": "mac",
}},
"schema_version": newSchemaVer,
},
wantErr: "",
name: "client_ip_mac",
}, {
in: yobj{
"clients": []yobj{{"ip": 1, "mac": "mac"}},
},
want: yobj{
"clients": []yobj{{"ip": 1, "mac": "mac"}},
"schema_version": newSchemaVer,
},
wantErr: "client.ip is not a string: 1",
name: "inv_client_ip",
}, {
in: yobj{
"clients": []yobj{{"ip": "127.0.0.1", "mac": 1}},
},
want: yobj{
"clients": []yobj{{"ip": "127.0.0.1", "mac": 1}},
"schema_version": newSchemaVer,
},
wantErr: "client.mac is not a string: 1",
name: "inv_client_mac",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema5to6(tc.in)
testutil.AssertErrorMsg(t, tc.wantErr, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema7to8(t *testing.T) {
const host = "1.2.3.4"
oldConf := yobj{
"dns": yobj{
"bind_host": host,
},
"schema_version": 7,
}
err := upgradeSchema7to8(oldConf)
require.NoError(t, err)
require.Equal(t, oldConf["schema_version"], 8)
dnsVal, ok := oldConf["dns"]
require.True(t, ok)
newDNSConf, ok := dnsVal.(yobj)
require.True(t, ok)
newBindHosts, ok := newDNSConf["bind_hosts"].(yarr)
require.True(t, ok)
require.Len(t, newBindHosts, 1)
assert.Equal(t, host, newBindHosts[0])
}
func TestUpgradeSchema8to9(t *testing.T) {
const tld = "foo"
t.Run("with_autohost_tld", func(t *testing.T) {
oldConf := yobj{
"dns": yobj{
"autohost_tld": tld,
},
"schema_version": 8,
}
err := upgradeSchema8to9(oldConf)
require.NoError(t, err)
require.Equal(t, oldConf["schema_version"], 9)
dnsVal, ok := oldConf["dns"]
require.True(t, ok)
newDNSConf, ok := dnsVal.(yobj)
require.True(t, ok)
localDomainName, ok := newDNSConf["local_domain_name"].(string)
require.True(t, ok)
assert.Equal(t, tld, localDomainName)
})
t.Run("without_autohost_tld", func(t *testing.T) {
oldConf := yobj{
"dns": yobj{},
"schema_version": 8,
}
err := upgradeSchema8to9(oldConf)
require.NoError(t, err)
require.Equal(t, oldConf["schema_version"], 9)
dnsVal, ok := oldConf["dns"]
require.True(t, ok)
newDNSConf, ok := dnsVal.(yobj)
require.True(t, ok)
// Should be nil in order to be set to the default value by the
// following config rewrite.
_, ok = newDNSConf["local_domain_name"]
require.False(t, ok)
})
}
// assertEqualExcept removes entries from configs and compares them.
func assertEqualExcept(t *testing.T, oldConf, newConf yobj, oldKeys, newKeys []string) {
t.Helper()
for _, k := range oldKeys {
delete(oldConf, k)
}
for _, k := range newKeys {
delete(newConf, k)
}
assert.Equal(t, oldConf, newConf)
}
func testDiskConf(schemaVersion int) (diskConf yobj) {
filters := []filtering.FilterYAML{{
URL: "https://filters.adtidy.org/android/filters/111_optimized.txt",
Name: "Latvian filter",
RulesCount: 100,
}, {
URL: "https://easylist.to/easylistgermany/easylistgermany.txt",
Name: "Germany filter",
RulesCount: 200,
}}
diskConf = yobj{
"language": "en",
"filters": filters,
"user_rules": []string{},
"schema_version": schemaVersion,
"bind_host": "0.0.0.0",
"bind_port": 80,
"auth_name": "name",
"auth_pass": "pass",
}
dnsConf := testDNSConf(schemaVersion)
if schemaVersion > 1 {
diskConf["dns"] = dnsConf
} else {
diskConf["coredns"] = dnsConf
}
return diskConf
}
// testDNSConf creates a DNS config for test the way gopkg.in/yaml.v3 would
// unmarshal it. In YAML, keys aren't guaranteed to always only be strings.
func testDNSConf(schemaVersion int) (dnsConf yobj) {
dnsConf = yobj{
"port": 53,
"blocked_response_ttl": 10,
"querylog_enabled": true,
"ratelimit": 20,
"bootstrap_dns": "8.8.8.8:53",
"parental_sensitivity": 13,
"ratelimit_whitelist": []string{},
"upstream_dns": []string{"tls://1.1.1.1", "tls://1.0.0.1", "8.8.8.8"},
"filtering_enabled": true,
"refuse_any": true,
"parental_enabled": true,
"bind_host": "0.0.0.0",
"protection_enabled": true,
"safesearch_enabled": true,
"safebrowsing_enabled": true,
}
if schemaVersion > 2 {
dnsConf["bootstrap_dns"] = []string{"8.8.8.8:53"}
}
return dnsConf
}
func TestAddQUICPort(t *testing.T) {
testCases := []struct {
name string
ups string
want string
}{{
name: "simple_ip",
ups: "8.8.8.8",
want: "8.8.8.8",
}, {
name: "url_ipv4",
ups: "quic://8.8.8.8",
want: "quic://8.8.8.8:784",
}, {
name: "url_ipv4_with_port",
ups: "quic://8.8.8.8:25565",
want: "quic://8.8.8.8:25565",
}, {
name: "url_ipv6",
ups: "quic://[::1]",
want: "quic://[::1]:784",
}, {
name: "url_ipv6_invalid",
ups: "quic://::1",
want: "quic://::1",
}, {
name: "url_ipv6_with_port",
ups: "quic://[::1]:25565",
want: "quic://[::1]:25565",
}, {
name: "url_hostname",
ups: "quic://example.com",
want: "quic://example.com:784",
}, {
name: "url_hostname_with_port",
ups: "quic://example.com:25565",
want: "quic://example.com:25565",
}, {
name: "url_hostname_with_endpoint",
ups: "quic://example.com/some-endpoint",
want: "quic://example.com:784/some-endpoint",
}, {
name: "url_hostname_with_port_endpoint",
ups: "quic://example.com:25565/some-endpoint",
want: "quic://example.com:25565/some-endpoint",
}, {
name: "non-quic_proto",
ups: "tls://example.com",
want: "tls://example.com",
}, {
name: "comment",
ups: "# comment",
want: "# comment",
}, {
name: "blank",
ups: "",
want: "",
}, {
name: "with_domain_ip",
ups: "[/example.domain/]8.8.8.8",
want: "[/example.domain/]8.8.8.8",
}, {
name: "with_domain_url",
ups: "[/example.domain/]quic://example.com",
want: "[/example.domain/]quic://example.com:784",
}, {
name: "invalid_domain",
ups: "[/exmaple.domain]quic://example.com",
want: "[/exmaple.domain]quic://example.com",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
withPort := addQUICPort(tc.ups, 784)
assert.Equal(t, tc.want, withPort)
})
}
}
func TestUpgradeSchema9to10(t *testing.T) {
const ultimateAns = 42
testCases := []struct {
ups any
want any
wantErr string
name string
}{{
ups: yarr{"quic://8.8.8.8"},
want: yarr{"quic://8.8.8.8:784"},
wantErr: "",
name: "success",
}, {
ups: ultimateAns,
want: nil,
wantErr: "unexpected type of dns.upstream_dns: int",
name: "bad_yarr_type",
}, {
ups: yarr{ultimateAns},
want: nil,
wantErr: "unexpected type of upstream field: int",
name: "bad_upstream_type",
}}
for _, tc := range testCases {
conf := yobj{
"dns": yobj{
"upstream_dns": tc.ups,
},
"schema_version": 9,
}
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema9to10(conf)
if tc.wantErr != "" {
testutil.AssertErrorMsg(t, tc.wantErr, err)
return
}
require.NoError(t, err)
require.Equal(t, conf["schema_version"], 10)
dnsVal, ok := conf["dns"]
require.True(t, ok)
newDNSConf, ok := dnsVal.(yobj)
require.True(t, ok)
fixedUps, ok := newDNSConf["upstream_dns"].(yarr)
require.True(t, ok)
assert.Equal(t, tc.want, fixedUps)
})
}
t.Run("no_dns", func(t *testing.T) {
err := upgradeSchema9to10(yobj{})
assert.NoError(t, err)
})
t.Run("bad_dns", func(t *testing.T) {
err := upgradeSchema9to10(yobj{
"dns": ultimateAns,
})
testutil.AssertErrorMsg(t, "unexpected type of dns: int", err)
})
}
func TestUpgradeSchema10to11(t *testing.T) {
check := func(t *testing.T, conf yobj) {
rlimit, _ := conf["rlimit_nofile"].(int)
err := upgradeSchema10to11(conf)
require.NoError(t, err)
require.Equal(t, conf["schema_version"], 11)
_, ok := conf["rlimit_nofile"]
assert.False(t, ok)
osVal, ok := conf["os"]
require.True(t, ok)
newOSConf, ok := osVal.(yobj)
require.True(t, ok)
_, ok = newOSConf["group"]
assert.True(t, ok)
_, ok = newOSConf["user"]
assert.True(t, ok)
rlimitVal, ok := newOSConf["rlimit_nofile"].(int)
require.True(t, ok)
assert.Equal(t, rlimit, rlimitVal)
}
const rlimit = 42
t.Run("with_rlimit", func(t *testing.T) {
conf := yobj{
"rlimit_nofile": rlimit,
"schema_version": 10,
}
check(t, conf)
})
t.Run("without_rlimit", func(t *testing.T) {
conf := yobj{
"schema_version": 10,
}
check(t, conf)
})
}
func TestUpgradeSchema11to12(t *testing.T) {
testCases := []struct {
ivl any
want any
wantErr string
name string
}{{
ivl: 1,
want: timeutil.Duration{Duration: timeutil.Day},
wantErr: "",
name: "success",
}, {
ivl: 0.25,
want: 0,
wantErr: "unexpected type of querylog_interval: float64",
name: "fail",
}}
for _, tc := range testCases {
conf := yobj{
"dns": yobj{
"querylog_interval": tc.ivl,
},
"schema_version": 11,
}
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema11to12(conf)
if tc.wantErr != "" {
require.Error(t, err)
assert.Equal(t, tc.wantErr, err.Error())
return
}
require.NoError(t, err)
require.Equal(t, conf["schema_version"], 12)
dnsVal, ok := conf["dns"]
require.True(t, ok)
var newDNSConf yobj
newDNSConf, ok = dnsVal.(yobj)
require.True(t, ok)
var newIvl timeutil.Duration
newIvl, ok = newDNSConf["querylog_interval"].(timeutil.Duration)
require.True(t, ok)
assert.Equal(t, tc.want, newIvl)
})
}
t.Run("no_dns", func(t *testing.T) {
err := upgradeSchema11to12(yobj{})
assert.NoError(t, err)
})
t.Run("bad_dns", func(t *testing.T) {
err := upgradeSchema11to12(yobj{
"dns": 0,
})
testutil.AssertErrorMsg(t, "unexpected type of dns: int", err)
})
t.Run("no_field", func(t *testing.T) {
conf := yobj{
"dns": yobj{},
}
err := upgradeSchema11to12(conf)
require.NoError(t, err)
dns, ok := conf["dns"]
require.True(t, ok)
var dnsVal yobj
dnsVal, ok = dns.(yobj)
require.True(t, ok)
var ivl any
ivl, ok = dnsVal["querylog_interval"]
require.True(t, ok)
var ivlVal timeutil.Duration
ivlVal, ok = ivl.(timeutil.Duration)
require.True(t, ok)
assert.Equal(t, 90*24*time.Hour, ivlVal.Duration)
})
}
func TestUpgradeSchema12to13(t *testing.T) {
const newSchemaVer = 13
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{},
want: yobj{"schema_version": newSchemaVer},
name: "no_dns",
}, {
in: yobj{"dns": yobj{}},
want: yobj{
"dns": yobj{},
"schema_version": newSchemaVer,
},
name: "no_dhcp",
}, {
in: yobj{
"dns": yobj{
"local_domain_name": "lan",
},
"dhcp": yobj{},
"schema_version": newSchemaVer - 1,
},
want: yobj{
"dns": yobj{},
"dhcp": yobj{
"local_domain_name": "lan",
},
"schema_version": newSchemaVer,
},
name: "good",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema12to13(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema13to14(t *testing.T) {
const newSchemaVer = 14
testClient := &clientObject{
Name: "agh-client",
IDs: []string{"id1"},
UseGlobalSettings: true,
}
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{},
want: yobj{
"schema_version": newSchemaVer,
// The clients field will be added anyway.
"clients": yobj{
"persistent": yarr{},
"runtime_sources": &clientSourcesConfig{
WHOIS: true,
ARP: true,
RDNS: false,
DHCP: true,
HostsFile: true,
},
},
},
name: "no_clients",
}, {
in: yobj{
"clients": []*clientObject{testClient},
},
want: yobj{
"schema_version": newSchemaVer,
"clients": yobj{
"persistent": []*clientObject{testClient},
"runtime_sources": &clientSourcesConfig{
WHOIS: true,
ARP: true,
RDNS: false,
DHCP: true,
HostsFile: true,
},
},
},
name: "no_dns",
}, {
in: yobj{
"clients": []*clientObject{testClient},
"dns": yobj{
"resolve_clients": true,
},
},
want: yobj{
"schema_version": newSchemaVer,
"clients": yobj{
"persistent": []*clientObject{testClient},
"runtime_sources": &clientSourcesConfig{
WHOIS: true,
ARP: true,
RDNS: true,
DHCP: true,
HostsFile: true,
},
},
"dns": yobj{},
},
name: "good",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema13to14(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema14to15(t *testing.T) {
const newSchemaVer = 15
defaultWantObj := yobj{
"querylog": map[string]any{
"enabled": true,
"file_enabled": true,
"interval": "2160h",
"size_memory": 1000,
"ignored": []any{},
},
"dns": map[string]any{},
"schema_version": newSchemaVer,
}
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{
"dns": map[string]any{
"querylog_enabled": true,
"querylog_file_enabled": true,
"querylog_interval": "2160h",
"querylog_size_memory": 1000,
},
},
want: defaultWantObj,
name: "basic",
}, {
in: yobj{
"dns": map[string]any{},
},
want: defaultWantObj,
name: "default_values",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema14to15(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema15to16(t *testing.T) {
const newSchemaVer = 16
defaultWantObj := yobj{
"statistics": map[string]any{
"enabled": true,
"interval": 1,
"ignored": []any{},
},
"dns": map[string]any{},
"schema_version": newSchemaVer,
}
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{
"dns": map[string]any{
"statistics_interval": 1,
},
},
want: defaultWantObj,
name: "basic",
}, {
in: yobj{
"dns": map[string]any{},
},
want: defaultWantObj,
name: "default_values",
}, {
in: yobj{
"dns": map[string]any{
"statistics_interval": 0,
},
},
want: yobj{
"statistics": map[string]any{
"enabled": false,
"interval": 1,
"ignored": []any{},
},
"dns": map[string]any{},
"schema_version": newSchemaVer,
},
name: "stats_disabled",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema15to16(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema16to17(t *testing.T) {
const newSchemaVer = 17
defaultWantObj := yobj{
"dns": map[string]any{
"edns_client_subnet": map[string]any{
"enabled": false,
"use_custom": false,
"custom_ip": "",
},
},
"schema_version": newSchemaVer,
}
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{
"dns": map[string]any{
"edns_client_subnet": false,
},
},
want: defaultWantObj,
name: "basic",
}, {
in: yobj{
"dns": map[string]any{},
},
want: defaultWantObj,
name: "default_values",
}, {
in: yobj{
"dns": map[string]any{
"edns_client_subnet": true,
},
},
want: yobj{
"dns": map[string]any{
"edns_client_subnet": map[string]any{
"enabled": true,
"use_custom": false,
"custom_ip": "",
},
},
"schema_version": newSchemaVer,
},
name: "is_true",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema16to17(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema17to18(t *testing.T) {
const newSchemaVer = 18
defaultWantObj := yobj{
"dns": yobj{
"safe_search": yobj{
"enabled": true,
"bing": true,
"duckduckgo": true,
"google": true,
"pixabay": true,
"yandex": true,
"youtube": true,
},
},
"schema_version": newSchemaVer,
}
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{"dns": yobj{}},
want: defaultWantObj,
name: "default_values",
}, {
in: yobj{"dns": yobj{"safesearch_enabled": true}},
want: defaultWantObj,
name: "enabled",
}, {
in: yobj{"dns": yobj{"safesearch_enabled": false}},
want: yobj{
"dns": yobj{
"safe_search": map[string]any{
"enabled": false,
"bing": true,
"duckduckgo": true,
"google": true,
"pixabay": true,
"yandex": true,
"youtube": true,
},
},
"schema_version": newSchemaVer,
},
name: "disabled",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema17to18(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema18to19(t *testing.T) {
const newSchemaVer = 19
defaultWantObj := yobj{
"clients": yobj{
"persistent": []yobj{{
"name": "localhost",
"safe_search": yobj{
"enabled": true,
"bing": true,
"duckduckgo": true,
"google": true,
"pixabay": true,
"yandex": true,
"youtube": true,
},
}},
},
"schema_version": newSchemaVer,
}
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{
"clients": yobj{},
},
want: yobj{
"clients": yobj{},
"schema_version": newSchemaVer,
},
name: "no_clients",
}, {
in: yobj{
"clients": yobj{
"persistent": []yobj{{"name": "localhost"}},
},
},
want: defaultWantObj,
name: "default_values",
}, {
in: yobj{
"clients": yobj{
"persistent": []yobj{{"name": "localhost", "safesearch_enabled": true}},
},
},
want: defaultWantObj,
name: "enabled",
}, {
in: yobj{
"clients": yobj{
"persistent": []yobj{{"name": "localhost", "safesearch_enabled": false}},
},
},
want: yobj{
"clients": yobj{"persistent": []yobj{{
"name": "localhost",
"safe_search": yobj{
"enabled": false,
"bing": true,
"duckduckgo": true,
"google": true,
"pixabay": true,
"yandex": true,
"youtube": true,
},
}}},
"schema_version": newSchemaVer,
},
name: "disabled",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema18to19(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema19to20(t *testing.T) {
testCases := []struct {
ivl any
want any
wantErr string
name string
}{{
ivl: 1,
want: timeutil.Duration{Duration: timeutil.Day},
wantErr: "",
name: "success",
}, {
ivl: 0,
want: timeutil.Duration{Duration: timeutil.Day},
wantErr: "",
name: "success",
}, {
ivl: 0.25,
want: 0,
wantErr: "unexpected type of interval: float64",
name: "fail",
}}
for _, tc := range testCases {
conf := yobj{
"statistics": yobj{
"interval": tc.ivl,
},
"schema_version": 19,
}
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema19to20(conf)
if tc.wantErr != "" {
require.Error(t, err)
assert.Equal(t, tc.wantErr, err.Error())
return
}
require.NoError(t, err)
require.Equal(t, conf["schema_version"], 20)
statsVal, ok := conf["statistics"]
require.True(t, ok)
var stats yobj
stats, ok = statsVal.(yobj)
require.True(t, ok)
var newIvl timeutil.Duration
newIvl, ok = stats["interval"].(timeutil.Duration)
require.True(t, ok)
assert.Equal(t, tc.want, newIvl)
})
}
t.Run("no_stats", func(t *testing.T) {
err := upgradeSchema19to20(yobj{})
assert.NoError(t, err)
})
t.Run("bad_stats", func(t *testing.T) {
err := upgradeSchema19to20(yobj{
"statistics": 0,
})
testutil.AssertErrorMsg(t, "unexpected type of stats: int", err)
})
t.Run("no_field", func(t *testing.T) {
conf := yobj{
"statistics": yobj{},
}
err := upgradeSchema19to20(conf)
require.NoError(t, err)
statsVal, ok := conf["statistics"]
require.True(t, ok)
var stats yobj
stats, ok = statsVal.(yobj)
require.True(t, ok)
var ivl any
ivl, ok = stats["interval"]
require.True(t, ok)
var ivlVal timeutil.Duration
ivlVal, ok = ivl.(timeutil.Duration)
require.True(t, ok)
assert.Equal(t, 24*time.Hour, ivlVal.Duration)
})
}
func TestUpgradeSchema20to21(t *testing.T) {
const newSchemaVer = 21
testCases := []struct {
in yobj
want yobj
name string
}{{
name: "nothing",
in: yobj{},
want: yobj{
"schema_version": newSchemaVer,
},
}, {
name: "no_clients",
in: yobj{
"dns": yobj{
"blocked_services": yarr{"ok"},
},
},
want: yobj{
"dns": yobj{
"blocked_services": yobj{
"ids": yarr{"ok"},
"schedule": yobj{
"time_zone": "Local",
},
},
},
"schema_version": newSchemaVer,
},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema20to21(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema21to22(t *testing.T) {
const newSchemaVer = 22
testCases := []struct {
in yobj
want yobj
name string
}{{
in: yobj{
"clients": yobj{},
},
want: yobj{
"clients": yobj{},
"schema_version": newSchemaVer,
},
name: "nothing",
}, {
in: yobj{
"clients": yobj{
"persistent": []any{yobj{"name": "localhost", "blocked_services": yarr{}}},
},
},
want: yobj{
"clients": yobj{
"persistent": []any{yobj{
"name": "localhost",
"blocked_services": yobj{
"ids": yarr{},
"schedule": yobj{
"time_zone": "Local",
},
},
}},
},
"schema_version": newSchemaVer,
},
name: "no_services",
}, {
in: yobj{
"clients": yobj{
"persistent": []any{yobj{"name": "localhost", "blocked_services": yarr{"ok"}}},
},
},
want: yobj{
"clients": yobj{
"persistent": []any{yobj{
"name": "localhost",
"blocked_services": yobj{
"ids": yarr{"ok"},
"schedule": yobj{
"time_zone": "Local",
},
},
}},
},
"schema_version": newSchemaVer,
},
name: "services",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema21to22(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema22to23(t *testing.T) {
const newSchemaVer = 23
testCases := []struct {
in yobj
want yobj
name string
}{{
name: "empty",
in: yobj{},
want: yobj{
"schema_version": newSchemaVer,
},
}, {
name: "ok",
in: yobj{
"bind_host": "1.2.3.4",
"bind_port": 8081,
"web_session_ttl": 720,
},
want: yobj{
"http": yobj{
"address": "1.2.3.4:8081",
"session_ttl": "720h",
},
"schema_version": newSchemaVer,
},
}, {
name: "v6_address",
in: yobj{
"bind_host": "2001:db8::1",
"bind_port": 8081,
"web_session_ttl": 720,
},
want: yobj{
"http": yobj{
"address": "[2001:db8::1]:8081",
"session_ttl": "720h",
},
"schema_version": newSchemaVer,
},
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema22to23(tc.in)
require.NoError(t, err)
assert.Equal(t, tc.want, tc.in)
})
}
}
func TestUpgradeSchema23to24(t *testing.T) {
const newSchemaVer = 24
testCases := []struct {
in yobj
want yobj
name string
wantErrMsg string
}{{
name: "empty",
in: yobj{},
want: yobj{
"schema_version": newSchemaVer,
},
wantErrMsg: "",
}, {
name: "ok",
in: yobj{
"log_file": "/test/path.log",
"log_max_backups": 1,
"log_max_size": 2,
"log_max_age": 3,
"log_compress": true,
"log_localtime": true,
"verbose": true,
},
want: yobj{
"log": yobj{
"file": "/test/path.log",
"max_backups": 1,
"max_size": 2,
"max_age": 3,
"compress": true,
"local_time": true,
"verbose": true,
},
"schema_version": newSchemaVer,
},
wantErrMsg: "",
}, {
name: "invalid",
in: yobj{
"log_file": "/test/path.log",
"log_max_backups": 1,
"log_max_size": 2,
"log_max_age": 3,
"log_compress": "",
"log_localtime": true,
"verbose": true,
},
want: yobj{
"log_file": "/test/path.log",
"log_max_backups": 1,
"log_max_size": 2,
"log_max_age": 3,
"log_compress": "",
"log_localtime": true,
"verbose": true,
"schema_version": newSchemaVer,
},
wantErrMsg: "unexpected type of log_compress: string",
}}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
err := upgradeSchema23to24(tc.in)
testutil.AssertErrorMsg(t, tc.wantErrMsg, err)
assert.Equal(t, tc.want, tc.in)
})
}
}