Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove Deployment.Client and change Deploy #676

Merged
merged 7 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ const ansiResetForeground = "\x1b[39m"

// errorf is a wrapper around t.Errorf which prints the failing error message in red.
func errorf(t TestLike, format string, args ...any) {
t.Helper()
format = ansiRedForeground + format + ansiResetForeground
t.Errorf(format, args...)
}

// fatalf is a wrapper around t.Fatalf which prints the failing error message in red.
func fatalf(t TestLike, format string, args ...any) {
t.Helper()
format = ansiRedForeground + format + ansiResetForeground
t.Fatalf(format, args...)
}
Expand Down
53 changes: 39 additions & 14 deletions internal/docker/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ type HomeserverDeployment struct {
accessTokensMutex sync.RWMutex
ApplicationServices map[string]string // e.g { "my-as-id": "id: xxx\nas_token: xxx ..."} }
DeviceIDs map[string]string // e.g { "@alice:hs1": "myDeviceID" }
CSAPIClients []*client.CSAPI
CSAPIClientsMutex sync.Mutex

// track all clients so if Restart() is called we can repoint to the new high-numbered port
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm failing to understand this comment, but maybe I'll get it once I'm further in the review

CSAPIClients []*client.CSAPI
CSAPIClientsMutex sync.Mutex
}

