Merge: Win travis build

* commit '6503bab1aaa27ff43175d069413630a420093be0':
  *: added cross-env to npm scripts
  run npm build on windows
  *: added more logging
  -: fix autohosts tests on Windows
  -: fix qlog test on Windows
  *: fix nvs script
  *: travis - use nvs on Windows
  *: travis-win -- try nvm
  *(global): travis: choco install nodejs
  +(global): windows travis build
This commit is contained in:
Andrey Meshkov 2020-04-15 16:13:24 +03:00
commit 215e3eeaf6
11 changed files with 217 additions and 67 deletions

View File

@ -7,14 +7,41 @@ go:
os: os:
- linux - linux
- osx - osx
- windows
before_install: before_install:
- nvm install node - |-
- npm install -g npm case $TRAVIS_OS_NAME in
- curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.23.8 linux | osx)
nvm install node
npm install -g npm
curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh| sh -s -- -b $(go env GOPATH)/bin v1.23.8
;;
windows)
# Using NVS for managing Node.js versions on Windows
NVS_HOME="C:\ProgramData\nvs"
git clone --single-branch https://github.com/jasongin/nvs $NVS_HOME
source $NVS_HOME/nvs.sh
nvs add latest
nvs use latest
;;
esac
install: install:
- npm --prefix client ci - |-
case $TRAVIS_OS_NAME in
linux | osx)
node --version
npm --version
npm --prefix client ci
;;
windows)
node --version
npm --version
nvs --version
npm --prefix client ci
;;
esac
cache: cache:
directories: directories:
@ -23,10 +50,24 @@ cache:
- $HOME/Library/Caches/go-build - $HOME/Library/Caches/go-build
script: script:
- /bin/bash ci.sh - |-
case $TRAVIS_OS_NAME in
linux | osx)
/bin/bash ci.sh
;;
windows)
npm --prefix client run build-prod
go test -race -v -bench=. -coverprofile=coverage.txt -covermode=atomic ./...
;;
esac
after_success: after_success:
- bash <(curl -s https://codecov.io/bash) - |-
case $TRAVIS_OS_NAME in
linux)
bash <(curl -s https://codecov.io/bash)
;;
esac
notifications: notifications:
slack: performix:yXTihlSzsLFSZiqbXMNzvTSX slack: performix:yXTihlSzsLFSZiqbXMNzvTSX
@ -60,6 +101,8 @@ matrix:
file_glob: true file_glob: true
skip_cleanup: true skip_cleanup: true
# Docker build configuration
- if: repo = AdguardTeam/AdGuardHome
- name: docker - name: docker
if: type != pull_request AND (branch = master OR tag IS present) AND repo = AdguardTeam/AdGuardHome if: type != pull_request AND (branch = master OR tag IS present) AND repo = AdguardTeam/AdGuardHome
go: go:

52
client/package-lock.json generated vendored
View File

@ -3522,6 +3522,58 @@
"gud": "^1.0.0" "gud": "^1.0.0"
} }
}, },
"cross-env": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.2.tgz",
"integrity": "sha512-KZP/bMEOJEDCkDQAyRhu3RL2ZO/SUVrxQVI0G3YEQ+OLbRA3c6zgixe8Mq8a/z7+HKlNEjo8oiLUs8iRijY2Rw==",
"dev": true,
"requires": {
"cross-spawn": "^7.0.1"
},
"dependencies": {
"cross-spawn": {
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.2.tgz",
"integrity": "sha512-PD6G8QG3S4FK/XCGFbEQrDqO2AnMMsy0meR7lerlIOHAAbkuavGU/pOqprrlvfTNjvowivTeBsjebAL0NSoMxw==",
"dev": true,
"requires": {
"path-key": "^3.1.0",
"shebang-command": "^2.0.0",
"which": "^2.0.1"
}
},
"path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==",
"dev": true
},
"shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
"dev": true,
"requires": {
"shebang-regex": "^3.0.0"
}
},
"shebang-regex": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
"dev": true
},
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
"dev": true,
"requires": {
"isexe": "^2.0.0"
}
}
}
},
"cross-spawn": { "cross-spawn": {
"version": "5.1.0", "version": "5.1.0",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",

11
client/package.json vendored
View File

@ -3,9 +3,9 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"scripts": { "scripts": {
"build-dev": "NODE_ENV=development ./node_modules/.bin/webpack --config webpack.dev.js", "build-dev": "cross-env NODE_ENV=development webpack --config webpack.dev.js",
"watch": "NODE_ENV=development ./node_modules/.bin/webpack --config webpack.dev.js --watch", "watch": "cross-env NODE_ENV=development webpack --config webpack.dev.js --watch",
"build-prod": "NODE_ENV=production ./node_modules/.bin/webpack --config webpack.prod.js", "build-prod": "cross-env NODE_ENV=production webpack --config webpack.prod.js",
"lint": "eslint client/" "lint": "eslint client/"
}, },
"dependencies": { "dependencies": {
@ -49,6 +49,7 @@
"clean-webpack-plugin": "^0.1.19", "clean-webpack-plugin": "^0.1.19",
"compression-webpack-plugin": "^1.1.11", "compression-webpack-plugin": "^1.1.11",
"copy-webpack-plugin": "^4.6.0", "copy-webpack-plugin": "^4.6.0",
"cross-env": "^7.0.2",
"css-loader": "^2.1.1", "css-loader": "^2.1.1",
"eslint": "^4.19.1", "eslint": "^4.19.1",
"eslint-config-airbnb-base": "^12.1.0", "eslint-config-airbnb-base": "^12.1.0",
@ -70,11 +71,11 @@
"style-loader": "^0.21.0", "style-loader": "^0.21.0",
"stylelint": "^9.10.1", "stylelint": "^9.10.1",
"stylelint-webpack-plugin": "0.10.4", "stylelint-webpack-plugin": "0.10.4",
"svg-url-loader": "^2.3.2",
"uglifyjs-webpack-plugin": "^1.2.7", "uglifyjs-webpack-plugin": "^1.2.7",
"url-loader": "^1.0.1", "url-loader": "^1.0.1",
"webpack": "3.8.1", "webpack": "3.8.1",
"webpack-dev-server": "^3.1.14", "webpack-dev-server": "^3.1.14",
"webpack-merge": "^4.1.3", "webpack-merge": "^4.1.3"
"svg-url-loader": "^2.3.2"
} }
} }

