cleanup: Make tests work

Fix #5
create-reload-action
Lukasz Janyst 4 years ago
parent b8ba625dcc
commit d3190b01e6
No known key found for this signature in database
GPG Key ID: 32DE641041F17A9A
  1. 59
      pkg/cookies/jar_test.go
  2. 69
      pkg/logging/logging_test.go
  3. 75
      pkg/logging/rotator.go
  4. 131
      pkg/logging/rotator_test.go
  5. 4
      pkg/users/users_clear_test.go
  6. 3
      pkg/users/users_test.go
  7. 2
      test/Makefile
  8. 11
      test/context/bridge.go
  9. 49
      test/context/bridge_panic_handler.go
  10. 5
      test/context/imap.go
  11. 5
      test/context/smtp.go

@ -18,13 +18,15 @@
package cookies
import (
"fmt"
"io/ioutil"
"net/http"
"net/http/httptest"
"net/url"
"os"
"testing"
"time"
"github.com/ljanyst/peroxide/pkg/config/settings"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@ -37,7 +39,10 @@ func TestJarGetSet(t *testing.T) {
})
defer ts.Close()
client, _ := getClientWithJar(t, newFakeSettings())
f, n := newFakeJarFile()
defer os.Remove(n)
defer f.Close()
client, _ := getClientWithJar(t, n)
// Hit a server that sets some cookies.
setRes, err := client.Get(ts.URL + "/set")
@ -63,10 +68,12 @@ func TestJarLoad(t *testing.T) {
defer ts.Close()
// This will be our "persistent storage" from which the cookie jar should load cookies.
s := newFakeSettings()
f, n := newFakeJarFile()
defer os.Remove(n)
defer f.Close()
// This client saves cookies to persistent storage.
oldClient, jar := getClientWithJar(t, s)
oldClient, jar := getClientWithJar(t, n)
// Hit a server that sets some cookies.
setRes, err := oldClient.Get(ts.URL + "/set")
@ -76,10 +83,10 @@ func TestJarLoad(t *testing.T) {
require.NoError(t, setRes.Body.Close())
// Save the cookies.
require.NoError(t, jar.PersistCookies())
require.NoError(t, jar.persistCookies())
// This client loads cookies from persistent storage.
newClient, _ := getClientWithJar(t, s)
newClient, _ := getClientWithJar(t, n)
// Hit a server that checks the cookies are there.
getRes, err := newClient.Get(ts.URL + "/get")
@ -98,10 +105,12 @@ func TestJarExpiry(t *testing.T) {
defer ts.Close()
// This will be our "persistent storage" from which the cookie jar should load cookies.
s := newFakeSettings()
f, n := newFakeJarFile()
defer os.Remove(n)
defer f.Close()
// This client saves cookies to persistent storage.
oldClient, jar1 := getClientWithJar(t, s)
oldClient, jar1 := getClientWithJar(t, n)
// Hit a server that sets some cookies.
setRes, err := oldClient.Get(ts.URL + "/set")
@ -111,20 +120,30 @@ func TestJarExpiry(t *testing.T) {
require.NoError(t, setRes.Body.Close())
// Save the cookies.
require.NoError(t, jar1.PersistCookies())
require.NoError(t, jar1.persistCookies())
// Wait until the second cookie expires.
time.Sleep(2 * time.Second)
// Load a client, which will clear out expired cookies.
_, jar2 := getClientWithJar(t, s)
_, jar2 := getClientWithJar(t, n)
// Save the cookies (expired ones were cleared out).
require.NoError(t, jar2.PersistCookies())
require.NoError(t, jar2.persistCookies())
// Load again to see if the cookies are cleared out
_, jar3 := getClientWithJar(t, n)
setURL, _ := url.Parse(ts.URL + "/set")
fmt.Printf("%+v", jar3.Cookies(setURL))
cookies := jar3.Cookies(setURL)
cs := []string{}
for _, c := range cookies {
cs = append(cs, c.Name)
}
assert.Contains(t, s.Get(settings.CookiesKey), "TestName1")
assert.NotContains(t, s.Get(settings.CookiesKey), "TestName2")
assert.Contains(t, s.Get(settings.CookiesKey), "TestName3")
assert.Contains(t, cs, "TestName1")
assert.NotContains(t, cs, "TestName2")
assert.Contains(t, cs, "TestName3")
}
type testCookie struct {
@ -132,8 +151,8 @@ type testCookie struct {
maxAge int
}
func getClientWithJar(t *testing.T, s *settings.Settings) (*http.Client, *Jar) {
jar, err := NewCookieJar(s)
func getClientWithJar(t *testing.T, jarFile string) (*http.Client, *Jar) {
jar, err := NewCookieJar(jarFile)
require.NoError(t, err)
return &http.Client{Jar: jar}, jar
@ -168,12 +187,10 @@ func getTestServer(t *testing.T, wantCookies []testCookie) *httptest.Server {
return httptest.NewServer(mux)
}
// newFakeSettings creates a temporary folder for files.
func newFakeSettings() *settings.Settings {
dir, err := ioutil.TempDir("", "test-settings")
func newFakeJarFile() (*os.File, string) {
file, err := ioutil.TempFile(os.TempDir(), "cookie-jar-")
if err != nil {
panic(err)
}
return settings.New(dir)
return file, file.Name()
}

@ -1,69 +0,0 @@
// Copyright (c) 2022 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package logging
import (
"io/ioutil"
"path/filepath"
"testing"
"github.com/stretchr/testify/require"
)
// TestClearLogs tests that cearLogs removes only bridge old log files keeping last three of them.
func TestClearLogs(t *testing.T) {
dir, err := ioutil.TempDir("", "clear-logs-test")
require.NoError(t, err)
require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "other.log"), []byte("Hello"), 0755))
require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "v1_10.log"), []byte("Hello"), 0755))
require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "v1_11.log"), []byte("Hello"), 0755))
require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "v2_12.log"), []byte("Hello"), 0755))
require.NoError(t, ioutil.WriteFile(filepath.Join(dir, "v2_13.log"), []byte("Hello"), 0755))
require.NoError(t, clearLogs(dir, 3, 0))
checkFileNames(t, dir, []string{
"other.log",
"v1_11.log",
"v2_12.log",
"v2_13.log",
})
}
func checkFileNames(t *testing.T, dir string, expectedFileNames []string) {
fileNames := getFileNames(t, dir)
require.Equal(t, expectedFileNames, fileNames)
}
func getFileNames(t *testing.T, dir string) []string {
files, err := ioutil.ReadDir(dir)
require.NoError(t, err)
fileNames := []string{}
for _, file := range files {
fileNames = append(fileNames, file.Name())
if file.IsDir() {
subDir := filepath.Join(dir, file.Name())
subFileNames := getFileNames(t, subDir)
for _, subFileName := range subFileNames {
fileNames = append(fileNames, file.Name()+"/"+subFileName)
}
}
}
return fileNames
}

