Skip to content

Commit

Permalink
Add JS SDK sanity check with CI
Browse files Browse the repository at this point in the history
  • Loading branch information
kegsay committed Nov 1, 2023
1 parent de24154 commit c54b8d5
Show file tree
Hide file tree
Showing 15 changed files with 1,321 additions and 3 deletions.
90 changes: 90 additions & 0 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
name: Tests

on:
push:
branches: [ 'main' ]
pull_request:
workflow_dispatch:

jobs:
check-signoff:
if: "github.event_name == 'pull_request'"
uses: "matrix-org/backend-meta/.github/workflows/sign-off.yml@v2"


complement:
name: JS tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3 # Checkout crypto tests

# Install Node, Go and Rust, along with libolm and gotestfmt
- name: Setup | Node.js 18.x
uses: actions/setup-node@v3
with:
node-version: 18
cache: 'yarn'
- name: Setup | Go
uses: actions/setup-go@v4
- name: Setup | Rust stable
uses: ATiltedTree/setup-rust@v1
with:
rust-version: stable
- name: "Install Complement Dependencies"
run: |
sudo apt-get update && sudo apt-get install -y libolm3 libolm-dev
go install -v github.com/gotesttools/gotestfmt/v2/cmd/gotestfmt@latest
# Install whatever version of the JS SDK is in package.json
- name: Build JS SDK
run: |
cat ./js-sdk/package.json
(cd js-sdk && yarn install --frozen-lockfile && yarn build)
cp -r ./js-sdk/dist/. ./tests/dist
# Build homeserver image, honouring branch names
- name: "Checkout corresponding Synapse branch"
shell: bash
run: |
mkdir -p homeserver
# Attempt to use the version of the homeserver which best matches the
# current build.
#
# 1. If we are not on complement's default branch, check if there's a
# similarly named branch (GITHUB_HEAD_REF for pull requests,
# otherwise GITHUB_REF).
# 2. otherwise, use the default homeserver branch ("HEAD")
for BRANCH_NAME in "$GITHUB_HEAD_REF" "${GITHUB_REF#refs/heads/}" "HEAD"; do
# Skip empty branch names, merge commits, and our default branch.
# (If we are on complement's default branch, we want to fall through to the HS's default branch
# rather than using the HS's 'master'/'main').
case "$BRANCH_NAME" in
"" | refs/pull/* | main | master)
continue
;;
esac
(wget -O - "https://github.com/matrix-org/synapse/archive/$BRANCH_NAME.tar.gz" | tar -xz --strip-components=1 -C homeserver) && break
done
# Build the base Synapse dockerfile and then build a Complement-specific image from that base.
- run: |
docker build -t matrixdotorg/synapse:latest -f docker/Dockerfile .
docker build -t matrixdotorg/synapse-workers:latest -f docker/Dockerfile-workers .
docker build -t homeserver -f docker/complement/Dockerfile docker/complement
working-directory: homeserver
env:
DOCKER_BUILDKIT: 1
- run: |
set -o pipefail &&
go test -v -json -timeout 5m ./tests | gotestfmt
shell: bash # required for pipefail to be A Thing. pipefail is required to stop gotestfmt swallowing non-zero exit codes
name: Run Complement Crypto Tests
env:
COMPLEMENT_BASE_IMAGE: homeserver
COMPLEMENT_ENABLE_DIRTY_RUNS: 1
COMPLEMENT_SHARE_ENV_PREFIX: PASS_
PASS_SYNAPSE_COMPLEMENT_DATABASE: sqlite
DOCKER_BUILDKIT: 1
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
js-sdk/node_modules
js-sdk/dist
tests/dist
52 changes: 49 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,50 @@
# .github
Default metadata files for repos in this org.
## Complement-Crypto

Complement for Rust SDK crypto.


### What is it? Why?

Complement-Crypto extends the existing Complement test suite to support full end-to-end testing of the Rust SDK. End-to-end testing is defined at the FFI / JS SDK layer through to a real homeserver, a real sliding sync proxy, real federation, to another rust SDK on FFI / JS SDK.

Why:
- To detect "unable to decrypt" failures and add regression tests for them.
- To date, there exists no test suite which meets the scope of Complement-Crypto.

### JS SDK

Prerequisites:
- A working Yarn/npm installation (version?)

This repo has a self-hosted copy of `matrix-js-sdk` which it will run in a headless chrome, in order to mimic Element Web (Rust Crypto edition).

In order to regenerate the JS SDK, run `./rebuild_js_sdk.sh` with an appropriate version.

### FFI Bindings (TODO)

Prerequisites:
- A working Rust installation (min version?)
- A working Go installation (1.19+?)

This repo has bindings to the `matrix_sdk` crate in rust SDK, in order to mimic Element X.

In order to generate these bindings, follow these instructions:
- Check out https://github.com/matrix-org/matrix-rust-sdk/tree/kegan/complement-test-fork (TODO: go back to main when async fns work with bindgen)
- Get the bindings generator: (TODO: recheck if https://github.com/NordSecurity/uniffi-bindgen-go/pull/13 lands)
```
git clone https://github.com/dignifiedquire/uniffi-bindgen-go.git
cd uniffi-bindgen-go
git checkout upgarde-uniffi-24
git submodule init
git submodule update
cd ..
cargo install uniffi-bindgen-go --path ./uniffi-bindgen-go/bindgen
```
- Compile the rust SDK: `cargo xtask ci bindings`. Check that `target/debug/libmatrix_sdk_ffi.a` exists.
- Generate the Go bindings to `./sdk`: `uniffi-bindgen-go -l ../matrix-rust-sdk/target/debug/libmatrix_sdk_ffi.a -o ./sdk ../matrix-rust-sdk/bindings/matrix-sdk-ffi/src/api.udl`
- Patch up the generated code as it's not quite right:
```
TODO
```
- Sanity check compile `LIBRARY_PATH=/path/to/matrix-rust-sdk/target/debug go test -c ./tests`

If you're seeing this readme in your project, your project is configured wrong.
1 change: 1 addition & 0 deletions chrome/callbacks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
package chrome
46 changes: 46 additions & 0 deletions chrome/exec.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package chrome

import (
"context"
"testing"

"github.com/chromedp/cdproto/runtime"
"github.com/chromedp/chromedp"
"github.com/matrix-org/complement/must"
)

func MustExecuteInto[T any](t *testing.T, ctx context.Context, js string) T {
t.Helper()
out, err := ExecuteInto[T](t, ctx, js)
must.NotError(t, js, err)
return *out
}

func ExecuteInto[T any](t *testing.T, ctx context.Context, js string) (*T, error) {
t.Helper()
t.Log(js)
out := new(T)
err := chromedp.Run(ctx,
chromedp.Evaluate(js, &out),
)
if err != nil {
return nil, err
}
return out, nil
}

func AwaitExecute(t *testing.T, ctx context.Context, js string) error {
var r *runtime.RemoteObject // stop large responses causing errors "Object reference chain is too long (-32000)"
t.Log(js)
return chromedp.Run(ctx,
chromedp.Evaluate(js, &r, func(p *runtime.EvaluateParams) *runtime.EvaluateParams {
return p.WithAwaitPromise(true)
}),
)
}

func MustAwaitExecute(t *testing.T, ctx context.Context, js string) {
t.Helper()
err := AwaitExecute(t, ctx, js)
must.NotError(t, js, err)
}
127 changes: 127 additions & 0 deletions deploy/deploy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
package deploy

import (
"context"
"fmt"
"log"
"testing"
"time"

"github.com/docker/go-connections/nat"
"github.com/matrix-org/complement"
"github.com/matrix-org/complement/must"
testcontainers "github.com/testcontainers/testcontainers-go"
"github.com/testcontainers/testcontainers-go/wait"
)

type SlidingSyncDeployment struct {
complement.Deployment
postgres testcontainers.Container
slidingSync testcontainers.Container
slidingSyncURL string
}

func (d *SlidingSyncDeployment) SlidingSyncURL(t *testing.T) string {
t.Helper()
if d.slidingSync == nil || d.slidingSyncURL == "" {
t.Fatalf("SlidingSyncURL: not set")
return ""
}
return d.slidingSyncURL
}

func (d *SlidingSyncDeployment) Teardown() {
if d.slidingSync != nil {
if err := d.slidingSync.Terminate(context.Background()); err != nil {
log.Fatalf("failed to stop sliding sync: %s", err)
}
}
if d.postgres != nil {
if err := d.postgres.Terminate(context.Background()); err != nil {
log.Fatalf("failed to stop postgres: %s", err)
}
}
}

func RunNewDeployment(t *testing.T) *SlidingSyncDeployment {
// allow 30s for everything to deploy
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer cancel()

// Deploy the homeserver using Complement
deployment := complement.Deploy(t, 1)
networkName := deployment.Network()

// Make a postgres container
postgresContainer, err := testcontainers.GenericContainer(context.Background(), testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "postgres:13-alpine",
ExposedPorts: []string{"5432/tcp"},
Env: map[string]string{
"POSTGRES_USER": "postgres",
"POSTGRES_PASSWORD": "postgres",
"POSTGRES_DB": "syncv3",
},
WaitingFor: wait.ForExec([]string{"pg_isready"}).WithExitCodeMatcher(func(exitCode int) bool {
fmt.Println("pg_isready exit code", exitCode)
return exitCode == 0
}).WithPollInterval(time.Second),
Networks: []string{networkName},
NetworkAliases: map[string][]string{
networkName: {"postgres"},
},
},
Started: true,
})
must.NotError(t, "failed to start postgres container", err)

// Make a sliding sync proxy
ssExposedPort := "6789/tcp"
ssContainer, err := testcontainers.GenericContainer(ctx,
testcontainers.GenericContainerRequest{
ContainerRequest: testcontainers.ContainerRequest{
Image: "ghcr.io/matrix-org/sliding-sync:v0.99.11",
ExposedPorts: []string{ssExposedPort},
Env: map[string]string{
"SYNCV3_SECRET": "secret",
"SYNCV3_BINDADDR": ":6789",
"SYNCV3_SERVER": "http://hs1:8008",
"SYNCV3_DB": "user=postgres dbname=syncv3 sslmode=disable password=postgres host=postgres",
},
WaitingFor: wait.ForLog("listening on"),
Networks: []string{networkName},
NetworkAliases: map[string][]string{
networkName: {"ssproxy"},
},
},
Started: true,
})
must.NotError(t, "failed to start sliding sync container", err)

ssURL := externalURL(t, ssContainer, ssExposedPort)
csapi := deployment.UnauthenticatedClient(t, "hs1")

// log for debugging purposes
t.Logf("SlidingSyncDeployment created (network=%s):", networkName)
t.Logf(" NAME INT / EXT")
t.Logf(" sliding sync: ssproxy / %s", ssURL)
t.Logf(" synapse: hs1 / %s", csapi.BaseURL)
t.Logf(" postgres: postgres")
return &SlidingSyncDeployment{
Deployment: deployment,
slidingSync: ssContainer,
postgres: postgresContainer,
slidingSyncURL: ssURL,
}
}

func externalURL(t *testing.T, c testcontainers.Container, exposedPort string) string {
t.Helper()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
host, err := c.Host(ctx)
must.NotError(t, "failed to get host", err)
mappedPort, err := c.MappedPort(ctx, nat.Port(exposedPort))
must.NotError(t, "failed to get mapped port", err)
return fmt.Sprintf("http://%s:%s", host, mappedPort.Port())
}
70 changes: 70 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
module github.com/matrix-org/complement-crypto

go 1.20

require (
github.com/chromedp/cdproto v0.0.0-20231025043423-5615e204d422
github.com/chromedp/chromedp v0.9.3
github.com/docker/go-connections v0.4.0
github.com/matrix-org/complement v0.0.0-20231030161126-e811566d9bb6
github.com/testcontainers/testcontainers-go v0.26.0
)

require (
dario.cat/mergo v1.0.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/Microsoft/go-winio v0.6.1 // indirect
github.com/Microsoft/hcsshim v0.11.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/chromedp/sysutil v1.0.0 // indirect
github.com/containerd/containerd v1.7.7 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/cpuguy83/dockercfg v0.3.1 // indirect
github.com/docker/distribution v2.8.2+incompatible // indirect
github.com/docker/docker v24.0.7+incompatible // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
github.com/gobwas/ws v1.3.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/klauspost/compress v1.16.0 // indirect
github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect
github.com/magiconair/properties v1.8.7 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 // indirect
github.com/matrix-org/gomatrixserverlib v0.0.0-20230921171121-0466775328c7 // indirect
github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 // indirect
github.com/moby/patternmatcher v0.6.0 // indirect
github.com/moby/sys/sequential v0.5.0 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0-rc5 // indirect
github.com/opencontainers/runc v1.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
github.com/shirou/gopsutil/v3 v3.23.9 // indirect
github.com/shoenig/go-m1cpu v0.1.6 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/tidwall/gjson v1.16.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.1 // indirect
github.com/tidwall/sjson v1.2.5 // indirect
github.com/tklauser/go-sysconf v0.3.12 // indirect
github.com/tklauser/numcpus v0.6.1 // indirect
github.com/yusufpapurcu/wmi v1.2.3 // indirect
golang.org/x/crypto v0.14.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/net v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/tools v0.13.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/grpc v1.57.1 // indirect
google.golang.org/protobuf v1.30.0 // indirect
maunium.net/go/mautrix v0.11.0 // indirect
)
Loading

0 comments on commit c54b8d5

Please sign in to comment.