youtubebeat/vendor/github.com/elastic/beats/journalbeat/checkpoint/checkpoint_test.go

218 lines
5.4 KiB
Go

// Licensed to Elasticsearch B.V. under one or more contributor
// license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright
// ownership. Elasticsearch B.V. licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// +build !integration
package checkpoint
import (
"io/ioutil"
"os"
"path/filepath"
"runtime"
"testing"
"time"
"github.com/stretchr/testify/assert"
)
func eventually(t *testing.T, predicate func() (bool, error), timeout time.Duration) {
const minInterval = time.Millisecond * 5
const maxInterval = time.Millisecond * 500
checkInterval := timeout / 100
if checkInterval < minInterval {
checkInterval = minInterval
}
if checkInterval > maxInterval {
checkInterval = maxInterval
}
for deadline, first := time.Now().Add(timeout), true; first || time.Now().Before(deadline); first = false {
ok, err := predicate()
if err != nil {
t.Fatal("predicate failed with error:", err)
return
}
if ok {
return
}
time.Sleep(checkInterval)
}
t.Fatal("predicate is not true after", timeout)
}
// Test that a write is triggered when the maximum number of updates is reached.
func TestWriteMaxUpdates(t *testing.T) {
dir, err := ioutil.TempDir("", "wlb-checkpoint-test")
if err != nil {
t.Fatal(err)
}
defer func() {
err := os.RemoveAll(dir)
if err != nil {
t.Fatal(err)
}
}()
file := filepath.Join(dir, "some", "new", "dir", ".winlogbeat.yml")
if !assert.False(t, fileExists(file), "%s should not exist", file) {
return
}
cp, err := NewCheckpoint(file, 2, time.Hour)
if err != nil {
t.Fatal(err)
}
defer cp.Shutdown()
// Send update - it's not written to disk but it's in memory.
cp.Persist("", "", 123456, 123456)
found := false
eventually(t, func() (bool, error) {
_, found = cp.States()[""]
return found, nil
}, time.Second*15)
assert.True(t, found)
ps, err := cp.read()
if err != nil {
t.Fatal("read failed", err)
}
assert.Len(t, ps.States, 0)
// Send update - it is written to disk.
cp.Persist("", "", 123456, 123456)
eventually(t, func() (bool, error) {
ps, err = cp.read()
return ps != nil && len(ps.States) > 0, err
}, time.Second*15)
if assert.Len(t, ps.States, 1, "state not written, could be a flush timing issue, retry") {
assert.Equal(t, "", ps.States[0].Path)
assert.Equal(t, "", ps.States[0].Cursor)
}
}
// Test that a write is triggered when the maximum time period since the last
// write is reached.
func TestWriteTimedFlush(t *testing.T) {
dir, err := ioutil.TempDir("", "wlb-checkpoint-test")
if err != nil {
t.Fatal(err)
}
defer func() {
err := os.RemoveAll(dir)
if err != nil {
t.Fatal(err)
}
}()
file := filepath.Join(dir, ".winlogbeat.yml")
if !assert.False(t, fileExists(file), "%s should not exist", file) {
return
}
cp, err := NewCheckpoint(file, 100, time.Second)
if err != nil {
t.Fatal(err)
}
defer cp.Shutdown()
// Send update then wait longer than the flush interval and it should be
// on disk.
cp.Persist("", "cursor", 123456, 123456)
eventually(t, func() (bool, error) {
ps, err := cp.read()
return ps != nil && len(ps.States) > 0, err
}, time.Second*15)
ps, err := cp.read()
if err != nil {
t.Fatal("read failed", err)
}
if assert.Len(t, ps.States, 1) {
assert.Equal(t, "", ps.States[0].Path)
assert.Equal(t, "cursor", ps.States[0].Cursor)
}
}
// Test that createDir creates the directory with 0750 permissions.
func TestCreateDir(t *testing.T) {
dir, err := ioutil.TempDir("", "wlb-checkpoint-test")
if err != nil {
t.Fatal(err)
}
defer func() {
err := os.RemoveAll(dir)
if err != nil {
t.Fatal(err)
}
}()
stateDir := filepath.Join(dir, "state", "dir", "does", "not", "exists")
file := filepath.Join(stateDir, ".winlogbeat.yml")
cp := &Checkpoint{file: file}
if !assert.False(t, fileExists(file), "%s should not exist", file) {
return
}
if err = cp.createDir(); err != nil {
t.Fatal("createDir", err)
}
if !assert.True(t, fileExists(stateDir), "%s should exist", file) {
return
}
// mkdir on Windows does not pass the POSIX mode to the CreateDirectory
// syscall so doesn't test the mode.
if runtime.GOOS != "windows" {
fileInfo, err := os.Stat(stateDir)
if assert.NoError(t, err) {
assert.Equal(t, true, fileInfo.IsDir())
assert.Equal(t, os.FileMode(0750), fileInfo.Mode().Perm())
}
}
}
// Test createDir when the directory already exists to verify that no error is
// returned.
func TestCreateDirAlreadyExists(t *testing.T) {
dir, err := ioutil.TempDir("", "wlb-checkpoint-test")
if err != nil {
t.Fatal(err)
}
defer func() {
err := os.RemoveAll(dir)
if err != nil {
t.Fatal(err)
}
}()
file := filepath.Join(dir, ".winlogbeat.yml")
cp := &Checkpoint{file: file}
if !assert.True(t, fileExists(dir), "%s should exist", file) {
return
}
assert.NoError(t, cp.createDir())
}
// fileExists returns true if the specified file exists.
func fileExists(file string) bool {
_, err := os.Stat(file)
return !os.IsNotExist(err)
}