Skip to content

Commit

Permalink
Add Stop/StartServer functions to Deployment (#692)
Browse files Browse the repository at this point in the history
* Add Stop/StartServer functions to Deployment

This will be used to test connectivity issues over federation.

* Add pause/unpause to keep ports stable

* Better docs

---------

Co-authored-by: Kegan Dougal <=>
  • Loading branch information
kegsay authored Nov 21, 2023
1 parent 971b5e1 commit f8f2b2a
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 11 deletions.
50 changes: 41 additions & 9 deletions internal/docker/deployer.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,33 +250,65 @@ func (d *Deployer) executePostScript(hsDep *HomeserverDeployment, testName strin
return cmd.CombinedOutput()
}

// Restart a homeserver deployment.
func (d *Deployer) Restart(hsDep *HomeserverDeployment, cfg *config.Complement) error {
func (d *Deployer) PauseServer(hsDep *HomeserverDeployment) error {
ctx := context.Background()
err := d.Docker.ContainerPause(ctx, hsDep.ContainerID)
if err != nil {
return fmt.Errorf("failed to pause container %s: %s", hsDep.ContainerID, err)
}
return nil
}

func (d *Deployer) UnpauseServer(hsDep *HomeserverDeployment) error {
ctx := context.Background()
secs := int(cfg.SpawnHSTimeout.Seconds())
err := d.Docker.ContainerUnpause(ctx, hsDep.ContainerID)
if err != nil {
return fmt.Errorf("failed to unpause container %s: %s", hsDep.ContainerID, err)
}
return nil
}

func (d *Deployer) StopServer(hsDep *HomeserverDeployment) error {
ctx := context.Background()
secs := int(d.config.SpawnHSTimeout.Seconds())
err := d.Docker.ContainerStop(ctx, hsDep.ContainerID, container.StopOptions{
Timeout: &secs,
})
if err != nil {
return fmt.Errorf("Restart: Failed to stop container %s: %s", hsDep.ContainerID, err)
return fmt.Errorf("failed to stop container %s: %s", hsDep.ContainerID, err)
}
return nil
}

err = d.Docker.ContainerStart(ctx, hsDep.ContainerID, types.ContainerStartOptions{})
// Restart a homeserver deployment.
func (d *Deployer) Restart(hsDep *HomeserverDeployment) error {
if err := d.StopServer(hsDep); err != nil {
return fmt.Errorf("Restart: %s", err)
}
if err := d.StartServer(hsDep); err != nil {
return fmt.Errorf("Restart: %s", err)
}
return nil
}

func (d *Deployer) StartServer(hsDep *HomeserverDeployment) error {
ctx := context.Background()
err := d.Docker.ContainerStart(ctx, hsDep.ContainerID, types.ContainerStartOptions{})
if err != nil {
return fmt.Errorf("Restart: Failed to start container %s: %s", hsDep.ContainerID, err)
return fmt.Errorf("failed to start container %s: %s", hsDep.ContainerID, err)
}

// Wait for the container to be ready.
baseURL, fedBaseURL, err := waitForPorts(ctx, d.Docker, hsDep.ContainerID)
if err != nil {
return fmt.Errorf("Restart: Failed to get ports for container %s: %s", hsDep.ContainerID, err)
return fmt.Errorf("failed to get ports for container %s: %s", hsDep.ContainerID, err)
}
hsDep.SetEndpoints(baseURL, fedBaseURL)

stopTime := time.Now().Add(cfg.SpawnHSTimeout)
stopTime := time.Now().Add(d.config.SpawnHSTimeout)
_, err = waitForContainer(ctx, d.Docker, hsDep, stopTime)
if err != nil {
return fmt.Errorf("Restart: Failed to restart container %s: %s", hsDep.ContainerID, err)
return fmt.Errorf("failed to wait for container %s: %s", hsDep.ContainerID, err)
}

return nil
Expand Down
46 changes: 45 additions & 1 deletion internal/docker/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,7 @@ func (d *Deployment) AppServiceUser(t *testing.T, hsName, appServiceUserID strin
func (d *Deployment) Restart(t *testing.T) error {
t.Helper()
for _, hsDep := range d.HS {
err := d.Deployer.Restart(hsDep, d.Config)
err := d.Deployer.Restart(hsDep)
if err != nil {
t.Errorf("Deployment.Restart: %s", err)
return err
Expand All @@ -238,3 +238,47 @@ func (d *Deployment) Restart(t *testing.T) error {

return nil
}

func (d *Deployment) StartServer(t *testing.T, hsName string) {
t.Helper()
hsDep := d.HS[hsName]
if hsDep == nil {
t.Fatalf("StartServer: %s does not exist in this deployment", hsName)
}
if err := d.Deployer.StartServer(hsDep); err != nil {
t.Fatalf("StartServer: %s", err)
}
}

func (d *Deployment) StopServer(t *testing.T, hsName string) {
t.Helper()
hsDep := d.HS[hsName]
if hsDep == nil {
t.Fatalf("StopServer: %s does not exist in this deployment", hsName)
}
if err := d.Deployer.StopServer(hsDep); err != nil {
t.Fatalf("StopServer: %s", err)
}
}

func (d *Deployment) PauseServer(t *testing.T, hsName string) {
t.Helper()
hsDep := d.HS[hsName]
if hsDep == nil {
t.Fatalf("PauseServer: %s does not exist in this deployment", hsName)
}
if err := d.Deployer.PauseServer(hsDep); err != nil {
t.Fatalf("PauseServer: %s", err)
}
}

func (d *Deployment) UnpauseServer(t *testing.T, hsName string) {
t.Helper()
hsDep := d.HS[hsName]
if hsDep == nil {
t.Fatalf("UnpauseServer: %s does not exist in this deployment", hsName)
}
if err := d.Deployer.UnpauseServer(hsDep); err != nil {
t.Fatalf("UnpauseServer: %s", err)
}
}
23 changes: 22 additions & 1 deletion test_package.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,29 @@ type Deployment interface {
// 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 a deployment. Restarts all homeservers in this deployment.
// This function is designed to be used to make assertions that servers are persisting information to disk.
Restart(t *testing.T) error
// Stop the container running this HS. Fails the test if this is not possible.
// This function is designed to be used to make assertions when federated servers are unreachable.
// Do not use this function if you need the HS CSAPI URL to be stable, prefer PauseServer if you need this.
StopServer(t *testing.T, hsName string)
// Start the container running this HS. The HS must exist in this deployment already and it must be stopped already.
// Fails the test if this isn't true, or there was a problem.
// This function is designed to be used to start a server previously stopped via StopServer.
// Do not use this function if you need the HS CSAPI URL to be stable, prefer UnpauseServer if you need this.
StartServer(t *testing.T, hsName string)
// Pause a running homeserver. The HS will be suspended, preserving data in memory.
// Prefer this function over StopServer if you need to keep the port allocations stable across your test.
// This function is designed to be used to make assertions when federated servers are unreachable.
// Fails the test if there is a problem pausing.
// See https://docs.docker.com/engine/reference/commandline/pause/
PauseServer(t *testing.T, hsName string)
// Unpause a running homeserver. The HS will be suspended, preserving data in memory.
// Fails the test if there is a problem unpausing.
// This function is designed to be used to make assertions when federated servers are unreachable.
// see https://docs.docker.com/engine/reference/commandline/unpause/
UnpauseServer(t *testing.T, hsName string)
// Destroy the entire deployment. Destroys all running containers. If `printServerLogs` is true,
// will print container logs before killing the container.
Destroy(t *testing.T)
Expand Down

0 comments on commit f8f2b2a

Please sign in to comment.