View File

@ -71,6 +71,8 @@ type User struct {
// InitAuth - create a global object // InitAuth - create a global object
func InitAuth(dbFilename string, users []User, sessionTTL uint32) *Auth { func InitAuth(dbFilename string, users []User, sessionTTL uint32) *Auth {
log.Info("Initializing auth module: %s", dbFilename)
a := Auth{} a := Auth{}
a.sessionTTL = sessionTTL a.sessionTTL = sessionTTL
a.sessions = make(map[string]*session) a.sessions = make(map[string]*session)
@ -83,7 +85,7 @@ func InitAuth(dbFilename string, users []User, sessionTTL uint32) *Auth {
} }
a.loadSessions() a.loadSessions()
a.users = users a.users = users
log.Debug("Auth: initialized. users:%d sessions:%d", len(a.users), len(a.sessions)) log.Info("Auth: initialized. users:%d sessions:%d", len(a.users), len(a.sessions))
return &a return &a
} }

View File

@ -43,10 +43,10 @@ const (
// Update-related variables // Update-related variables
var ( var (
versionString string versionString = "dev"
updateChannel string updateChannel = "none"
versionCheckURL string versionCheckURL = ""
ARMVersion string ARMVersion = ""
) )
const versionCheckPeriod = time.Hour * 8 const versionCheckPeriod = time.Hour * 8
@ -155,11 +155,11 @@ func run(args options) {
configureLogger(args) configureLogger(args)
// print the first message after logger is configured // print the first message after logger is configured
msg := "AdGuard Home, version %s, channel %s\n, arch %s %s" msg := "AdGuard Home, version %s, channel %s, arch %s %s"
if ARMVersion != "" { if ARMVersion != "" {
msg = msg + " v" + ARMVersion msg = msg + " v" + ARMVersion
} }
log.Printf(msg, versionString, updateChannel, runtime.GOOS, runtime.GOARCH, ARMVersion) log.Printf(msg, versionString, updateChannel, runtime.GOOS, runtime.GOARCH)
log.Debug("Current working directory is %s", Context.workDir) log.Debug("Current working directory is %s", Context.workDir)
if args.runningAsService { if args.runningAsService {
log.Info("AdGuard Home is running as a service") log.Info("AdGuard Home is running as a service")
@ -169,6 +169,7 @@ func run(args options) {
Context.firstRun = detectFirstRun() Context.firstRun = detectFirstRun()
if Context.firstRun { if Context.firstRun {
log.Info("This is the first time AdGuard Home is launched")
requireAdminRights() requireAdminRights()
} }
@ -197,6 +198,7 @@ func run(args options) {
err = parseConfig() err = parseConfig()
if err != nil { if err != nil {
log.Error("Failed to parse configuration, exiting")
os.Exit(1) os.Exit(1)
} }
@ -211,6 +213,7 @@ func run(args options) {
config.DHCP.ConfigModified = onConfigModified config.DHCP.ConfigModified = onConfigModified
Context.dhcpServer = dhcpd.Create(config.DHCP) Context.dhcpServer = dhcpd.Create(config.DHCP)
if Context.dhcpServer == nil { if Context.dhcpServer == nil {
log.Error("Failed to initialize DHCP server, exiting")
os.Exit(1) os.Exit(1)
} }
Context.autoHosts.Init("") Context.autoHosts.Init("")

View File

@ -107,14 +107,14 @@ schema_version: 5
// . Wait until the filters are downloaded // . Wait until the filters are downloaded
// . Stop and cleanup // . Stop and cleanup
func TestHome(t *testing.T) { func TestHome(t *testing.T) {
// Reinit context // Init new context
Context = homeContext{} Context = homeContext{}
dir := prepareTestDir() dir := prepareTestDir()
defer func() { _ = os.RemoveAll(dir) }() defer func() { _ = os.RemoveAll(dir) }()
_ = os.MkdirAll(filepath.Join(Context.getDataDir(), filterDir), 0755)
fn := filepath.Join(dir, "AdGuardHome.yaml") fn := filepath.Join(dir, "AdGuardHome.yaml")
// Prepare the test config
assert.True(t, ioutil.WriteFile(fn, []byte(yamlConf), 0644) == nil) assert.True(t, ioutil.WriteFile(fn, []byte(yamlConf), 0644) == nil)
fn, _ = filepath.Abs(fn) fn, _ = filepath.Abs(fn)
@ -135,11 +135,11 @@ func TestHome(t *testing.T) {
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
} }
assert.Truef(t, err == nil, "%s", err) assert.Truef(t, err == nil, "%s", err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
resp, err = h.Get("http://127.0.0.1:3000/control/status") resp, err = h.Get("http://127.0.0.1:3000/control/status")
assert.Truef(t, err == nil, "%s", err) assert.Truef(t, err == nil, "%s", err)
assert.Equal(t, 200, resp.StatusCode) assert.Equal(t, http.StatusOK, resp.StatusCode)
// test DNS over UDP // test DNS over UDP
r := upstream.NewResolver("127.0.0.1:5354", 3*time.Second) r := upstream.NewResolver("127.0.0.1:5354", 3*time.Second)

View File

@ -42,6 +42,8 @@ type Web struct {
// CreateWeb - create module // CreateWeb - create module
func CreateWeb(conf *WebConfig) *Web { func CreateWeb(conf *WebConfig) *Web {
log.Info("Initialize web module")
w := Web{} w := Web{}
w.conf = conf w.conf = conf

View File

@ -206,7 +206,9 @@ func (l *queryLog) getData(params getDataParams) map[string]interface{} {
fileEntries, oldest, total := l.searchFiles(params) fileEntries, oldest, total := l.searchFiles(params)
if params.OlderThan.IsZero() { if params.OlderThan.IsZero() {
params.OlderThan = now // In case if the timer is not precise (for instance, on Windows)
// We really want to get all records including those added just before the call
params.OlderThan = now.Add(time.Millisecond)
} }
// add from memory buffer // add from memory buffer

View File

@ -23,7 +23,7 @@ type AutoHosts struct {
hostsFn string // path to the main hosts-file hostsFn string // path to the main hosts-file
hostsDirs []string // paths to OS-specific directories with hosts-files hostsDirs []string // paths to OS-specific directories with hosts-files
watcher *fsnotify.Watcher // file and directory watcher object watcher *fsnotify.Watcher // file and directory watcher object
updateChan chan bool // signal for 'update' goroutine updateChan chan bool // signal for 'updateLoop' goroutine
onChanged onChangedT // notification to other modules onChanged onChangedT // notification to other modules
} }
@ -68,20 +68,22 @@ func (a *AutoHosts) Init(hostsFn string) {
// Start - start module // Start - start module
func (a *AutoHosts) Start() { func (a *AutoHosts) Start() {
go a.update() log.Debug("Start AutoHosts module")
go a.updateLoop()
a.updateChan <- true a.updateChan <- true
go a.watcherLoop() go a.watcherLoop()
err := a.watcher.Add(a.hostsFn) err := a.watcher.Add(a.hostsFn)
if err != nil { if err != nil {
log.Error("AutoHosts: %s", err) log.Error("Error while initializing watcher for a file %s: %s", a.hostsFn, err)
} }
for _, dir := range a.hostsDirs { for _, dir := range a.hostsDirs {
err = a.watcher.Add(dir) err = a.watcher.Add(dir)
if err != nil { if err != nil {
log.Error("AutoHosts: %s", err) log.Error("Error while initializing watcher for a directory %s: %s", dir, err)
} }
} }
} }
@ -89,7 +91,8 @@ func (a *AutoHosts) Start() {
// Close - close module // Close - close module
func (a *AutoHosts) Close() { func (a *AutoHosts) Close() {
a.updateChan <- false a.updateChan <- false
a.watcher.Close() close(a.updateChan)
_ = a.watcher.Close()
} }
// Read IP-hostname pairs from file // Read IP-hostname pairs from file
@ -174,7 +177,7 @@ func (a *AutoHosts) watcherLoop() {
log.Debug("AutoHosts: modified: %s", event.Name) log.Debug("AutoHosts: modified: %s", event.Name)
select { select {
case a.updateChan <- true: case a.updateChan <- true:
// sent a signal to 'update' goroutine // sent a signal to 'updateLoop' goroutine
default: default:
// queue is full // queue is full
} }
@ -189,41 +192,48 @@ func (a *AutoHosts) watcherLoop() {
} }
} }
// Read static hosts from system files // updateLoop - read static hosts from system files
func (a *AutoHosts) update() { func (a *AutoHosts) updateLoop() {
for { for {
select { select {
case ok := <-a.updateChan: case ok := <-a.updateChan:
if !ok { if !ok {
log.Debug("Finished AutoHosts update loop")
return return
} }
table := make(map[string][]net.IP) a.updateHosts()
a.load(table, a.hostsFn)
for _, dir := range a.hostsDirs {
fis, err := ioutil.ReadDir(dir)
if err != nil {
if !os.IsNotExist(err) {
log.Error("AutoHosts: Opening directory: %s: %s", dir, err)
}
continue
}
for _, fi := range fis {
a.load(table, dir+"/"+fi.Name())
}
}
a.lock.Lock()
a.table = table
a.lock.Unlock()
a.notify()
} }
} }
} }
// updateHosts - loads system hosts
func (a *AutoHosts) updateHosts() {
table := make(map[string][]net.IP)
a.load(table, a.hostsFn)
for _, dir := range a.hostsDirs {
fis, err := ioutil.ReadDir(dir)
if err != nil {
if !os.IsNotExist(err) {
log.Error("AutoHosts: Opening directory: %s: %s", dir, err)
}
continue
}
for _, fi := range fis {
a.load(table, dir+"/"+fi.Name())
}
}
a.lock.Lock()
a.table = table
a.lock.Unlock()
a.notify()
}
// Process - get the list of IP addresses for the hostname // Process - get the list of IP addresses for the hostname
// Return nil if not found // Return nil if not found
func (a *AutoHosts) Process(host string) []net.IP { func (a *AutoHosts) Process(host string) []net.IP {

View File

@ -17,38 +17,73 @@ func prepareTestDir() string {
return dir return dir
} }
func TestAutoHosts(t *testing.T) { func TestAutoHostsResolution(t *testing.T) {
ah := AutoHosts{} ah := AutoHosts{}
dir := prepareTestDir() dir := prepareTestDir()
defer func() { _ = os.RemoveAll(dir) }() defer func() { _ = os.RemoveAll(dir) }()
f, _ := ioutil.TempFile(dir, "") f, _ := ioutil.TempFile(dir, "")
defer os.Remove(f.Name()) defer func() { _ = os.Remove(f.Name()) }()
defer f.Close() defer f.Close()
_, _ = f.WriteString(" 127.0.0.1 host localhost \n") _, _ = f.WriteString(" 127.0.0.1 host localhost \n")
ah.Init(f.Name()) ah.Init(f.Name())
ah.Start()
// wait until we parse the file
time.Sleep(50 * time.Millisecond)
// Update from the hosts file
ah.updateHosts()
// Existing host
ips := ah.Process("localhost") ips := ah.Process("localhost")
assert.True(t, ips[0].Equal(net.ParseIP("127.0.0.1"))) assert.NotNil(t, ips)
ips = ah.Process("newhost") assert.Equal(t, 1, len(ips))
assert.True(t, ips == nil) assert.Equal(t, net.ParseIP("127.0.0.1"), ips[0])
// Unknown host
ips = ah.Process("newhost")
assert.Nil(t, ips)
// Test hosts file
table := ah.List() table := ah.List()
ips, _ = table["host"] ips, _ = table["host"]
assert.True(t, ips[0].String() == "127.0.0.1") assert.NotNil(t, ips)
assert.Equal(t, 1, len(ips))
assert.Equal(t, "127.0.0.1", ips[0].String())
}
func TestAutoHostsFSNotify(t *testing.T) {
ah := AutoHosts{}
dir := prepareTestDir()
defer func() { _ = os.RemoveAll(dir) }()
f, _ := ioutil.TempFile(dir, "")
defer func() { _ = os.Remove(f.Name()) }()
defer f.Close()
// Init
_, _ = f.WriteString(" 127.0.0.1 host localhost \n")
ah.Init(f.Name())
ah.updateHosts()
// Unknown host
ips := ah.Process("newhost")
assert.Nil(t, ips)
// Stat monitoring for changes
ah.Start()
defer ah.Close()
// Update file
_, _ = f.WriteString("127.0.0.2 newhost\n") _, _ = f.WriteString("127.0.0.2 newhost\n")
_ = f.Sync()
// wait until fsnotify has triggerred and processed the file-modification event // wait until fsnotify has triggerred and processed the file-modification event
time.Sleep(50 * time.Millisecond) time.Sleep(50 * time.Millisecond)
// Check if we are notified about changes
ips = ah.Process("newhost") ips = ah.Process("newhost")
assert.True(t, ips[0].Equal(net.ParseIP("127.0.0.2"))) assert.NotNil(t, ips)
assert.Equal(t, 1, len(ips))
ah.Close() assert.Equal(t, "127.0.0.2", ips[0].String())
} }

View File

@ -13,7 +13,7 @@ func SetRlimit(val uint) {
func HaveAdminRights() (bool, error) { func HaveAdminRights() (bool, error) {
var token windows.Token var token windows.Token
h, _ := windows.GetCurrentProcess() h := windows.CurrentProcess()
err := windows.OpenProcessToken(h, windows.TOKEN_QUERY, &token) err := windows.OpenProcessToken(h, windows.TOKEN_QUERY, &token)
if err != nil { if err != nil {
return false, err return false, err