chore(all): provider to servers map in allServers
- Simplify formatting CLI - Simplify updater code - Simplify filter choices for config validation - Simplify all servers deep copying - Custom JSON marshaling methods for `AllServers` - Simplify provider constructor switch - Simplify storage merging - Simplify storage reading and extraction - Simplify updating code
This commit is contained in:
@@ -11,14 +11,14 @@ import (
|
||||
var _ Flusher = (*Storage)(nil)
|
||||
|
||||
type Flusher interface {
|
||||
FlushToFile(allServers models.AllServers) error
|
||||
FlushToFile(allServers *models.AllServers) error
|
||||
}
|
||||
|
||||
func (s *Storage) FlushToFile(allServers models.AllServers) error {
|
||||
func (s *Storage) FlushToFile(allServers *models.AllServers) error {
|
||||
return flushToFile(s.filepath, allServers)
|
||||
}
|
||||
|
||||
func flushToFile(path string, servers models.AllServers) error {
|
||||
func flushToFile(path string, servers *models.AllServers) error {
|
||||
dirPath := filepath.Dir(path)
|
||||
if err := os.MkdirAll(dirPath, 0644); err != nil {
|
||||
return err
|
||||
|
||||
@@ -3,6 +3,8 @@ package storage
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
@@ -12,5 +14,13 @@ func Test_parseHardcodedServers(t *testing.T) {
|
||||
servers, err := parseHardcodedServers()
|
||||
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, len(servers.Cyberghost.Servers))
|
||||
|
||||
// all providers minus custom
|
||||
allProviders := providers.All()
|
||||
require.Equal(t, len(allProviders), len(servers.ProviderToServers))
|
||||
for _, provider := range allProviders {
|
||||
servers, ok := servers.ProviderToServers[provider]
|
||||
assert.Truef(t, ok, "for provider %s", provider)
|
||||
assert.NotEmptyf(t, servers, "for provider %s", provider)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,29 +28,20 @@ func (s *Storage) logTimeDiff(provider string, persistedUnix, hardcodedUnix int6
|
||||
}
|
||||
|
||||
func (s *Storage) mergeServers(hardcoded, persisted models.AllServers) models.AllServers {
|
||||
return models.AllServers{
|
||||
Version: hardcoded.Version,
|
||||
Cyberghost: s.mergeProviderServers(providers.Cyberghost, hardcoded.Cyberghost, persisted.Cyberghost),
|
||||
Expressvpn: s.mergeProviderServers(providers.Expressvpn, hardcoded.Expressvpn, persisted.Expressvpn),
|
||||
Fastestvpn: s.mergeProviderServers(providers.Fastestvpn, hardcoded.Fastestvpn, persisted.Fastestvpn),
|
||||
HideMyAss: s.mergeProviderServers(providers.HideMyAss, hardcoded.HideMyAss, persisted.HideMyAss),
|
||||
Ipvanish: s.mergeProviderServers(providers.Ipvanish, hardcoded.Ipvanish, persisted.Ipvanish),
|
||||
Ivpn: s.mergeProviderServers(providers.Ivpn, hardcoded.Ivpn, persisted.Ivpn),
|
||||
Mullvad: s.mergeProviderServers(providers.Mullvad, hardcoded.Mullvad, persisted.Mullvad),
|
||||
Nordvpn: s.mergeProviderServers(providers.Nordvpn, hardcoded.Nordvpn, persisted.Nordvpn),
|
||||
Perfectprivacy: s.mergeProviderServers(providers.Perfectprivacy, hardcoded.Perfectprivacy, persisted.Perfectprivacy),
|
||||
Privado: s.mergeProviderServers(providers.Privado, hardcoded.Privado, persisted.Privado),
|
||||
Pia: s.mergeProviderServers(providers.PrivateInternetAccess, hardcoded.Pia, persisted.Pia),
|
||||
Privatevpn: s.mergeProviderServers(providers.Privatevpn, hardcoded.Privatevpn, persisted.Privatevpn),
|
||||
Protonvpn: s.mergeProviderServers(providers.Protonvpn, hardcoded.Protonvpn, persisted.Protonvpn),
|
||||
Purevpn: s.mergeProviderServers(providers.Purevpn, hardcoded.Purevpn, persisted.Purevpn),
|
||||
Surfshark: s.mergeProviderServers(providers.Surfshark, hardcoded.Surfshark, persisted.Surfshark),
|
||||
Torguard: s.mergeProviderServers(providers.Torguard, hardcoded.Torguard, persisted.Torguard),
|
||||
VPNUnlimited: s.mergeProviderServers(providers.VPNUnlimited, hardcoded.VPNUnlimited, persisted.VPNUnlimited),
|
||||
Vyprvpn: s.mergeProviderServers(providers.Vyprvpn, hardcoded.Vyprvpn, persisted.Vyprvpn),
|
||||
Wevpn: s.mergeProviderServers(providers.Wevpn, hardcoded.Wevpn, persisted.Wevpn),
|
||||
Windscribe: s.mergeProviderServers(providers.Windscribe, hardcoded.Windscribe, persisted.Windscribe),
|
||||
allProviders := providers.All()
|
||||
merged := models.AllServers{
|
||||
Version: hardcoded.Version,
|
||||
ProviderToServers: make(map[string]models.Servers, len(allProviders)),
|
||||
}
|
||||
|
||||
for _, provider := range allProviders {
|
||||
hardcodedServers := hardcoded.ProviderToServers[provider]
|
||||
persistedServers := persisted.ProviderToServers[provider]
|
||||
merged.ProviderToServers[provider] = s.mergeProviderServers(provider,
|
||||
hardcodedServers, persistedServers)
|
||||
}
|
||||
|
||||
return merged
|
||||
}
|
||||
|
||||
func (s *Storage) mergeProviderServers(provider string,
|
||||
|
||||
@@ -38,172 +38,39 @@ func (s *Storage) readFromFile(filepath string, hardcoded models.AllServers) (
|
||||
|
||||
func (s *Storage) extractServersFromBytes(b []byte, hardcoded models.AllServers) (
|
||||
servers models.AllServers, err error) {
|
||||
var versions allVersions
|
||||
if err := json.Unmarshal(b, &versions); err != nil {
|
||||
return servers, fmt.Errorf("cannot decode versions: %w", err)
|
||||
}
|
||||
|
||||
var rawMessages allJSONRawMessages
|
||||
rawMessages := make(map[string]json.RawMessage)
|
||||
if err := json.Unmarshal(b, &rawMessages); err != nil {
|
||||
return servers, fmt.Errorf("cannot decode servers: %w", err)
|
||||
}
|
||||
|
||||
type element struct {
|
||||
provider string
|
||||
hardcoded models.Servers
|
||||
serverVersion serverVersion
|
||||
rawMessage json.RawMessage
|
||||
target *models.Servers
|
||||
}
|
||||
elements := []element{
|
||||
{
|
||||
provider: providers.Cyberghost,
|
||||
hardcoded: hardcoded.Cyberghost,
|
||||
serverVersion: versions.Cyberghost,
|
||||
rawMessage: rawMessages.Cyberghost,
|
||||
target: &servers.Cyberghost,
|
||||
},
|
||||
{
|
||||
provider: providers.Expressvpn,
|
||||
hardcoded: hardcoded.Expressvpn,
|
||||
serverVersion: versions.Expressvpn,
|
||||
rawMessage: rawMessages.Expressvpn,
|
||||
target: &servers.Expressvpn,
|
||||
},
|
||||
{
|
||||
provider: providers.Fastestvpn,
|
||||
hardcoded: hardcoded.Fastestvpn,
|
||||
serverVersion: versions.Fastestvpn,
|
||||
rawMessage: rawMessages.Fastestvpn,
|
||||
target: &servers.Fastestvpn,
|
||||
},
|
||||
{
|
||||
provider: providers.HideMyAss,
|
||||
hardcoded: hardcoded.HideMyAss,
|
||||
serverVersion: versions.HideMyAss,
|
||||
rawMessage: rawMessages.HideMyAss,
|
||||
target: &servers.HideMyAss,
|
||||
},
|
||||
{
|
||||
provider: providers.Ipvanish,
|
||||
hardcoded: hardcoded.Ipvanish,
|
||||
serverVersion: versions.Ipvanish,
|
||||
rawMessage: rawMessages.Ipvanish,
|
||||
target: &servers.Ipvanish,
|
||||
},
|
||||
{
|
||||
provider: providers.Ivpn,
|
||||
hardcoded: hardcoded.Ivpn,
|
||||
serverVersion: versions.Ivpn,
|
||||
rawMessage: rawMessages.Ivpn,
|
||||
target: &servers.Ivpn,
|
||||
},
|
||||
{
|
||||
provider: providers.Mullvad,
|
||||
hardcoded: hardcoded.Mullvad,
|
||||
serverVersion: versions.Mullvad,
|
||||
rawMessage: rawMessages.Mullvad,
|
||||
target: &servers.Mullvad,
|
||||
},
|
||||
{
|
||||
provider: providers.Nordvpn,
|
||||
hardcoded: hardcoded.Nordvpn,
|
||||
serverVersion: versions.Nordvpn,
|
||||
rawMessage: rawMessages.Nordvpn,
|
||||
target: &servers.Nordvpn,
|
||||
},
|
||||
{
|
||||
provider: providers.Perfectprivacy,
|
||||
hardcoded: hardcoded.Perfectprivacy,
|
||||
serverVersion: versions.Perfectprivacy,
|
||||
rawMessage: rawMessages.Perfectprivacy,
|
||||
target: &servers.Perfectprivacy,
|
||||
},
|
||||
{
|
||||
provider: providers.Privado,
|
||||
hardcoded: hardcoded.Privado,
|
||||
serverVersion: versions.Privado,
|
||||
rawMessage: rawMessages.Privado,
|
||||
target: &servers.Privado,
|
||||
},
|
||||
{
|
||||
provider: providers.PrivateInternetAccess,
|
||||
hardcoded: hardcoded.Pia,
|
||||
serverVersion: versions.Pia,
|
||||
rawMessage: rawMessages.Pia,
|
||||
target: &servers.Pia,
|
||||
},
|
||||
{
|
||||
provider: providers.Privatevpn,
|
||||
hardcoded: hardcoded.Privatevpn,
|
||||
serverVersion: versions.Privatevpn,
|
||||
rawMessage: rawMessages.Privatevpn,
|
||||
target: &servers.Privatevpn,
|
||||
},
|
||||
{
|
||||
provider: providers.Protonvpn,
|
||||
hardcoded: hardcoded.Protonvpn,
|
||||
serverVersion: versions.Protonvpn,
|
||||
rawMessage: rawMessages.Protonvpn,
|
||||
target: &servers.Protonvpn,
|
||||
},
|
||||
{
|
||||
provider: providers.Purevpn,
|
||||
hardcoded: hardcoded.Purevpn,
|
||||
serverVersion: versions.Purevpn,
|
||||
rawMessage: rawMessages.Purevpn,
|
||||
target: &servers.Purevpn,
|
||||
},
|
||||
{
|
||||
provider: providers.Surfshark,
|
||||
hardcoded: hardcoded.Surfshark,
|
||||
serverVersion: versions.Surfshark,
|
||||
rawMessage: rawMessages.Surfshark,
|
||||
target: &servers.Surfshark,
|
||||
},
|
||||
{
|
||||
provider: providers.Torguard,
|
||||
hardcoded: hardcoded.Torguard,
|
||||
serverVersion: versions.Torguard,
|
||||
rawMessage: rawMessages.Torguard,
|
||||
target: &servers.Torguard,
|
||||
},
|
||||
{
|
||||
provider: providers.VPNUnlimited,
|
||||
hardcoded: hardcoded.VPNUnlimited,
|
||||
serverVersion: versions.VPNUnlimited,
|
||||
rawMessage: rawMessages.VPNUnlimited,
|
||||
target: &servers.VPNUnlimited,
|
||||
},
|
||||
{
|
||||
provider: providers.Vyprvpn,
|
||||
hardcoded: hardcoded.Vyprvpn,
|
||||
serverVersion: versions.Vyprvpn,
|
||||
rawMessage: rawMessages.Vyprvpn,
|
||||
target: &servers.Vyprvpn,
|
||||
},
|
||||
{
|
||||
provider: providers.Wevpn,
|
||||
hardcoded: hardcoded.Wevpn,
|
||||
serverVersion: versions.Wevpn,
|
||||
rawMessage: rawMessages.Wevpn,
|
||||
target: &servers.Wevpn,
|
||||
},
|
||||
{
|
||||
provider: providers.Windscribe,
|
||||
hardcoded: hardcoded.Windscribe,
|
||||
serverVersion: versions.Windscribe,
|
||||
rawMessage: rawMessages.Windscribe,
|
||||
target: &servers.Windscribe,
|
||||
},
|
||||
}
|
||||
// Note schema version is at map key "version" as number
|
||||
|
||||
for _, element := range elements {
|
||||
*element.target, err = s.readServers(element.provider,
|
||||
element.hardcoded, element.serverVersion, element.rawMessage)
|
||||
if err != nil {
|
||||
return servers, err
|
||||
allProviders := providers.All()
|
||||
servers.ProviderToServers = make(map[string]models.Servers, len(allProviders))
|
||||
for _, provider := range allProviders {
|
||||
hardcoded, ok := hardcoded.ProviderToServers[provider]
|
||||
if !ok {
|
||||
panic(fmt.Sprintf("provider %s not found in hardcoded servers map", provider))
|
||||
}
|
||||
|
||||
rawMessage, ok := rawMessages[provider]
|
||||
if !ok {
|
||||
// If the provider is not found in the data bytes, just don't set it in
|
||||
// the providers map. That way the hardcoded servers will override them.
|
||||
// This is user provided and could come from different sources in the
|
||||
// future (e.g. a file or API request).
|
||||
continue
|
||||
}
|
||||
|
||||
mergedServers, versionsMatch, err := s.readServers(provider, hardcoded, rawMessage)
|
||||
if err != nil {
|
||||
return models.AllServers{}, err
|
||||
} else if !versionsMatch {
|
||||
// mergedServers is the empty struct in this case, so don't set the key
|
||||
// in the providerToServers map.
|
||||
continue
|
||||
}
|
||||
servers.ProviderToServers[provider] = mergedServers
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
@@ -214,73 +81,20 @@ var (
|
||||
)
|
||||
|
||||
func (s *Storage) readServers(provider string, hardcoded models.Servers,
|
||||
serverVersion serverVersion, rawMessage json.RawMessage) (
|
||||
servers models.Servers, err error) {
|
||||
rawMessage json.RawMessage) (servers models.Servers, versionsMatch bool, err error) {
|
||||
provider = strings.Title(provider)
|
||||
if hardcoded.Version != serverVersion.Version {
|
||||
s.logVersionDiff(provider, hardcoded.Version, serverVersion.Version)
|
||||
return servers, nil
|
||||
}
|
||||
|
||||
err = json.Unmarshal(rawMessage, &servers)
|
||||
var persistedServers models.Servers
|
||||
err = json.Unmarshal(rawMessage, &persistedServers)
|
||||
if err != nil {
|
||||
return servers, fmt.Errorf("%w: %s: %s", errDecodeProvider, provider, err)
|
||||
return servers, false, fmt.Errorf("%w: %s: %s", errDecodeProvider, provider, err)
|
||||
}
|
||||
|
||||
return servers, nil
|
||||
}
|
||||
versionsMatch = hardcoded.Version == persistedServers.Version
|
||||
if !versionsMatch {
|
||||
s.logVersionDiff(provider, hardcoded.Version, persistedServers.Version)
|
||||
return servers, versionsMatch, nil
|
||||
}
|
||||
|
||||
// allVersions is a subset of models.AllServers structure used to track
|
||||
// versions to avoid unmarshaling errors.
|
||||
type allVersions struct {
|
||||
Version uint16 `json:"version"` // used for migration of the top level scheme
|
||||
Cyberghost serverVersion `json:"cyberghost"`
|
||||
Expressvpn serverVersion `json:"expressvpn"`
|
||||
Fastestvpn serverVersion `json:"fastestvpn"`
|
||||
HideMyAss serverVersion `json:"hidemyass"`
|
||||
Ipvanish serverVersion `json:"ipvanish"`
|
||||
Ivpn serverVersion `json:"ivpn"`
|
||||
Mullvad serverVersion `json:"mullvad"`
|
||||
Nordvpn serverVersion `json:"nordvpn"`
|
||||
Perfectprivacy serverVersion `json:"perfect privacy"`
|
||||
Privado serverVersion `json:"privado"`
|
||||
Pia serverVersion `json:"private internet access"`
|
||||
Privatevpn serverVersion `json:"privatevpn"`
|
||||
Protonvpn serverVersion `json:"protonvpn"`
|
||||
Purevpn serverVersion `json:"purevpn"`
|
||||
Surfshark serverVersion `json:"surfshark"`
|
||||
Torguard serverVersion `json:"torguard"`
|
||||
VPNUnlimited serverVersion `json:"vpn unlimited"`
|
||||
Vyprvpn serverVersion `json:"vyprvpn"`
|
||||
Wevpn serverVersion `json:"wevpn"`
|
||||
Windscribe serverVersion `json:"windscribe"`
|
||||
}
|
||||
|
||||
type serverVersion struct {
|
||||
Version uint16 `json:"version"`
|
||||
}
|
||||
|
||||
// allJSONRawMessages is to delay decoding of each provider servers.
|
||||
type allJSONRawMessages struct {
|
||||
Version uint16 `json:"version"` // used for migration of the top level scheme
|
||||
Cyberghost json.RawMessage `json:"cyberghost"`
|
||||
Expressvpn json.RawMessage `json:"expressvpn"`
|
||||
Fastestvpn json.RawMessage `json:"fastestvpn"`
|
||||
HideMyAss json.RawMessage `json:"hidemyass"`
|
||||
Ipvanish json.RawMessage `json:"ipvanish"`
|
||||
Ivpn json.RawMessage `json:"ivpn"`
|
||||
Mullvad json.RawMessage `json:"mullvad"`
|
||||
Nordvpn json.RawMessage `json:"nordvpn"`
|
||||
Perfectprivacy json.RawMessage `json:"perfect privacy"`
|
||||
Privado json.RawMessage `json:"privado"`
|
||||
Pia json.RawMessage `json:"private internet access"`
|
||||
Privatevpn json.RawMessage `json:"privatevpn"`
|
||||
Protonvpn json.RawMessage `json:"protonvpn"`
|
||||
Purevpn json.RawMessage `json:"purevpn"`
|
||||
Surfshark json.RawMessage `json:"surfshark"`
|
||||
Torguard json.RawMessage `json:"torguard"`
|
||||
VPNUnlimited json.RawMessage `json:"vpn unlimited"`
|
||||
Vyprvpn json.RawMessage `json:"vyprvpn"`
|
||||
Wevpn json.RawMessage `json:"wevpn"`
|
||||
Windscribe json.RawMessage `json:"windscribe"`
|
||||
return persistedServers, versionsMatch, nil
|
||||
}
|
||||
|
||||
@@ -1,80 +1,89 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/qdm12/gluetun/internal/constants/providers"
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func populateProviders(allProviderVersion uint16, allProviderTimestamp int64,
|
||||
servers models.AllServers) models.AllServers {
|
||||
allProviders := providers.All()
|
||||
if servers.ProviderToServers == nil {
|
||||
servers.ProviderToServers = make(map[string]models.Servers, len(allProviders)-1)
|
||||
}
|
||||
for _, provider := range allProviders {
|
||||
_, has := servers.ProviderToServers[provider]
|
||||
if has {
|
||||
continue
|
||||
}
|
||||
servers.ProviderToServers[provider] = models.Servers{
|
||||
Version: allProviderVersion,
|
||||
Timestamp: allProviderTimestamp,
|
||||
}
|
||||
}
|
||||
return servers
|
||||
}
|
||||
|
||||
func Test_extractServersFromBytes(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
testCases := map[string]struct {
|
||||
b []byte
|
||||
hardcoded models.AllServers
|
||||
logged []string
|
||||
persisted models.AllServers
|
||||
err error
|
||||
b []byte
|
||||
hardcoded models.AllServers
|
||||
logged []string
|
||||
persisted models.AllServers
|
||||
errMessage string
|
||||
}{
|
||||
"no data": {
|
||||
err: errors.New("cannot decode versions: unexpected end of JSON input"),
|
||||
"bad JSON": {
|
||||
b: []byte("garbage"),
|
||||
errMessage: "cannot decode servers: invalid character 'g' looking for beginning of value",
|
||||
},
|
||||
"empty JSON": {
|
||||
b: []byte("{}"),
|
||||
err: errors.New("cannot decode servers for provider: Cyberghost: unexpected end of JSON input"),
|
||||
"bad provider JSON": {
|
||||
b: []byte(`{"cyberghost": "garbage"}`),
|
||||
hardcoded: populateProviders(1, 0, models.AllServers{}),
|
||||
errMessage: "cannot decode servers for provider: Cyberghost: " +
|
||||
"json: cannot unmarshal string into Go value of type models.Servers",
|
||||
},
|
||||
"different versions": {
|
||||
b: []byte(`{}`),
|
||||
hardcoded: models.AllServers{
|
||||
Cyberghost: models.Servers{Version: 1},
|
||||
Expressvpn: models.Servers{Version: 1},
|
||||
Fastestvpn: models.Servers{Version: 1},
|
||||
HideMyAss: models.Servers{Version: 1},
|
||||
Ipvanish: models.Servers{Version: 1},
|
||||
Ivpn: models.Servers{Version: 1},
|
||||
Mullvad: models.Servers{Version: 1},
|
||||
Nordvpn: models.Servers{Version: 1},
|
||||
Perfectprivacy: models.Servers{Version: 1},
|
||||
Privado: models.Servers{Version: 1},
|
||||
Pia: models.Servers{Version: 1},
|
||||
Privatevpn: models.Servers{Version: 1},
|
||||
Protonvpn: models.Servers{Version: 1},
|
||||
Purevpn: models.Servers{Version: 1},
|
||||
Surfshark: models.Servers{Version: 1},
|
||||
Torguard: models.Servers{Version: 1},
|
||||
VPNUnlimited: models.Servers{Version: 1},
|
||||
Vyprvpn: models.Servers{Version: 1},
|
||||
Wevpn: models.Servers{Version: 1},
|
||||
Windscribe: models.Servers{Version: 1},
|
||||
},
|
||||
logged: []string{
|
||||
"Cyberghost servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Expressvpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Fastestvpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Hidemyass servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Ipvanish servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Ivpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Mullvad servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Nordvpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Perfect Privacy servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Privado servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Private Internet Access servers from file discarded because they have version 0 and hardcoded servers have version 1", //nolint:lll
|
||||
"Privatevpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Protonvpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Purevpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Surfshark servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Torguard servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Vpn Unlimited servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Vyprvpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Wevpn servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"Windscribe servers from file discarded because they have version 0 and hardcoded servers have version 1",
|
||||
"absent provider keys": {
|
||||
b: []byte(`{}`),
|
||||
hardcoded: populateProviders(1, 0, models.AllServers{}),
|
||||
persisted: models.AllServers{
|
||||
ProviderToServers: map[string]models.Servers{},
|
||||
},
|
||||
},
|
||||
"same versions": {
|
||||
b: []byte(`{
|
||||
"cyberghost": {"version": 1, "timestamp": 1},
|
||||
"expressvpn": {"version": 1, "timestamp": 1},
|
||||
"fastestvpn": {"version": 1, "timestamp": 1},
|
||||
"hidemyass": {"version": 1, "timestamp": 1},
|
||||
"ipvanish": {"version": 1, "timestamp": 1},
|
||||
"ivpn": {"version": 1, "timestamp": 1},
|
||||
"mullvad": {"version": 1, "timestamp": 1},
|
||||
"nordvpn": {"version": 1, "timestamp": 1},
|
||||
"perfect privacy": {"version": 1, "timestamp": 1},
|
||||
"privado": {"version": 1, "timestamp": 1},
|
||||
"private internet access": {"version": 1, "timestamp": 1},
|
||||
"privatevpn": {"version": 1, "timestamp": 1},
|
||||
"protonvpn": {"version": 1, "timestamp": 1},
|
||||
"purevpn": {"version": 1, "timestamp": 1},
|
||||
"surfshark": {"version": 1, "timestamp": 1},
|
||||
"torguard": {"version": 1, "timestamp": 1},
|
||||
"vpn unlimited": {"version": 1, "timestamp": 1},
|
||||
"vyprvpn": {"version": 1, "timestamp": 1},
|
||||
"wevpn": {"version": 1, "timestamp": 1},
|
||||
"windscribe": {"version": 1, "timestamp": 1}
|
||||
}`),
|
||||
hardcoded: populateProviders(1, 0, models.AllServers{}),
|
||||
persisted: populateProviders(1, 1, models.AllServers{}),
|
||||
},
|
||||
"different versions": {
|
||||
b: []byte(`{
|
||||
"cyberghost": {"version": 1, "timestamp": 1},
|
||||
"expressvpn": {"version": 1, "timestamp": 1},
|
||||
@@ -97,49 +106,31 @@ func Test_extractServersFromBytes(t *testing.T) {
|
||||
"wevpn": {"version": 1, "timestamp": 1},
|
||||
"windscribe": {"version": 1, "timestamp": 1}
|
||||
}`),
|
||||
hardcoded: models.AllServers{
|
||||
Cyberghost: models.Servers{Version: 1},
|
||||
Expressvpn: models.Servers{Version: 1},
|
||||
Fastestvpn: models.Servers{Version: 1},
|
||||
HideMyAss: models.Servers{Version: 1},
|
||||
Ipvanish: models.Servers{Version: 1},
|
||||
Ivpn: models.Servers{Version: 1},
|
||||
Mullvad: models.Servers{Version: 1},
|
||||
Nordvpn: models.Servers{Version: 1},
|
||||
Perfectprivacy: models.Servers{Version: 1},
|
||||
Privado: models.Servers{Version: 1},
|
||||
Pia: models.Servers{Version: 1},
|
||||
Privatevpn: models.Servers{Version: 1},
|
||||
Protonvpn: models.Servers{Version: 1},
|
||||
Purevpn: models.Servers{Version: 1},
|
||||
Surfshark: models.Servers{Version: 1},
|
||||
Torguard: models.Servers{Version: 1},
|
||||
VPNUnlimited: models.Servers{Version: 1},
|
||||
Vyprvpn: models.Servers{Version: 1},
|
||||
Wevpn: models.Servers{Version: 1},
|
||||
Windscribe: models.Servers{Version: 1},
|
||||
hardcoded: populateProviders(2, 0, models.AllServers{}),
|
||||
logged: []string{
|
||||
"Cyberghost servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Expressvpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Fastestvpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Hidemyass servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Ipvanish servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Ivpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Mullvad servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Nordvpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Perfect Privacy servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Privado servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Private Internet Access servers from file discarded because they have version 1 and hardcoded servers have version 2", //nolint:lll
|
||||
"Privatevpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Protonvpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Purevpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Surfshark servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Torguard servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Vpn Unlimited servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Vyprvpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Wevpn servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
"Windscribe servers from file discarded because they have version 1 and hardcoded servers have version 2",
|
||||
},
|
||||
persisted: models.AllServers{
|
||||
Cyberghost: models.Servers{Version: 1, Timestamp: 1},
|
||||
Expressvpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
Fastestvpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
HideMyAss: models.Servers{Version: 1, Timestamp: 1},
|
||||
Ipvanish: models.Servers{Version: 1, Timestamp: 1},
|
||||
Ivpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
Mullvad: models.Servers{Version: 1, Timestamp: 1},
|
||||
Nordvpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
Perfectprivacy: models.Servers{Version: 1, Timestamp: 1},
|
||||
Privado: models.Servers{Version: 1, Timestamp: 1},
|
||||
Pia: models.Servers{Version: 1, Timestamp: 1},
|
||||
Privatevpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
Protonvpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
Purevpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
Surfshark: models.Servers{Version: 1, Timestamp: 1},
|
||||
Torguard: models.Servers{Version: 1, Timestamp: 1},
|
||||
VPNUnlimited: models.Servers{Version: 1, Timestamp: 1},
|
||||
Vyprvpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
Wevpn: models.Servers{Version: 1, Timestamp: 1},
|
||||
Windscribe: models.Servers{Version: 1, Timestamp: 1},
|
||||
ProviderToServers: map[string]models.Servers{},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -151,8 +142,13 @@ func Test_extractServersFromBytes(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
|
||||
logger := NewMockInfoErrorer(ctrl)
|
||||
var previousLogCall *gomock.Call
|
||||
for _, logged := range testCase.logged {
|
||||
logger.EXPECT().Info(logged)
|
||||
call := logger.EXPECT().Info(logged)
|
||||
if previousLogCall != nil {
|
||||
call.After(previousLogCall)
|
||||
}
|
||||
previousLogCall = call
|
||||
}
|
||||
|
||||
s := &Storage{
|
||||
@@ -161,9 +157,8 @@ func Test_extractServersFromBytes(t *testing.T) {
|
||||
|
||||
servers, err := s.extractServersFromBytes(testCase.b, testCase.hardcoded)
|
||||
|
||||
if testCase.err != nil {
|
||||
require.Error(t, err)
|
||||
assert.Equal(t, testCase.err.Error(), err.Error())
|
||||
if testCase.errMessage != "" {
|
||||
assert.EqualError(t, err, testCase.errMessage)
|
||||
} else {
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
@@ -171,4 +166,25 @@ func Test_extractServersFromBytes(t *testing.T) {
|
||||
assert.Equal(t, testCase.persisted, servers)
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("hardcoded panic", func(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := &Storage{}
|
||||
|
||||
allProviders := providers.All()
|
||||
require.GreaterOrEqual(t, len(allProviders), 2)
|
||||
|
||||
b := []byte(`{}`)
|
||||
hardcoded := models.AllServers{
|
||||
ProviderToServers: map[string]models.Servers{
|
||||
allProviders[0]: {},
|
||||
// Missing provider allProviders[1]
|
||||
},
|
||||
}
|
||||
expectedPanicValue := fmt.Sprintf("provider %s not found in hardcoded servers map", allProviders[1])
|
||||
assert.PanicsWithValue(t, expectedPanicValue, func() {
|
||||
_, _ = s.extractServersFromBytes(b, hardcoded)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@@ -7,27 +7,11 @@ import (
|
||||
"github.com/qdm12/gluetun/internal/models"
|
||||
)
|
||||
|
||||
func countServers(allServers models.AllServers) int {
|
||||
return len(allServers.Cyberghost.Servers) +
|
||||
len(allServers.Expressvpn.Servers) +
|
||||
len(allServers.Fastestvpn.Servers) +
|
||||
len(allServers.HideMyAss.Servers) +
|
||||
len(allServers.Ipvanish.Servers) +
|
||||
len(allServers.Ivpn.Servers) +
|
||||
len(allServers.Mullvad.Servers) +
|
||||
len(allServers.Nordvpn.Servers) +
|
||||
len(allServers.Perfectprivacy.Servers) +
|
||||
len(allServers.Privado.Servers) +
|
||||
len(allServers.Pia.Servers) +
|
||||
len(allServers.Privatevpn.Servers) +
|
||||
len(allServers.Protonvpn.Servers) +
|
||||
len(allServers.Purevpn.Servers) +
|
||||
len(allServers.Surfshark.Servers) +
|
||||
len(allServers.Torguard.Servers) +
|
||||
len(allServers.VPNUnlimited.Servers) +
|
||||
len(allServers.Vyprvpn.Servers) +
|
||||
len(allServers.Wevpn.Servers) +
|
||||
len(allServers.Windscribe.Servers)
|
||||
func countServers(allServers models.AllServers) (count int) {
|
||||
for _, servers := range allServers.ProviderToServers {
|
||||
count += len(servers.Servers)
|
||||
}
|
||||
return count
|
||||
}
|
||||
|
||||
func (s *Storage) SyncServers() (err error) {
|
||||
@@ -57,7 +41,7 @@ func (s *Storage) SyncServers() (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if err := flushToFile(s.filepath, s.mergedServers); err != nil {
|
||||
if err := flushToFile(s.filepath, &s.mergedServers); err != nil {
|
||||
return fmt.Errorf("cannot write servers to file: %w", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user