diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 3c54b00b..a9172a5c 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -48,7 +48,7 @@ lint: tags: - medium -test: +test-linux: stage: test only: - branches @@ -65,6 +65,14 @@ test: tags: - medium +test-windows: + extends: .build-windows-base + stage: test + only: + - branches + script: + - make test + test-integration: stage: test only: @@ -96,6 +104,7 @@ build-qml: - cd internal/frontend/qml - tar -cvzf ../../../bridge_qml.tgz ./* + .build-base: stage: build only: @@ -134,6 +143,7 @@ build-linux-qa: paths: - bridge_*.tgz + .build-darwin-base: extends: .build-base before_script: @@ -170,6 +180,40 @@ build-darwin-qa: paths: - bridge_*.tgz + +.build-windows-base: + extends: .build-base + before_script: + - export GOROOT=/c/Go + - export PATH=$GOROOT/bin:$PATH + - export GOARCH=amd64 + - export GOPATH=~/go + - export GO111MODULE=on + - export PATH=$GOPATH/bin:$PATH + - export MSYSTEM= + - export PATH=$PATH:/c/grrrQt/5.13.2/mingw73_64/bin + tags: + - windows-bridge + +build-windows: + extends: .build-windows-base + artifacts: + name: "bridge-windows-$CI_COMMIT_SHORT_SHA" + paths: + - bridge_*.tgz + +build-windows-qa: + extends: .build-windows-base + only: + - web + - branches + script: + - BUILD_TAGS="build_qa" make build + artifacts: + name: "bridge-windows-qa-$CI_COMMIT_SHORT_SHA" + paths: + - bridge_*.tgz + # Stage: MIRROR mirror-repo: diff --git a/internal/config/settings/kvs_test.go b/internal/config/settings/kvs_test.go index fc5106d4..6de60945 100644 --- a/internal/config/settings/kvs_test.go +++ b/internal/config/settings/kvs_test.go @@ -25,81 +25,118 @@ import ( "github.com/stretchr/testify/require" ) -const testPrefFilePath = "/tmp/pref.json" - func TestLoadNoKeyValueStore(t *testing.T) { - pref := newTestEmptyKeyValueStore(t) - require.Equal(t, "", pref.Get("key")) + r := require.New(t) + pref, clean := newTestEmptyKeyValueStore(r) + defer clean() + + r.Equal("", pref.Get("key")) } func TestLoadBadKeyValueStore(t *testing.T) { - require.NoError(t, ioutil.WriteFile(testPrefFilePath, []byte("{\"key\":\"value"), 0700)) - pref := newKeyValueStore(testPrefFilePath) - require.Equal(t, "", pref.Get("key")) + r := require.New(t) + path, clean := newTmpFile(r) + defer clean() + + r.NoError(ioutil.WriteFile(path, []byte("{\"key\":\"MISSING_QUOTES"), 0700)) + pref := newKeyValueStore(path) + r.Equal("", pref.Get("key")) } -func TestKeyValueStoreGet(t *testing.T) { - pref := newTestKeyValueStore(t) - require.Equal(t, "value", pref.Get("str")) - require.Equal(t, "42", pref.Get("int")) - require.Equal(t, "true", pref.Get("bool")) - require.Equal(t, "t", pref.Get("falseBool")) +func TestKeyValueStor(t *testing.T) { + r := require.New(t) + pref, clean := newTestKeyValueStore(r) + defer clean() + + r.Equal("value", pref.Get("str")) + r.Equal("42", pref.Get("int")) + r.Equal("true", pref.Get("bool")) + r.Equal("t", pref.Get("falseBool")) } func TestKeyValueStoreGetInt(t *testing.T) { - pref := newTestKeyValueStore(t) - require.Equal(t, 0, pref.GetInt("str")) - require.Equal(t, 42, pref.GetInt("int")) - require.Equal(t, 0, pref.GetInt("bool")) - require.Equal(t, 0, pref.GetInt("falseBool")) + r := require.New(t) + pref, clean := newTestKeyValueStore(r) + defer clean() + + r.Equal(0, pref.GetInt("str")) + r.Equal(42, pref.GetInt("int")) + r.Equal(0, pref.GetInt("bool")) + r.Equal(0, pref.GetInt("falseBool")) } func TestKeyValueStoreGetBool(t *testing.T) { - pref := newTestKeyValueStore(t) - require.Equal(t, false, pref.GetBool("str")) - require.Equal(t, false, pref.GetBool("int")) - require.Equal(t, true, pref.GetBool("bool")) - require.Equal(t, false, pref.GetBool("falseBool")) + r := require.New(t) + pref, clean := newTestKeyValueStore(r) + defer clean() + + r.Equal(false, pref.GetBool("str")) + r.Equal(false, pref.GetBool("int")) + r.Equal(true, pref.GetBool("bool")) + r.Equal(false, pref.GetBool("falseBool")) } func TestKeyValueStoreSetDefault(t *testing.T) { - pref := newTestEmptyKeyValueStore(t) + r := require.New(t) + pref, clean := newTestEmptyKeyValueStore(r) + defer clean() + pref.setDefault("key", "value") pref.setDefault("key", "othervalue") - require.Equal(t, "value", pref.Get("key")) + r.Equal("value", pref.Get("key")) } func TestKeyValueStoreSet(t *testing.T) { - pref := newTestEmptyKeyValueStore(t) + r := require.New(t) + pref, clean := newTestEmptyKeyValueStore(r) + defer clean() + pref.Set("str", "value") - checkSavedKeyValueStore(t, "{\n\t\"str\": \"value\"\n}") + checkSavedKeyValueStore(r, pref.path, "{\n\t\"str\": \"value\"\n}") } func TestKeyValueStoreSetInt(t *testing.T) { - pref := newTestEmptyKeyValueStore(t) + r := require.New(t) + pref, clean := newTestEmptyKeyValueStore(r) + defer clean() + pref.SetInt("int", 42) - checkSavedKeyValueStore(t, "{\n\t\"int\": \"42\"\n}") + checkSavedKeyValueStore(r, pref.path, "{\n\t\"int\": \"42\"\n}") } func TestKeyValueStoreSetBool(t *testing.T) { - pref := newTestEmptyKeyValueStore(t) + r := require.New(t) + pref, clean := newTestEmptyKeyValueStore(r) + defer clean() + pref.SetBool("trueBool", true) pref.SetBool("falseBool", false) - checkSavedKeyValueStore(t, "{\n\t\"falseBool\": \"false\",\n\t\"trueBool\": \"true\"\n}") + checkSavedKeyValueStore(r, pref.path, "{\n\t\"falseBool\": \"false\",\n\t\"trueBool\": \"true\"\n}") } -func newTestEmptyKeyValueStore(t *testing.T) *keyValueStore { - require.NoError(t, os.RemoveAll(testPrefFilePath)) - return newKeyValueStore(testPrefFilePath) +func newTmpFile(r *require.Assertions) (path string, clean func()) { + tmpfile, err := ioutil.TempFile("", "pref.*.json") + r.NoError(err) + defer r.NoError(tmpfile.Close()) + + return tmpfile.Name(), func() { + r.NoError(os.Remove(tmpfile.Name())) + } } -func newTestKeyValueStore(t *testing.T) *keyValueStore { - require.NoError(t, ioutil.WriteFile(testPrefFilePath, []byte("{\"str\":\"value\",\"int\":\"42\",\"bool\":\"true\",\"falseBool\":\"t\"}"), 0700)) - return newKeyValueStore(testPrefFilePath) +func newTestEmptyKeyValueStore(r *require.Assertions) (*keyValueStore, func()) { + path, clean := newTmpFile(r) + return newKeyValueStore(path), clean } -func checkSavedKeyValueStore(t *testing.T, expected string) { - data, err := ioutil.ReadFile(testPrefFilePath) - require.NoError(t, err) - require.Equal(t, expected, string(data)) +func newTestKeyValueStore(r *require.Assertions) (*keyValueStore, func()) { + path, clean := newTmpFile(r) + r.NoError(ioutil.WriteFile(path, []byte("{\"str\":\"value\",\"int\":\"42\",\"bool\":\"true\",\"falseBool\":\"t\"}"), 0700)) + return newKeyValueStore(path), clean +} + +func checkSavedKeyValueStore(r *require.Assertions, path, expected string) { + data, err := ioutil.ReadFile(path) + r.NoError(err) + r.Equal(expected, string(data)) } diff --git a/internal/store/cache/disk.go b/internal/store/cache/disk.go index 46091f88..fd8da082 100644 --- a/internal/store/cache/disk.go +++ b/internal/store/cache/disk.go @@ -63,10 +63,16 @@ func NewOnDiskCache(path string, cmp Compressor, opts Options) (Cache, error) { } file, err := ioutil.TempFile(path, "tmp") + defer func() { + file.Close() //nolint[errcheck] + os.Remove(file.Name()) //nolint[errcheck] + }() if err != nil { + return nil, fmt.Errorf("cannot open test write target: %w", err) + } + if _, err := file.Write([]byte("test-write")); err != nil { return nil, fmt.Errorf("cannot write to target: %w", err) } - os.Remove(file.Name()) //nolint[errcheck] usage := du.NewDiskUsage(path) diff --git a/internal/users/cache.go b/internal/users/cache.go index c06c8b91..01ece8fd 100644 --- a/internal/users/cache.go +++ b/internal/users/cache.go @@ -229,7 +229,10 @@ func (u *Users) MigrateCache(srcPath, dstPath string) error { // (read-only is conserved). Do copy instead. tmp, err := ioutil.TempFile(srcPath, "tmp") if err == nil { - defer os.Remove(tmp.Name()) //nolint[errcheck] + defer func() { + tmp.Close() //nolint[errcheck] + os.Remove(tmp.Name()) //nolint[errcheck] + }() if err := os.Rename(srcPath, dstPath); err == nil { return nil diff --git a/internal/users/users_test.go b/internal/users/users_test.go index 00b14d7c..af90aa80 100644 --- a/internal/users/users_test.go +++ b/internal/users/users_test.go @@ -175,6 +175,7 @@ func initMocks(t *testing.T) mocks { cacheFile, err := ioutil.TempFile("", "bridge-store-cache-*.db") r.NoError(t, err, "could not get temporary file for store cache") + r.NoError(t, cacheFile.Close()) m := mocks{ t: t, @@ -201,6 +202,7 @@ func initMocks(t *testing.T) mocks { dbFile, err := ioutil.TempFile(t.TempDir(), "bridge-store-db-*.db") r.NoError(t, err, "could not get temporary file for store db") + r.NoError(t, dbFile.Close()) return store.New( sentryReporter, diff --git a/internal/versioner/versioner_remove_test.go b/internal/versioner/versioner_remove_test.go index aa404741..a6a89dce 100644 --- a/internal/versioner/versioner_remove_test.go +++ b/internal/versioner/versioner_remove_test.go @@ -32,7 +32,7 @@ import ( // RemoveOldVersions is a noop on darwin; we don't test it there. func TestRemoveOldVersions(t *testing.T) { - updates, err := ioutil.TempDir("", "updates") + updates, err := ioutil.TempDir(t.TempDir(), "updates") require.NoError(t, err) v := newTestVersioner(t, "myCoolApp", updates, "2.3.4-beta", "2.3.4", "2.3.5", "2.4.0") diff --git a/internal/versioner/versioner_test.go b/internal/versioner/versioner_test.go index d28bbdc0..4b83a643 100644 --- a/internal/versioner/versioner_test.go +++ b/internal/versioner/versioner_test.go @@ -65,11 +65,13 @@ func makeDummyVersionDirectory(t *testing.T, exeName, updates, version string) s exe, err := os.Create(filepath.Join(target, getExeName(exeName))) require.NoError(t, err) require.NotNil(t, exe) + require.NoError(t, exe.Close()) require.NoError(t, os.Chmod(exe.Name(), 0700)) sig, err := os.Create(filepath.Join(target, getExeName(exeName)+".sig")) require.NoError(t, err) require.NotNil(t, sig) + require.NoError(t, sig.Close()) return target } diff --git a/pkg/parallel/parallel_test.go b/pkg/parallel/parallel_test.go index c380274b..628a5dc4 100644 --- a/pkg/parallel/parallel_test.go +++ b/pkg/parallel/parallel_test.go @@ -21,6 +21,7 @@ import ( "errors" "fmt" "math" + "runtime" "testing" "time" @@ -33,6 +34,7 @@ var ( wantOutput = []int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} testProcessSleep = 100 // ms runParallelTimeOverhead = 150 // ms + windowsCIExtra = 250 // ms - estimated experimentally ) func TestParallel(t *testing.T) { @@ -56,6 +58,9 @@ func TestParallel(t *testing.T) { wantMinDuration := int(math.Ceil(float64(len(testInput))/float64(workers))) * testProcessSleep wantMaxDuration := wantMinDuration + runParallelTimeOverhead + if runtime.GOOS == "windows" { + wantMaxDuration += windowsCIExtra + } r.True(t, duration.Nanoseconds() > int64(wantMinDuration*1000000), "Duration too short: %v (expected: %v)", duration, wantMinDuration) r.True(t, duration.Nanoseconds() < int64(wantMaxDuration*1000000), "Duration too long: %v (expected: %v)", duration, wantMaxDuration) })