@ -1,75 +0,0 @@
// Copyright (c) 2022 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package logging
import "io"
type Rotator struct {
getFile FileProvider
wc io.WriteCloser
size int
maxSize int
}
type FileProvider func() (io.WriteCloser, error)
func NewRotator(maxSize int, getFile FileProvider) (*Rotator, error) {
r := &Rotator{
getFile: getFile,
maxSize: maxSize,
}
if err := r.rotate(); err != nil {
return nil, err
}
return r, nil
}
func (r *Rotator) Write(p []byte) (int, error) {
if r.size+len(p) > r.maxSize {
if err := r.rotate(); err != nil {
return 0, err
}
}
n, err := r.wc.Write(p)
if err != nil {
return n, err
}
r.size += n
return n, nil
}
func (r *Rotator) rotate() error {
if r.wc != nil {
_ = r.wc.Close()
}
wc, err := r.getFile()
if err != nil {
return err
}
r.wc = wc
r.size = 0
return nil
}

@ -1,131 +0,0 @@
// Copyright (c) 2022 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package logging
import (
"bytes"
"io"
"io/ioutil"
"os"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type WriteCloser struct {
bytes.Buffer
}
func (c *WriteCloser) Close() error {
return nil
}
func TestRotator(t *testing.T) {
n := 0
getFile := func() (io.WriteCloser, error) {
n++
return &WriteCloser{}, nil
}
r, err := NewRotator(10, getFile)
require.NoError(t, err)
_, err = r.Write([]byte("12345"))
require.NoError(t, err)
assert.Equal(t, 1, n)
_, err = r.Write([]byte("12345"))
require.NoError(t, err)
assert.Equal(t, 1, n)
_, err = r.Write([]byte("01234"))
require.NoError(t, err)
assert.Equal(t, 2, n)
_, err = r.Write([]byte("01234"))
require.NoError(t, err)
assert.Equal(t, 2, n)
_, err = r.Write([]byte("01234"))
require.NoError(t, err)
assert.Equal(t, 3, n)
_, err = r.Write([]byte("01234"))
require.NoError(t, err)
assert.Equal(t, 3, n)
_, err = r.Write([]byte("01234"))
require.NoError(t, err)
assert.Equal(t, 4, n)
}
func BenchmarkRotateRAMFile(b *testing.B) {
dir, err := ioutil.TempDir("", "rotate-benchmark")
require.NoError(b, err)
defer os.RemoveAll(dir) // nolint[errcheck]
benchRotate(b, MaxLogSize, getTestFile(b, dir, MaxLogSize-1))
}
func BenchmarkRotateDiskFile(b *testing.B) {
cache, err := os.UserCacheDir()
require.NoError(b, err)
dir, err := ioutil.TempDir(cache, "rotate-benchmark")
require.NoError(b, err)
defer os.RemoveAll(dir) // nolint[errcheck]
benchRotate(b, MaxLogSize, getTestFile(b, dir, MaxLogSize-1))
}
func benchRotate(b *testing.B, logSize int, getFile func() (io.WriteCloser, error)) {
r, err := NewRotator(logSize, getFile)
require.NoError(b, err)
for n := 0; n < b.N; n++ {
require.NoError(b, r.rotate())
f, ok := r.wc.(*os.File)
require.True(b, ok)
require.NoError(b, os.Remove(f.Name()))
}
}
func getTestFile(b *testing.B, dir string, length int) func() (io.WriteCloser, error) {
return func() (io.WriteCloser, error) {
b.StopTimer()
defer b.StartTimer()
f, err := ioutil.TempFile(dir, "log")
if err != nil {
return nil, err
}
if _, err := f.Write(make([]byte, length)); err != nil {
return nil, err
}
if err := f.Sync(); err != nil {
return nil, err
}
return f, nil
}
}

@ -20,8 +20,8 @@ package users
import (
"testing"
"github.com/ljanyst/peroxide/pkg/events"
gomock "github.com/golang/mock/gomock"
"github.com/ljanyst/peroxide/pkg/events"
r "github.com/stretchr/testify/require"
)
@ -46,7 +46,5 @@ func TestClearData(t *testing.T) {
m.pmapiClient.EXPECT().AuthDelete(gomock.Any())
m.credentialsStore.EXPECT().Logout("users").Return(testCredentialsSplitDisconnected, nil)
m.locator.EXPECT().Clear()
r.NoError(t, users.ClearData())
}

@ -178,7 +178,6 @@ func initMocks(t *testing.T) mocks {
t: t,
ctrl: mockCtrl,
locator: usersmocks.NewMockLocator(mockCtrl),
credentialsStore: usersmocks.NewMockCredentialsStorer(mockCtrl),
storeMaker: usersmocks.NewMockStoreMaker(mockCtrl),
eventListener: usersmocks.NewMockListener(mockCtrl),
@ -236,7 +235,7 @@ func testNewUsers(t *testing.T, m mocks) *Users { //nolint[unparam]
m.eventListener.EXPECT().ProvideChannel(events.UpgradeApplicationEvent)
m.eventListener.EXPECT().ProvideChannel(events.InternetOnEvent)
users := New(m.locator, m.eventListener, m.clientManager, m.credentialsStore, m.storeMaker)
users := New(m.eventListener, m.clientManager, m.credentialsStore, m.storeMaker)
waitForEvents()

@ -13,7 +13,7 @@ check-go:
check-godog:
@which godog || $(MAKE) install-godog
install-godog: check-go
go get github.com/cucumber/godog/cmd/godog@v0.12.1
go install github.com/cucumber/godog/cmd/godog@upd-go1.18
test: test-bridge
test-bridge: FEATURES ?= features

@ -20,11 +20,8 @@ package context
import (
"time"
"github.com/ProtonMail/go-autostart"
"github.com/ljanyst/peroxide/pkg/bridge"
"github.com/ljanyst/peroxide/pkg/config/settings"
"github.com/ljanyst/peroxide/pkg/config/useragent"
"github.com/ljanyst/peroxide/pkg/constants"
"github.com/ljanyst/peroxide/pkg/listener"
"github.com/ljanyst/peroxide/pkg/message"
"github.com/ljanyst/peroxide/pkg/pmapi"
@ -75,20 +72,12 @@ func newBridgeInstance(
clientManager pmapi.Manager,
) *bridge.Bridge {
return bridge.New(
locations,
cacheProvider,
fakeSettings,
&panicHandler{t: t},
eventListener,
cache.NewInMemoryCache(100*(1<<20)),
message.NewBuilder(fakeSettings.GetInt(settings.FetchWorkers), fakeSettings.GetInt(settings.AttachmentWorkers)),
clientManager,
credStore,
newFakeUpdater(),
newFakeVersioner(),
&autostart.App{
Name: "bridge",
Exec: []string{"bridge"},
},
)
}

@ -1,49 +0,0 @@
// Copyright (c) 2022 Proton Technologies AG
//
// This file is part of ProtonMail Bridge.Bridge.
//
// ProtonMail Bridge is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// ProtonMail Bridge is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with ProtonMail Bridge. If not, see <https://www.gnu.org/licenses/>.
package context
import (
"bytes"
"io/ioutil"
"runtime/pprof"
)
type panicHandler struct {
t *bddT
}
func newPanicHandler(t *bddT) *panicHandler {
return &panicHandler{
t: t,
}
}
// HandlePanic makes the panicHandler implement the panicHandler interface for bridge.
func (ph *panicHandler) HandlePanic() {
r := recover()
if r != nil {
ph.t.Errorf("panic: %s", r)
r := bytes.NewBufferString("")
_ = pprof.Lookup("goroutine").WriteTo(r, 2)
b, err := ioutil.ReadAll(r)
ph.t.Errorf("pprof details: %s %s", err, b)
ph.t.FailNow()
}
}

@ -54,12 +54,11 @@ func (ctx *TestContext) withIMAPServer() {
}
settingsPath, _ := ctx.locations.ProvideSettingsPath()
ph := newPanicHandler(ctx.t)
port := ctx.settings.GetInt(settings.IMAPPortKey)
tls, _ := tls.New(settingsPath).GetConfig()
backend := imap.NewIMAPBackend(ph, ctx.listener, ctx.cache, ctx.settings, ctx.bridge)
server := imap.NewIMAPServer(ph, true, true, port, tls, backend, ctx.userAgent, ctx.listener)
backend := imap.NewIMAPBackend(ctx.listener, ctx.cache, ctx.settings, ctx.bridge)
server := imap.NewIMAPServer(true, true, port, tls, backend, ctx.userAgent, ctx.listener)
go server.ListenAndServe()
require.NoError(ctx.t, waitForPort(port, 5*time.Second))

@ -54,13 +54,12 @@ func (ctx *TestContext) withSMTPServer() {
}
settingsPath, _ := ctx.locations.ProvideSettingsPath()
ph := newPanicHandler(ctx.t)
tls, _ := tls.New(settingsPath).GetConfig()
port := ctx.settings.GetInt(settings.SMTPPortKey)
useSSL := ctx.settings.GetBool(settings.SMTPSSLKey)
backend := smtp.NewSMTPBackend(ph, ctx.listener, ctx.settings, ctx.bridge)
server := smtp.NewSMTPServer(ph, true, port, useSSL, tls, backend, ctx.listener)
backend := smtp.NewSMTPBackend(ctx.listener, ctx.settings, ctx.bridge)
server := smtp.NewSMTPServer(true, port, useSSL, tls, backend, ctx.listener)
go server.ListenAndServe()
require.NoError(ctx.t, waitForPort(port, 5*time.Second))

Loading…
Cancel
Save