// Updates the client and federation base URLs of the homeserver deployment.
Expand Down Expand Up @@ -85,7 +87,11 @@ func (d *Deployment) Register(t *testing.T, hsName string, opts helpers.Registra
if password == "" {
password = "complement_meets_min_password_req"
}
localpart := fmt.Sprintf("user-%v-%v", d.localpartCounter.Add(1), opts.LocalpartSuffix)

localpart := fmt.Sprintf("user-%v", d.localpartCounter.Add(1))
if opts.LocalpartSuffix != "" {
localpart += fmt.Sprintf("-%s", opts.LocalpartSuffix)
}
var userID, accessToken, deviceID string
if opts.IsAdmin {
userID, accessToken, deviceID = client.RegisterSharedSecret(t, localpart, password, opts.IsAdmin)
Expand Down Expand Up @@ -133,29 +139,48 @@ func (d *Deployment) Login(t *testing.T, hsName string, existing *client.CSAPI,
return client
}

// Client returns a CSAPI client targeting the given hsName, using the access token for the given userID.
// Fails the test if the hsName is not found. Returns an unauthenticated client if userID is "", fails the test
// if the userID is otherwise not found.
func (d *Deployment) Client(t *testing.T, hsName, userID string) *client.CSAPI {
func (d *Deployment) UnauthenticatedClient(t *testing.T, hsName string) *client.CSAPI {
t.Helper()
dep, ok := d.HS[hsName]
if !ok {
t.Fatalf("Deployment.Client - HS name '%s' not found", hsName)
return nil
}
client := &client.CSAPI{
BaseURL: dep.BaseURL,
Client: client.NewLoggedClient(t, hsName, nil),
SyncUntilTimeout: 5 * time.Second,
Debug: d.Deployer.debugLogging,
}
// Appending a slice is not thread-safe. Protect the write with a mutex.
dep.CSAPIClientsMutex.Lock()
dep.CSAPIClients = append(dep.CSAPIClients, client)
dep.CSAPIClientsMutex.Unlock()
return client
}

// AppServiceUser returns a client for the given app service user ID. The HS in question must have an appservice
// hooked up to it already. TODO: REMOVE
func (d *Deployment) AppServiceUser(t *testing.T, hsName, appServiceUserID string) *client.CSAPI {
t.Helper()
dep, ok := d.HS[hsName]
if !ok {
t.Fatalf("Deployment.Client - HS name '%s' not found", hsName)
return nil
}
dep.accessTokensMutex.RLock()
token := dep.AccessTokens[userID]
token := dep.AccessTokens[appServiceUserID]
dep.accessTokensMutex.RUnlock()
if token == "" && userID != "" {
t.Fatalf("Deployment.Client - HS name '%s' - user ID '%s' not found", hsName, userID)
if token == "" && appServiceUserID != "" {
t.Fatalf("Deployment.Client - HS name '%s' - user ID '%s' not found", hsName, appServiceUserID)
return nil
}
deviceID := dep.DeviceIDs[userID]
if deviceID == "" && userID != "" {
t.Logf("WARNING: Deployment.Client - HS name '%s' - user ID '%s' - deviceID not found", hsName, userID)
deviceID := dep.DeviceIDs[appServiceUserID]
if deviceID == "" && appServiceUserID != "" {
t.Logf("WARNING: Deployment.Client - HS name '%s' - user ID '%s' - deviceID not found", hsName, appServiceUserID)
}
client := &client.CSAPI{
UserID: userID,
UserID: appServiceUserID,
AccessToken: token,
DeviceID: deviceID,
BaseURL: dep.BaseURL,
Expand Down
15 changes: 13 additions & 2 deletions test_main.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,21 @@ func TestMain(m *testing.M, namespace string) {
// It will construct the blueprint if it doesn't already exist in the docker image cache.
// This function is the main setup function for all tests as it provides a deployment with
// which tests can interact with.
func Deploy(t *testing.T, blueprint b.Blueprint) Deployment {
func OldDeploy(t *testing.T, blueprint b.Blueprint) Deployment {
t.Helper()
if testPackage == nil {
t.Fatalf("Deploy: testPackage not set, did you forget to call complement.TestMain?")
}
return testPackage.Deploy(t, blueprint)
return testPackage.OldDeploy(t, blueprint)
}

// Deploy will deploy the given number of servers or terminate the test.
// This function is the main setup function for all tests as it provides a deployment with
// which tests can interact with.
func Deploy(t *testing.T, numServers int) Deployment {
t.Helper()
if testPackage == nil {
t.Fatalf("Deploy: testPackage not set, did you forget to call complement.TestMain?")
}
return testPackage.Deploy(t, numServers)
}
46 changes: 39 additions & 7 deletions test_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,16 @@ import (

// Deployment provides a way for tests to interact with a set of homeservers.
type Deployment interface {
// Client returns a CSAPI client targeting the given hsName, using the access token for the given userID.
// Fails the test if the hsName is not found. Returns an unauthenticated client if userID is "", fails the test
// if the userID is otherwise not found.
Client(t *testing.T, serverName, userID string) *client.CSAPI
// UnauthenticatedClient returns a blank CSAPI client.
UnauthenticatedClient(t *testing.T, serverName string) *client.CSAPI
// Register a new user on the given server.
Register(t *testing.T, hsName string, opts helpers.RegistrationOpts) *client.CSAPI
kegsay marked this conversation as resolved.
Show resolved Hide resolved
// Login to an existing user account on the given server. In order to make tests not hardcode full user IDs,
// an existing logged in client must be supplied.
Login(t *testing.T, hsName string, existing *client.CSAPI, opts helpers.LoginOpts) *client.CSAPI
// AppServiceUser returns a client for the given app service user ID. The HS in question must have an appservice
// hooked up to it already. TODO: REMOVE
AppServiceUser(t *testing.T, hsName, appServiceUserID string) *client.CSAPI
// Restart a deployment.
Restart(t *testing.T) error
// Destroy the entire deployment. Destroys all running containers. If `printServerLogs` is true,
Expand Down Expand Up @@ -82,9 +83,30 @@ func (tp *TestPackage) Cleanup() {
// It will construct the blueprint if it doesn't already exist in the docker image cache.
// This function is the main setup function for all tests as it provides a deployment with
// which tests can interact with.
func (tp *TestPackage) Deploy(t *testing.T, blueprint b.Blueprint) Deployment {
func (tp *TestPackage) OldDeploy(t *testing.T, blueprint b.Blueprint) Deployment {
t.Helper()
timeStartBlueprint := time.Now()
if err := tp.complementBuilder.ConstructBlueprintIfNotExist(blueprint); err != nil {
t.Fatalf("OldDeploy: Failed to construct blueprint: %s", err)
}
namespace := fmt.Sprintf("%d", atomic.AddUint64(&tp.namespaceCounter, 1))
d, err := docker.NewDeployer(namespace, tp.complementBuilder.Config)
if err != nil {
t.Fatalf("OldDeploy: NewDeployer returned error %s", err)
}
timeStartDeploy := time.Now()
dep, err := d.Deploy(context.Background(), blueprint.Name)
if err != nil {
t.Fatalf("OldDeploy: Deploy returned error %s", err)
}
t.Logf("OldDeploy times: %v blueprints, %v containers", timeStartDeploy.Sub(timeStartBlueprint), time.Since(timeStartDeploy))
return dep
}

func (tp *TestPackage) Deploy(t *testing.T, numServers int) Deployment {
kegsay marked this conversation as resolved.
Show resolved Hide resolved
t.Helper()
blueprint := mapServersToBlueprint(numServers)
timeStartBlueprint := time.Now()
if err := tp.complementBuilder.ConstructBlueprintIfNotExist(blueprint); err != nil {
t.Fatalf("Deploy: Failed to construct blueprint: %s", err)
}
Expand All @@ -102,6 +124,16 @@ func (tp *TestPackage) Deploy(t *testing.T, blueprint b.Blueprint) Deployment {
return dep
}

func (tp *TestPackage) DeployDirty(t *testing.T, numServers int) Deployment {
return nil
// converts the requested number of servers into a single blueprint, which can be deployed using normal blueprint machinery.
func mapServersToBlueprint(numServers int) b.Blueprint {
servers := make([]b.Homeserver, numServers)
for i := range servers {
servers[i] = b.Homeserver{
Name: fmt.Sprintf("hs%d", i+1), // hs1,hs2,...
}
}
return b.MustValidate(b.Blueprint{
Name: fmt.Sprintf("%d_servers", numServers),
Homeservers: servers,
})
}
3 changes: 1 addition & 2 deletions tests/csapi/account_change_password_pushers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"testing"

"github.com/matrix-org/complement"
"github.com/matrix-org/complement/b"
"github.com/matrix-org/complement/client"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/match"
Expand All @@ -17,7 +16,7 @@ import (
)

func TestChangePasswordPushers(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintAlice)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)
password1 := "superuser"
password2 := "my_new_password"
Expand Down
7 changes: 3 additions & 4 deletions tests/csapi/account_change_password_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"testing"

"github.com/matrix-org/complement"
"github.com/matrix-org/complement/b"
"github.com/matrix-org/complement/client"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/match"
Expand All @@ -15,14 +14,14 @@ import (
)

func TestChangePassword(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintAlice)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)
password1 := "superuser"
password2 := "my_new_password"
passwordClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{
Password: password1,
})
unauthedClient := deployment.Client(t, "hs1", "")
unauthedClient := deployment.UnauthenticatedClient(t, "hs1")
_, sessionTest := createSession(t, deployment, passwordClient.UserID, "superuser")
// sytest: After changing password, can't log in with old password
t.Run("After changing password, can't log in with old password", func(t *testing.T) {
Expand Down Expand Up @@ -124,7 +123,7 @@ func changePassword(t *testing.T, passwordClient *client.CSAPI, oldPassword stri
}

func createSession(t *testing.T, deployment complement.Deployment, userID, password string) (deviceID string, authedClient *client.CSAPI) {
authedClient = deployment.Client(t, "hs1", "")
authedClient = deployment.UnauthenticatedClient(t, "hs1")
reqBody := client.WithJSONBody(t, map[string]interface{}{
"identifier": map[string]interface{}{
"type": "m.id.user",
Expand Down
6 changes: 3 additions & 3 deletions tests/csapi/account_data_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ import (
"testing"

"github.com/matrix-org/complement"
"github.com/matrix-org/complement/b"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/match"
"github.com/matrix-org/complement/must"
)

func TestAddAccountData(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintOneToOneRoom)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)

alice := deployment.Client(t, "hs1", "@alice:hs1")
alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{})

// sytest: Can add account data
// sytest: Can get account data without syncing
Expand Down
5 changes: 2 additions & 3 deletions tests/csapi/account_deactivate_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,21 +7,20 @@ import (
"github.com/tidwall/gjson"

"github.com/matrix-org/complement"
"github.com/matrix-org/complement/b"
"github.com/matrix-org/complement/client"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/match"
"github.com/matrix-org/complement/must"
)

func TestDeactivateAccount(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintAlice)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)
password := "superuser"
authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{
Password: password,
})
unauthedClient := deployment.Client(t, "hs1", "")
unauthedClient := deployment.UnauthenticatedClient(t, "hs1")

// Ensure that the first step, in which the client queries the server's user-interactive auth flows, returns
// at least one auth flow involving a password.
Expand Down
9 changes: 4 additions & 5 deletions tests/csapi/admin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"github.com/tidwall/gjson"

"github.com/matrix-org/complement"
"github.com/matrix-org/complement/b"
"github.com/matrix-org/complement/client"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/match"
Expand All @@ -18,7 +17,7 @@ import (
// Check if this homeserver supports Synapse-style admin registration.
// Not all images support this currently.
func TestCanRegisterAdmin(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintAlice)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)
deployment.Register(t, "hs1", helpers.RegistrationOpts{
IsAdmin: true,
Expand All @@ -27,15 +26,15 @@ func TestCanRegisterAdmin(t *testing.T) {

// Test if the implemented /_synapse/admin/v1/send_server_notice behaves as expected
func TestServerNotices(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintAlice)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)
admin := deployment.Register(t, "hs1", helpers.RegistrationOpts{
IsAdmin: true,
})
alice := deployment.Client(t, "hs1", "@alice:hs1")
alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{})

reqBody := client.WithJSONBody(t, map[string]interface{}{
"user_id": "@alice:hs1",
"user_id": alice.UserID,
"content": map[string]interface{}{
"msgtype": "m.text",
"body": "hello from server notices!",
Expand Down
6 changes: 3 additions & 3 deletions tests/csapi/apidoc_content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,15 @@ import (
"testing"

"github.com/matrix-org/complement"
"github.com/matrix-org/complement/b"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/internal/data"
)

func TestContent(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintAlice)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)

alice := deployment.Client(t, "hs1", "@alice:hs1")
alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{})
wantContentType := "image/png"
// sytest: POST /media/v3/upload can create an upload
mxcUri := alice.UploadContent(t, data.MatrixPng, "test.png", wantContentType)
Expand Down
5 changes: 2 additions & 3 deletions tests/csapi/apidoc_device_management_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,16 @@ import (
"github.com/tidwall/gjson"

"github.com/matrix-org/complement"
"github.com/matrix-org/complement/b"
"github.com/matrix-org/complement/client"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/match"
"github.com/matrix-org/complement/must"
)

func TestDeviceManagement(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintAlice)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)
unauthedClient := deployment.Client(t, "hs1", "")
unauthedClient := deployment.UnauthenticatedClient(t, "hs1")
authedClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{
Password: "superuser",
})
Expand Down
5 changes: 2 additions & 3 deletions tests/csapi/apidoc_login_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import (
"github.com/tidwall/gjson"

"github.com/matrix-org/complement"
"github.com/matrix-org/complement/b"
"github.com/matrix-org/complement/client"
"github.com/matrix-org/complement/helpers"
"github.com/matrix-org/complement/match"
Expand All @@ -18,9 +17,9 @@ import (
)

func TestLogin(t *testing.T) {
deployment := complement.Deploy(t, b.BlueprintAlice)
deployment := complement.Deploy(t, 1)
defer deployment.Destroy(t)
unauthedClient := deployment.Client(t, "hs1", "")
unauthedClient := deployment.UnauthenticatedClient(t, "hs1")
testClient := deployment.Register(t, "hs1", helpers.RegistrationOpts{
Password: "superuser",
})
Expand Down
Loading
Loading