forked from Silverfish/proton-bridge
GODT-2181(test): Basic ATLAS test in test context
This commit is contained in:
@ -18,27 +18,73 @@
|
||||
package tests
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"os"
|
||||
|
||||
"github.com/Masterminds/semver/v3"
|
||||
"github.com/ProtonMail/go-proton-api"
|
||||
"github.com/ProtonMail/go-proton-api/server"
|
||||
)
|
||||
|
||||
type API interface {
|
||||
SetMinAppVersion(*semver.Version)
|
||||
AddCallWatcher(func(server.Call), ...string)
|
||||
|
||||
GetHostURL() string
|
||||
GetDomain() string
|
||||
AddCallWatcher(func(server.Call), ...string)
|
||||
RemoveAddressKey(userID, addrID, keyID string) error
|
||||
GetAppVersion() string
|
||||
|
||||
Close()
|
||||
}
|
||||
|
||||
func newTestAPI() API {
|
||||
if hostURL := os.Getenv("FEATURE_TEST_HOST_URL"); hostURL != "" {
|
||||
return newLiveAPI(hostURL)
|
||||
}
|
||||
|
||||
return newFakeAPI()
|
||||
}
|
||||
|
||||
type fakeAPI struct {
|
||||
*server.Server
|
||||
}
|
||||
|
||||
func newFakeAPI() *fakeAPI {
|
||||
func newFakeAPI() API {
|
||||
return &fakeAPI{
|
||||
Server: server.New(),
|
||||
}
|
||||
}
|
||||
|
||||
func (api *fakeAPI) GetAppVersion() string {
|
||||
return proton.DefaultAppVersion
|
||||
}
|
||||
|
||||
type liveAPI struct {
|
||||
*server.Server
|
||||
|
||||
domain string
|
||||
}
|
||||
|
||||
func newLiveAPI(hostURL string) API {
|
||||
url, err := url.Parse(hostURL)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return &liveAPI{
|
||||
Server: server.New(server.WithProxyOrigin(hostURL)),
|
||||
domain: url.Hostname(),
|
||||
}
|
||||
}
|
||||
|
||||
func (api *liveAPI) GetHostURL() string {
|
||||
return api.Server.GetProxyURL()
|
||||
}
|
||||
|
||||
func (api *liveAPI) GetDomain() string {
|
||||
return api.domain
|
||||
}
|
||||
|
||||
func (api *liveAPI) GetAppVersion() string {
|
||||
return os.Getenv("FEATURE_TEST_APP_VERSION")
|
||||
}
|
||||
|
||||
@ -113,13 +113,13 @@ func TestFeatures(testingT *testing.T) {
|
||||
// ==== SETUP ====
|
||||
ctx.Step(`^there exists an account with username "([^"]*)" and password "([^"]*)"$`, s.thereExistsAnAccountWithUsernameAndPassword)
|
||||
ctx.Step(`^the account "([^"]*)" has additional address "([^"]*)"$`, s.theAccountHasAdditionalAddress)
|
||||
ctx.Step(`^the account "([^"]*)" has additional address "([^"]*)" without keys$`, s.theAccountHasAdditionalAddressWithoutKeys)
|
||||
ctx.Step(`^the account "([^"]*)" no longer has additional address "([^"]*)"$`, s.theAccountNoLongerHasAdditionalAddress)
|
||||
ctx.Step(`^the account "([^"]*)" has (\d+) custom folders$`, s.theAccountHasCustomFolders)
|
||||
ctx.Step(`^the account "([^"]*)" has (\d+) custom labels$`, s.theAccountHasCustomLabels)
|
||||
ctx.Step(`^the account "([^"]*)" has the following custom mailboxes:$`, s.theAccountHasTheFollowingCustomMailboxes)
|
||||
ctx.Step(`^the address "([^"]*)" of account "([^"]*)" has the following messages in "([^"]*)":$`, s.theAddressOfAccountHasTheFollowingMessagesInMailbox)
|
||||
ctx.Step(`^the address "([^"]*)" of account "([^"]*)" has (\d+) messages in "([^"]*)"$`, s.theAddressOfAccountHasMessagesInMailbox)
|
||||
ctx.Step(`^the address "([^"]*)" of account "([^"]*)" has no keys$`, s.theAddressOfAccountHasNoKeys)
|
||||
ctx.Step(`^the following fields were changed in draft (\d+) for address "([^"]*)" of account "([^"]*)":$`, s.theFollowingFieldsWereChangedInDraftForAddressOfAccount)
|
||||
|
||||
// ==== BRIDGE ====
|
||||
|
||||
@ -32,6 +32,7 @@ func (t *testCtx) withProton(fn func(*proton.Manager) error) error {
|
||||
m := proton.New(
|
||||
proton.WithHostURL(t.api.GetHostURL()),
|
||||
proton.WithTransport(proton.InsecureTransport()),
|
||||
proton.WithAppVersion(t.api.GetAppVersion()),
|
||||
)
|
||||
defer m.Close()
|
||||
|
||||
@ -65,10 +66,23 @@ func (t *testCtx) withClientPass(ctx context.Context, username, password string,
|
||||
}
|
||||
|
||||
// runQuarkCmd runs the given quark command with the given arguments.
|
||||
func (t *testCtx) runQuarkCmd(ctx context.Context, command string, args ...string) error {
|
||||
return t.withProton(func(m *proton.Manager) error {
|
||||
return m.Quark(ctx, command, args...)
|
||||
})
|
||||
func (t *testCtx) runQuarkCmd(ctx context.Context, command string, args ...string) ([]byte, error) {
|
||||
var out []byte
|
||||
|
||||
if err := t.withProton(func(m *proton.Manager) error {
|
||||
res, err := m.QuarkRes(ctx, command, args...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out = res
|
||||
|
||||
return nil
|
||||
}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (t *testCtx) withAddrKR(
|
||||
|
||||
@ -43,7 +43,7 @@ import (
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
var defaultVersion = semver.MustParse("1.0.0")
|
||||
var defaultVersion = semver.MustParse("3.0.6")
|
||||
|
||||
type testCtx struct {
|
||||
// These are the objects supporting the test.
|
||||
@ -104,7 +104,7 @@ func newTestCtx(tb testing.TB) *testCtx {
|
||||
|
||||
t := &testCtx{
|
||||
dir: dir,
|
||||
api: newFakeAPI(),
|
||||
api: newTestAPI(),
|
||||
netCtl: proton.NewNetCtl(),
|
||||
locator: locations.New(bridge.NewTestLocationsProvider(dir), "config-name"),
|
||||
storeKey: []byte("super-secret-store-key"),
|
||||
|
||||
@ -60,20 +60,12 @@ Feature: Bridge can fully sync an account
|
||||
| Labels | 0 | 0 |
|
||||
| Labels/three | 0 | 0 |
|
||||
|
||||
Scenario: If an address has no keys, the account is still synced
|
||||
Given the account "user" has additional address "alias@[domain]"
|
||||
And the account "user" has the following custom mailboxes:
|
||||
| name | type |
|
||||
| encrypted | folder |
|
||||
And the address "alias@[domain]" of account "user" has the following messages in "encrypted":
|
||||
| from | to | subject |
|
||||
| a@[domain] | a@[domain] | no key |
|
||||
| b@[domain] | b@[domain] | no key |
|
||||
And the address "alias@[domain]" of account "user" has no keys
|
||||
Scenario: If an address has no keys, it does not break other addresses
|
||||
Given the account "user" has additional address "alias@[domain]" without keys
|
||||
When the user logs in with username "user" and password "password"
|
||||
And user "user" finishes syncing
|
||||
When user "user" connects and authenticates IMAP client "1"
|
||||
Then IMAP client "1" eventually sees the following messages in "Folders/encrypted":
|
||||
| from | to | subject | mime-type |
|
||||
| a@[domain] | a@[domain] | no key | multipart/encrypted |
|
||||
| b@[domain] | b@[domain] | no key | multipart/encrypted |
|
||||
Then IMAP client "1" eventually sees the following messages in "Folders/one":
|
||||
| from | to | subject | unread |
|
||||
| a@[domain] | a@[domain] | one | true |
|
||||
| b@[domain] | b@[domain] | two | false |
|
||||
@ -35,7 +35,7 @@ import (
|
||||
|
||||
func (s *scenario) thereExistsAnAccountWithUsernameAndPassword(username, password string) error {
|
||||
// Create the user and generate its default address (with keys).
|
||||
if err := s.t.runQuarkCmd(
|
||||
if _, err := s.t.runQuarkCmd(
|
||||
context.Background(),
|
||||
"user:create",
|
||||
"--name", username,
|
||||
@ -51,6 +51,22 @@ func (s *scenario) thereExistsAnAccountWithUsernameAndPassword(username, passwor
|
||||
return err
|
||||
}
|
||||
|
||||
// Decrypt the user's encrypted ID for use with quark.
|
||||
userDecID, err := s.t.runQuarkCmd(context.Background(), "encryption:id", "--decrypt", user.ID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Upgrade the user to a paid account.
|
||||
if _, err := s.t.runQuarkCmd(
|
||||
context.Background(),
|
||||
"user:create:subscription",
|
||||
"--planID", "plus",
|
||||
string(userDecID),
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
addr, err := c.GetAddresses(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
@ -72,12 +88,51 @@ func (s *scenario) thereExistsAnAccountWithUsernameAndPassword(username, passwor
|
||||
func (s *scenario) theAccountHasAdditionalAddress(username, address string) error {
|
||||
userID := s.t.getUserID(username)
|
||||
|
||||
// Decrypt the user's encrypted ID for use with quark.
|
||||
userDecID, err := s.t.runQuarkCmd(context.Background(), "encryption:id", "--decrypt", userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the user's additional address.
|
||||
if err := s.t.runQuarkCmd(
|
||||
if _, err := s.t.runQuarkCmd(
|
||||
context.Background(),
|
||||
"user:create:address",
|
||||
"--gen-keys", "RSA2048",
|
||||
userID,
|
||||
string(userDecID),
|
||||
s.t.getUserPass(userID),
|
||||
address,
|
||||
); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return s.t.withClient(context.Background(), username, func(ctx context.Context, c *proton.Client) error {
|
||||
addr, err := c.GetAddresses(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Set the new address of the user.
|
||||
s.t.setUserAddr(userID, addr[len(addr)-1].ID, address)
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (s *scenario) theAccountHasAdditionalAddressWithoutKeys(username, address string) error {
|
||||
userID := s.t.getUserID(username)
|
||||
|
||||
// Decrypt the user's encrypted ID for use with quark.
|
||||
userDecID, err := s.t.runQuarkCmd(context.Background(), "--decrypt", "encryption:id", userID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create the user's additional address.
|
||||
if _, err := s.t.runQuarkCmd(
|
||||
context.Background(),
|
||||
"user:create:address",
|
||||
string(userDecID),
|
||||
s.t.getUserPass(userID),
|
||||
address,
|
||||
); err != nil {
|
||||
@ -241,26 +296,6 @@ func (s *scenario) theAddressOfAccountHasMessagesInMailbox(address, username str
|
||||
})))
|
||||
}
|
||||
|
||||
func (s *scenario) theAddressOfAccountHasNoKeys(address, username string) error {
|
||||
userID := s.t.getUserID(username)
|
||||
addrID := s.t.getUserAddrID(userID, address)
|
||||
|
||||
return s.t.withClient(context.Background(), username, func(ctx context.Context, client *proton.Client) error {
|
||||
address, err := client.GetAddress(ctx, addrID)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, key := range address.Keys {
|
||||
if err := s.t.api.RemoveAddressKey(userID, addrID, key.ID); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
// accountDraftChanged changes the draft attributes, where draftIndex is
|
||||
// similar to sequential ID i.e. 1 represents the first message of draft folder
|
||||
// sorted by API creation time.
|
||||
|
||||
Reference in New Issue
Block a user