diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index d3ea9cec6..739dddae7 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -17,7 +17,7 @@ jobs: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: persist-credentials: false - - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version-file: go.mod - name: "Run internal Complement tests" @@ -46,7 +46,7 @@ jobs: - homeserver: Synapse repo: famedly/synapse tags: synapse_blacklist - packages: ./tests/msc3874 ./tests/msc3902 ./tests/msc4306 + packages: ./tests/msc3874 ./tests/msc3902 ./tests/msc4306 ./tests/msc4429 env: "COMPLEMENT_ENABLE_DIRTY_RUNS=1 COMPLEMENT_SHARE_ENV_PREFIX=PASS_ PASS_SYNAPSE_COMPLEMENT_DATABASE=sqlite" timeout: 20m @@ -62,7 +62,7 @@ jobs: with: persist-credentials: false - - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 + - uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0 with: go-version-file: go.mod diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0e5ea0e51..6c9dc358d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ We ask that everybody who contributes to this project signs off their contributi We follow a simple 'inbound=outbound' model for contributions: the act of submitting an 'inbound' contribution means that the contributor agrees to license their contribution under the same terms as the project's overall 'outbound' license - in our case, this is Apache Software License v2 (see [LICENSE](./LICENSE)). -In order to have a concrete record that your contribution is intentional and you agree to license it under the same terms as the project's license, we've adopted the same lightweight approach used by the [Linux Kernel](https://www.kernel.org/doc/html/latest/process/submitting-patches.html), [Docker](https://github.com/docker/docker/blob/master/CONTRIBUTING.md), and many other projects: the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). This is a simple declaration that you wrote the contribution or otherwise have the right to contribute it to Matrix: +In order to have a concrete record that your contribution is intentional and you agree to license it under the same terms as the project's license, we've adopted the same lightweight approach used by the [Linux Kernel](https://www.kernel.org/doc/html/latest/process/submitting-patches.html), [Docker](https://github.com/moby/moby/blob/master/CONTRIBUTING.md), and many other projects: the [Developer Certificate of Origin](https://developercertificate.org/) (DCO). This is a simple declaration that you wrote the contribution or otherwise have the right to contribute it to Matrix: ``` Developer Certificate of Origin diff --git a/cmd/perftest/snapshot.go b/cmd/perftest/snapshot.go index 3294ee068..9b407822c 100644 --- a/cmd/perftest/snapshot.go +++ b/cmd/perftest/snapshot.go @@ -5,8 +5,9 @@ import ( "encoding/json" "time" - "github.com/docker/docker/api/types/container" "github.com/matrix-org/complement/internal/docker" + "github.com/moby/moby/api/types/container" + "github.com/moby/moby/client" ) type Snapshot struct { @@ -26,7 +27,7 @@ type Snapshot struct { func snapshotStats(spanName, desc string, deployment *docker.Deployment, absDuration, duration time.Duration) (snapshots []Snapshot) { for hsName, hsInfo := range deployment.HS { - stats, err := deployment.Deployer.Docker.ContainerStatsOneShot(context.Background(), hsInfo.ContainerID) + stats, err := deployment.Deployer.Docker.ContainerStats(context.Background(), hsInfo.ContainerID, client.ContainerStatsOptions{}) if err != nil { return nil } diff --git a/go.mod b/go.mod index f98df2f8d..fec5f3bcd 100644 --- a/go.mod +++ b/go.mod @@ -3,12 +3,12 @@ module github.com/matrix-org/complement go 1.25.0 require ( - github.com/docker/docker v28.5.2+incompatible - github.com/docker/go-connections v0.7.0 github.com/gorilla/mux v1.8.1 github.com/matrix-org/gomatrix v0.0.0-20220926102614-ceba4d9f7530 github.com/matrix-org/gomatrixserverlib v0.0.0-20260506075950-c9c468727353 github.com/matrix-org/util v0.0.0-20221111132719-399730281e66 + github.com/moby/moby/api v1.55.0 + github.com/moby/moby/client v0.5.1 github.com/sirupsen/logrus v1.9.4 github.com/tidwall/gjson v1.19.0 github.com/tidwall/sjson v1.2.5 @@ -22,41 +22,34 @@ require ( codeberg.org/go-latex/latex v0.2.0 // indirect codeberg.org/go-pdf/fpdf v0.11.1 // indirect git.sr.ht/~sbinet/gg v0.7.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/containerd/errdefs v1.0.0 // indirect github.com/containerd/errdefs/pkg v0.3.0 // indirect - github.com/containerd/log v0.1.0 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/go-units v0.4.0 // indirect + github.com/docker/go-connections v0.7.0 // indirect + github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-logr/logr v1.4.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/hashicorp/go-set/v3 v3.0.0 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect - github.com/moby/sys/atomicwriter v0.1.0 // indirect - github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect - github.com/morikuni/aec v1.0.0 // indirect github.com/oleiade/lane/v2 v2.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect - github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect - github.com/pkg/errors v0.9.1 // indirect + github.com/opencontainers/image-spec v1.1.1 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.1 // indirect go.opentelemetry.io/auto/sdk v1.2.1 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect go.opentelemetry.io/otel v1.43.0 // indirect - go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 // indirect go.opentelemetry.io/otel/metric v1.43.0 // indirect go.opentelemetry.io/otel/sdk v1.43.0 // indirect + go.opentelemetry.io/otel/sdk/metric v1.43.0 // indirect go.opentelemetry.io/otel/trace v1.43.0 // indirect golang.org/x/image v0.41.0 // indirect golang.org/x/sys v0.46.0 // indirect golang.org/x/text v0.38.0 // indirect - golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac // indirect gonum.org/v1/gonum v0.17.0 // indirect - gotest.tools/v3 v3.0.3 // indirect ) diff --git a/go.sum b/go.sum index 3dd402e8a..93a3d7cd2 100644 --- a/go.sum +++ b/go.sum @@ -12,9 +12,6 @@ git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo= git.sr.ht/~sbinet/cmpimg v0.1.0/go.mod h1:FU12psLbF4TfNXkKH2ZZQ29crIqoiqTZmeQ7dkp/pxE= git.sr.ht/~sbinet/gg v0.7.0 h1:YmNf7YKd7diDMTPm86hZa1EM3pbkOyD/zzjl0LZUdNM= git.sr.ht/~sbinet/gg v0.7.0/go.mod h1:VYeli15tpMM4EvqlivlVbbyvWZlOU+EZn4XZmfBGUdM= -github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= @@ -22,27 +19,20 @@ github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw= github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM= -github.com/cenkalti/backoff/v5 v5.0.3 h1:ZN+IMa753KfX5hd8vVaMixjnqRZ3y8CuJKRKj1xcsSM= -github.com/cenkalti/backoff/v5 v5.0.3/go.mod h1:rkhZdG3JZukswDf7f0cwqPNk4K0sa+F97BxZthm/crw= github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= -github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= -github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v28.5.2+incompatible h1:DBX0Y0zAjZbSrm1uzOkdr1onVghKaftjlSWt4AFexzM= -github.com/docker/docker v28.5.2+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.7.0 h1:6SsRfJddP22WMrCkj19x9WKjEDTB+ahsdiGYf0mN39c= github.com/docker/go-connections v0.7.0/go.mod h1:no1qkHdjq7kLMGUXYAduOhYPSJxxvgWBh7ogVvptn3Q= -github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw= -github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= @@ -52,16 +42,12 @@ github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= -github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0/go.mod h1:JfhWUomR1baixubs02l85lZYYOm7LV6om4ceouMv45c= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542 h1:2VTzZjLZBgl62/EtslCrtky5vbi9dd7HrQPQIx6wqiw= github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI= github.com/hashicorp/go-set/v3 v3.0.0 h1:CaJBQvQCOWoftrBcDt7Nwgo0kdpmrKxar/x2o6pV9JA= @@ -77,30 +63,22 @@ github.com/miekg/dns v1.1.66 h1:FeZXOS3VCVsKnEAd+wBkjMC3D2K+ww66Cq3VnCINuJE= github.com/miekg/dns v1.1.66/go.mod h1:jGFzBsSNbJw6z1HYut1RKBKHA9PBdxeHrZG8J+gC2WE= github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= -github.com/moby/sys/atomicwriter v0.1.0 h1:kw5D/EqkBwsBFi0ss9v1VG3wIkVhzGvLklJ+w3A14Sw= -github.com/moby/sys/atomicwriter v0.1.0/go.mod h1:Ul8oqv2ZMNHOceF643P6FKPXeCmYtlQMvpizfsSoaWs= -github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= -github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 h1:yH0SvLzcbZxcJXho2yh7CqdENGMQe73Cw3woZBpPli0= -github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= -github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= -github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= +github.com/moby/moby/api v1.55.0 h1:2/sexvQyqIWS8pRSCFddBfpW2qE7vR7FCL+vN8pxwMc= +github.com/moby/moby/api v1.55.0/go.mod h1:+RQ6wluLwtYaTd1WnPLykIDPekkuyD/ROWQClE83pzs= +github.com/moby/moby/client v0.5.1 h1:tYNaJno4c0HXz12y5BiqEDy0rVTYkWzI26lGvnTMiJw= +github.com/moby/moby/client v0.5.1/go.mod h1:odLstlZ6uSnfvAgVxMpvgmb8SUdd+siH2T0GBuxVAlM= github.com/oleiade/lane/v2 v2.0.0 h1:XW/ex/Inr+bPkLd3O240xrFOhUkTd4Wy176+Gv0E3Qw= github.com/oleiade/lane/v2 v2.0.0/go.mod h1:i5FBPFAYSWCgLh58UkUGCChjcCzef/MI7PlQm2TKCeg= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= -github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec= -github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= -github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040= +github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shoenig/test v1.11.0 h1:NoPa5GIoBwuqzIviCrnUJa+t5Xb4xi5Z+zODJnIDsEQ= github.com/shoenig/test v1.11.0/go.mod h1:UxJ6u/x2v/TNs/LoLxBNJRV9DiwBBKYxXSyczsBHFoI= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= -github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tidwall/gjson v1.14.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= @@ -116,22 +94,18 @@ github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64= go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 h1:sbiXRNDSWJOTobXh5HyQKjq6wUC5tNybqjIqDpAY4CU= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0/go.mod h1:69uWxva0WgAA/4bu2Yy70SLDBwZXuQ6PbBpbsa5iZrQ= go.opentelemetry.io/otel v1.43.0 h1:mYIM03dnh5zfN7HautFE4ieIig9amkNANT+xcVxAj9I= go.opentelemetry.io/otel v1.43.0/go.mod h1:JuG+u74mvjvcm8vj8pI5XiHy1zDeoCS2LB1spIq7Ay0= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0 h1:88Y4s2C8oTui1LGM6bTWkw0ICGcOLCAI5l6zsD1j20k= -go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.43.0/go.mod h1:Vl1/iaggsuRlrHf/hfPJPvVag77kKyvrLeD10kpMl+A= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0 h1:3iZJKlCZufyRzPzlQhUIWVmfltrXuGyfjREgGP3UUjc= -go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.43.0/go.mod h1:/G+nUPfhq2e+qiXMGxMwumDrP5jtzU+mWN7/sjT2rak= go.opentelemetry.io/otel/metric v1.43.0 h1:d7638QeInOnuwOONPp4JAOGfbCEpYb+K6DVWvdxGzgM= go.opentelemetry.io/otel/metric v1.43.0/go.mod h1:RDnPtIxvqlgO8GRW18W6Z/4P462ldprJtfxHxyKd2PY= go.opentelemetry.io/otel/sdk v1.43.0 h1:pi5mE86i5rTeLXqoF/hhiBtUNcrAGHLKQdhg4h4V9Dg= go.opentelemetry.io/otel/sdk v1.43.0/go.mod h1:P+IkVU3iWukmiit/Yf9AWvpyRDlUeBaRg6Y+C58QHzg= +go.opentelemetry.io/otel/sdk/metric v1.43.0 h1:S88dyqXjJkuBNLeMcVPRFXpRw2fuwdvfCGLEo89fDkw= +go.opentelemetry.io/otel/sdk/metric v1.43.0/go.mod h1:C/RJtwSEJ5hzTiUz5pXF1kILHStzb9zFlIEe85bhj6A= go.opentelemetry.io/otel/trace v1.43.0 h1:BkNrHpup+4k4w+ZZ86CZoHHEkohws8AY+WTX09nk+3A= go.opentelemetry.io/otel/trace v1.43.0/go.mod h1:/QJhyVBUUswCphDVxq+8mld+AvhXZLhe+8WVFxiFff0= -go.opentelemetry.io/proto/otlp v1.10.0 h1:IQRWgT5srOCYfiWnpqUYz9CVmbO8bFmKcwYxpuCSL2g= -go.opentelemetry.io/proto/otlp v1.10.0/go.mod h1:/CV4QoCR/S9yaPj8utp3lvQPoqMtxXdzn7ozvvozVqk= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= @@ -144,7 +118,6 @@ golang.org/x/image v0.41.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.36.0 h1:JJjpVx6myfUsUdAzZuOSTTmRE0PfZeNWzzvKrP7amb4= golang.org/x/mod v0.36.0/go.mod h1:moc6ELqsWcOw5Ef3xVprK5ul/MvtVvkIXLziUOICjUQ= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= @@ -156,49 +129,36 @@ golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.46.0 h1:noSf2Fq6F8DBgS+LysIkx7rIExoNHJsxOAtPp4rthXw= golang.org/x/sys v0.46.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.38.0 h1:sXmwo9DwP3OK9EZ7PqAdaooSGozfl/3a6/xJcbzPRhE= golang.org/x/text v0.38.0/go.mod h1:YXZt3QhHUKYT53r2lLKFIVi6Ao1jdzrTR/KQ09qyxF4= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac h1:7zkz7BUtwNFFqcowJ+RIgu2MaV/MapERkDIy+mwPyjs= -golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.45.0 h1:18qN3FAooORvApf5XjCXgsuayZOEtXf6JK18I3+ONa8= golang.org/x/tools v0.45.0/go.mod h1:LuUGqqaXcXMEFEruIVJVm5mgDD8vww/z/SR1gQ4uE/0= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= gonum.org/v1/gonum v0.17.0 h1:VbpOemQlsSMrYmn7T2OUvQ4dqxQXU+ouZFQsZOx50z4= gonum.org/v1/gonum v0.17.0/go.mod h1:El3tOrEuMpv2UdMrbNlKEh9vd86bmQ6vqIcDwxEOc1E= gonum.org/v1/plot v0.17.0 h1:d0DwPVBe9jnEGqQBoZGl/P2M9WciJbG2CnV59C9QBT4= gonum.org/v1/plot v0.17.0/go.mod h1:ipt2GUN1oqzr2O7wCjLDtw1ShfIYYNBp4o0O1Ez5B3Y= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9 h1:VPWxll4HlMw1Vs/qXtN7BvhZqsS9cdAittCNvVENElA= -google.golang.org/genproto/googleapis/api v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:7QBABkRtR8z+TEnmXTqIqwJLlzrZKVfAUm7tY3yGv0M= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9 h1:m8qni9SQFH0tJc1X0vmnpw/0t+AImlSvp30sEupozUg= -google.golang.org/genproto/googleapis/rpc v0.0.0-20260401024825-9d38bb4040a9/go.mod h1:4Hqkh8ycfw05ld/3BWL7rJOSfebL2Q+DVDeRgYgxUU8= -google.golang.org/grpc v1.80.0 h1:Xr6m2WmWZLETvUNvIUmeD5OAagMw3FiKmMlTdViWsHM= -google.golang.org/grpc v1.80.0/go.mod h1:ho/dLnxwi3EDJA4Zghp7k2Ec1+c2jqup0bFkw07bwF4= -google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= -google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= gopkg.in/h2non/gock.v1 v1.1.2 h1:jBbHXgGBK/AoPVfJh5x4r/WxIrElvbLel8TCZkkZJoY= gopkg.in/h2non/gock.v1 v1.1.2/go.mod h1:n7UGz/ckNChHiK05rDoiC4MYSunEC/lyaUm2WWaDva0= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= -gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0= -gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= +gotest.tools/v3 v3.5.2 h1:7koQfIKdy+I8UTetycgUqXWSDwpgv193Ka+qRsmBY8Q= +gotest.tools/v3 v3.5.2/go.mod h1:LtdLGcnqToBH83WByAAi/wiwSFCArdFIUV/xxN4pcjA= honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las= +pgregory.net/rapid v1.2.0 h1:keKAYRcjm+e1F0oAuU5F5+YPAWcyxNNRK2wud503Gnk= +pgregory.net/rapid v1.2.0/go.mod h1:PY5XlDGj0+V1FCq0o192FdRhpKHGTRIWBgqjDBTrq04= rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/internal/docker/builder.go b/internal/docker/builder.go index 8b0edc99e..82145212e 100644 --- a/internal/docker/builder.go +++ b/internal/docker/builder.go @@ -17,15 +17,14 @@ import ( "context" "fmt" "log" + "net/netip" "strings" "time" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/image" - "github.com/docker/docker/api/types/network" - "github.com/docker/docker/client" - "github.com/docker/docker/pkg/stdcopy" - "github.com/docker/go-connections/nat" + "github.com/moby/moby/api/pkg/stdcopy" + "github.com/moby/moby/api/types/container" + "github.com/moby/moby/api/types/network" + "github.com/moby/moby/client" "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/config" @@ -77,7 +76,7 @@ func (d *Builder) Cleanup() { // removeImages removes all images with `complementLabel`. func (d *Builder) removeNetworks() error { - networks, err := d.Docker.NetworkList(context.Background(), network.ListOptions{ + networks, err := d.Docker.NetworkList(context.Background(), client.NetworkListOptions{ Filters: label( complementLabel, "complement_pkg="+d.Config.PackageNamespace, @@ -86,8 +85,8 @@ func (d *Builder) removeNetworks() error { if err != nil { return err } - for _, nw := range networks { - err = d.Docker.NetworkRemove(context.Background(), nw.ID) + for _, nw := range networks.Items { + _, err = d.Docker.NetworkRemove(context.Background(), nw.ID, client.NetworkRemoveOptions{}) if err != nil { return err } @@ -97,7 +96,7 @@ func (d *Builder) removeNetworks() error { // removeImages removes all images with `complementLabel`. func (d *Builder) removeImages() error { - images, err := d.Docker.ImageList(context.Background(), image.ListOptions{ + images, err := d.Docker.ImageList(context.Background(), client.ImageListOptions{ Filters: label( complementLabel, "complement_pkg="+d.Config.PackageNamespace, @@ -106,7 +105,7 @@ func (d *Builder) removeImages() error { if err != nil { return err } - for _, img := range images { + for _, img := range images.Items { // we only clean up localhost/complement images else if someone docker pulls // an anonymous snapshot we might incorrectly nuke it :( any non-localhost // tag marks this image as safe (as images can have multiple tags) @@ -133,7 +132,7 @@ func (d *Builder) removeImages() error { d.log("Keeping image created from blueprint %s", bprintName) continue } - _, err = d.Docker.ImageRemove(context.Background(), img.ID, image.RemoveOptions{ + _, err = d.Docker.ImageRemove(context.Background(), img.ID, client.ImageRemoveOptions{ Force: true, }) if err != nil { @@ -146,7 +145,7 @@ func (d *Builder) removeImages() error { // removeContainers removes all containers with `complementLabel`. func (d *Builder) removeContainers() error { - containers, err := d.Docker.ContainerList(context.Background(), container.ListOptions{ + containers, err := d.Docker.ContainerList(context.Background(), client.ContainerListOptions{ All: true, Filters: label( complementLabel, @@ -156,8 +155,8 @@ func (d *Builder) removeContainers() error { if err != nil { return err } - for _, c := range containers { - err = d.Docker.ContainerRemove(context.Background(), c.ID, container.RemoveOptions{ + for _, c := range containers.Items { + _, err = d.Docker.ContainerRemove(context.Background(), c.ID, client.ContainerRemoveOptions{ Force: true, }) if err != nil { @@ -168,7 +167,7 @@ func (d *Builder) removeContainers() error { } func (d *Builder) ConstructBlueprintIfNotExist(bprint b.Blueprint) error { - images, err := d.Docker.ImageList(context.Background(), image.ListOptions{ + images, err := d.Docker.ImageList(context.Background(), client.ImageListOptions{ Filters: label( "complement_blueprint="+bprint.Name, "complement_pkg="+d.Config.PackageNamespace, @@ -177,7 +176,7 @@ func (d *Builder) ConstructBlueprintIfNotExist(bprint b.Blueprint) error { if err != nil { return fmt.Errorf("ConstructBlueprintIfNotExist(%s): failed to ImageList: %w", bprint.Name, err) } - if len(images) == 0 { + if len(images.Items) == 0 { err = d.ConstructBlueprint(bprint) if err != nil { return fmt.Errorf("ConstructBlueprintIfNotExist(%s): failed to ConstructBlueprint: %w", bprint.Name, err) @@ -197,12 +196,12 @@ func (d *Builder) ConstructBlueprint(bprint b.Blueprint) error { // wait a bit for images/containers to show up in 'image ls' foundImages := false - var images []image.Summary + var images client.ImageListResult var err error waitTime := 5 * time.Second startTime := time.Now() for time.Since(startTime) < waitTime { - images, err = d.Docker.ImageList(context.Background(), image.ListOptions{ + images, err = d.Docker.ImageList(context.Background(), client.ImageListOptions{ Filters: label( complementLabel, "complement_blueprint="+bprint.Name, @@ -212,7 +211,7 @@ func (d *Builder) ConstructBlueprint(bprint b.Blueprint) error { if err != nil { return err } - if len(images) < len(bprint.Homeservers) { + if len(images.Items) < len(bprint.Homeservers) { time.Sleep(100 * time.Millisecond) } else { foundImages = true @@ -226,7 +225,7 @@ func (d *Builder) ConstructBlueprint(bprint b.Blueprint) error { return fmt.Errorf("failed to find built images via ImageList: did they all build ok?") } var imgDatas []string - for _, img := range images { + for _, img := range images.Items { imgDatas = append(imgDatas, fmt.Sprintf("%s=>%v", img.ID, img.Labels)) } d.log("Constructed blueprint '%s' : %v", bprint.Name, imgDatas) @@ -252,7 +251,7 @@ func (d *Builder) construct(bprint b.Blueprint) (errs []error) { // something went wrong, but we have a container which may have interesting logs printLogs(d.Docker, res.containerID, res.contextStr) } - if delErr := d.Docker.ContainerRemove(context.Background(), res.containerID, container.RemoveOptions{ + if _, delErr := d.Docker.ContainerRemove(context.Background(), res.containerID, client.ContainerRemoveOptions{ Force: true, }); delErr != nil { d.log("%s: failed to remove container which failed to deploy: %s", res.contextStr, delErr) @@ -262,19 +261,21 @@ func (d *Builder) construct(bprint b.Blueprint) (errs []error) { } // kill the container defer func(r result) { - containerInfo, err := d.Docker.ContainerInspect(context.Background(), r.containerID) + containerInfo, err := d.Docker.ContainerInspect(context.Background(), r.containerID, client.ContainerInspectOptions{}) if err != nil { d.log("%s : Can't get status of %s", r.contextStr, r.containerID) return } - if !containerInfo.State.Running { + if !containerInfo.Container.State.Running { // The container isn't running anyway, so no need to kill it. return } - killErr := d.Docker.ContainerKill(context.Background(), r.containerID, "KILL") + _, killErr := d.Docker.ContainerKill(context.Background(), r.containerID, client.ContainerKillOptions{ + Signal: "SIGKILL", + }) if killErr != nil { d.log("%s : Failed to kill container %s: %s\n", r.contextStr, r.containerID, killErr) } @@ -323,7 +324,7 @@ func (d *Builder) construct(bprint b.Blueprint) (errs []error) { // then incurs a slow recovery process when we use the blueprint later. d.log("%s: Stopping container: %s", res.contextStr, res.containerID) tenSeconds := 10 - d.Docker.ContainerStop(context.Background(), res.containerID, container.StopOptions{ + d.Docker.ContainerStop(context.Background(), res.containerID, client.ContainerStopOptions{ Timeout: &tenSeconds, }) @@ -331,9 +332,9 @@ func (d *Builder) construct(bprint b.Blueprint) (errs []error) { d.log("%s: Stopped container: %s", res.contextStr, res.containerID) // commit the container - commit, err := d.Docker.ContainerCommit(context.Background(), res.containerID, container.CommitOptions{ + commit, err := d.Docker.ContainerCommit(context.Background(), res.containerID, client.ContainerCommitOptions{ Author: "Complement", - Pause: true, + NoPause: false, Reference: "localhost/complement:" + res.contextStr, Changes: toChanges(labels), @@ -438,7 +439,7 @@ func generateASRegistrationYaml(as b.ApplicationService) string { // Name is guaranteed not to be empty when err == nil func createNetworkIfNotExists(docker *client.Client, pkgNamespace, blueprintName string) (networkName string, err error) { // check if a network already exists for this blueprint - nws, err := docker.NetworkList(context.Background(), network.ListOptions{ + nws, err := docker.NetworkList(context.Background(), client.NetworkListOptions{ Filters: label( "complement_pkg="+pkgNamespace, "complement_blueprint="+blueprintName, @@ -448,15 +449,15 @@ func createNetworkIfNotExists(docker *client.Client, pkgNamespace, blueprintName return "", fmt.Errorf("%s: failed to list networks. %w", blueprintName, err) } // return the existing network - if len(nws) > 0 { - if len(nws) > 1 { - log.Printf("WARNING: createNetworkIfNotExists got %d networks for pkg=%s blueprint=%s", len(nws), pkgNamespace, blueprintName) + if len(nws.Items) > 0 { + if len(nws.Items) > 1 { + log.Printf("WARNING: createNetworkIfNotExists got %d networks for pkg=%s blueprint=%s", len(nws.Items), pkgNamespace, blueprintName) } - return nws[0].Name, nil + return nws.Items[0].Name, nil } networkName = "complement_" + pkgNamespace + "_" + blueprintName // make a user-defined network so we get DNS based on the container name - nw, err := docker.NetworkCreate(context.Background(), networkName, network.CreateOptions{ + nw, err := docker.NetworkCreate(context.Background(), networkName, client.NetworkCreateOptions{ Labels: map[string]string{ complementLabel: blueprintName, "complement_blueprint": blueprintName, @@ -466,11 +467,11 @@ func createNetworkIfNotExists(docker *client.Client, pkgNamespace, blueprintName if err != nil { return "", fmt.Errorf("%s: failed to create docker network. %w", blueprintName, err) } - if nw.Warning != "" { + if len(nw.Warning) > 0 && nw.Warning[0] != "" { if nw.ID == "" { - return "", fmt.Errorf("%s: fatal warning while creating docker network. %s", blueprintName, nw.Warning) + return "", fmt.Errorf("%s: fatal warning while creating docker network. %s", blueprintName, nw.Warning[0]) } - log.Printf("WARNING: %s\n", nw.Warning) + log.Printf("WARNING: %s\n", nw.Warning[0]) } if nw.ID == "" { return "", fmt.Errorf("%s: unexpected empty ID while creating networkID", blueprintName) @@ -479,7 +480,7 @@ func createNetworkIfNotExists(docker *client.Client, pkgNamespace, blueprintName } func printLogs(docker *client.Client, containerID, contextStr string) { - reader, err := docker.ContainerLogs(context.Background(), containerID, container.LogsOptions{ + reader, err := docker.ContainerLogs(context.Background(), containerID, client.ContainerLogsOptions{ ShowStderr: true, ShowStdout: true, Follow: false, @@ -497,7 +498,7 @@ func printLogs(docker *client.Client, containerID, contextStr string) { func printPortBindingsOfAllComplementContainers(docker *client.Client, contextStr string) { ctx := context.Background() - containers, err := docker.ContainerList(ctx, container.ListOptions{ + containers, err := docker.ContainerList(ctx, client.ContainerListOptions{ All: true, Filters: label( complementLabel, @@ -510,10 +511,10 @@ func printPortBindingsOfAllComplementContainers(docker *client.Client, contextSt log.Printf("============== %s : START ALL COMPLEMENT DOCKER PORT BINDINGS ==============\n", contextStr) - for _, container := range containers { + for _, container := range containers.Items { log.Printf("Container: %s: %s", container.ID, container.Names) - inspectRes, err := docker.ContainerInspect(ctx, container.ID) + inspectRes, err := docker.ContainerInspect(ctx, container.ID, client.ContainerInspectOptions{}) if err != nil { log.Printf("%s : Failed to inspect container (%s) while trying to `printPortBindingsOfAllComplementContainers`: %s\n", contextStr, container.ID, err) return @@ -522,7 +523,7 @@ func printPortBindingsOfAllComplementContainers(docker *client.Client, contextSt // Print an example so it's easier to understand the output log.Printf(" (host) -> (container)\n") // Then print the actual port bindings - for containerPort, portBindings := range inspectRes.NetworkSettings.Ports { + for containerPort, portBindings := range inspectRes.Container.NetworkSettings.Ports { hostPortBindingStrings := make([]string, len(portBindings)) for portBindingIndex, portBinding := range portBindings { hostPortBindingStrings[portBindingIndex] = fmt.Sprintf("%s:%s", portBinding.HostIP, portBinding.HostPort) @@ -537,58 +538,68 @@ func printPortBindingsOfAllComplementContainers(docker *client.Client, contextSt } // endpoints transforms the homeserver ports into the base URL and federation base URL. -func endpoints(p nat.PortMap, hsPortBindingIP string, csPort, ssPort int) (baseURL, fedBaseURL string, err error) { +func endpoints(p network.PortMap, hsPortBindingIP string, csPort, ssPort int) (baseURL, fedBaseURL string, err error) { csapiPortBinding, err := findPortBinding(p, hsPortBindingIP, csPort) if err != nil { return "", "", fmt.Errorf("Problem finding CS API port: %s", err) } - baseURL = fmt.Sprintf("http://"+csapiPortBinding.HostIP+":%s", csapiPortBinding.HostPort) + baseURL = fmt.Sprintf("http://%s:%s", csapiPortBinding.HostIP, csapiPortBinding.HostPort) ssapiPortBinding, err := findPortBinding(p, hsPortBindingIP, ssPort) if err != nil { return "", "", fmt.Errorf("Problem finding SS API port: %s", err) } - fedBaseURL = fmt.Sprintf("https://"+ssapiPortBinding.HostIP+":%s", ssapiPortBinding.HostPort) + fedBaseURL = fmt.Sprintf("https://%s:%s", ssapiPortBinding.HostIP, ssapiPortBinding.HostPort) return } -// findPortBinding finds a matching port binding for the given host/port in the `nat.PortMap`. +// findPortBinding finds a matching port binding for the given host/port in the `network.PortMap`. // // This function will return the first port binding that matches the given host IP. If a // `0.0.0.0` binding is found, we will assume that it is listening on all interfaces, // including the `hsPortBindingIP`, and return a binding with the `hsPortBindingIP` as // the host IP. -func findPortBinding(p nat.PortMap, hsPortBindingIP string, port int) (portBinding nat.PortBinding, err error) { +func findPortBinding(p network.PortMap, hsPortBindingIP string, port int) (network.PortBinding, error) { portString := fmt.Sprintf("%d/tcp", port) - portBindings, ok := p[nat.Port(portString)] + parsedPort, err := network.ParsePort(portString) + if err != nil { + return network.PortBinding{}, fmt.Errorf("port %s failed to be parsed: %v", portString, err) + } + portBindings, ok := p[parsedPort] if !ok { - return nat.PortBinding{}, fmt.Errorf("port %s not exposed - exposed ports: %v", portString, p) + return network.PortBinding{}, fmt.Errorf("port %s not exposed - exposed ports: %v", portString, p) } if len(portBindings) == 0 { - return nat.PortBinding{}, fmt.Errorf("port %s exposed with not mapped port: %+v", portString, p) + return network.PortBinding{}, fmt.Errorf("port %s exposed with not mapped port: %+v", portString, p) } for _, pb := range portBindings { - if pb.HostIP == hsPortBindingIP { + pbHostIP := pb.HostIP.String() + if pbHostIP == hsPortBindingIP { return pb, nil - } else if pb.HostIP == "0.0.0.0" { + } else if pbHostIP == "0.0.0.0" { // `0.0.0.0` means "all interfaces", so we can assume that this will be listening // for connections from `hsPortBindingIP` as well. - return nat.PortBinding{ - HostIP: hsPortBindingIP, - HostPort: pb.HostPort, - }, nil - } else if pb.HostIP == "" && hsPortBindingIP == "127.0.0.1" { + return getPortBinding(hsPortBindingIP, pb.HostPort) + } else if pbHostIP == "" && hsPortBindingIP == "127.0.0.1" { // `HostIP` can be empty in certain environments (observed with podman v4.3.1). We // will assume this is only a binding for `127.0.0.1`. - return nat.PortBinding{ - HostIP: hsPortBindingIP, - HostPort: pb.HostPort, - }, nil + return getPortBinding(hsPortBindingIP, pb.HostPort) } } - return nat.PortBinding{}, fmt.Errorf("unable to find matching port binding for %s %s: %+v", hsPortBindingIP, portString, p) + return network.PortBinding{}, fmt.Errorf("unable to find matching port binding for %s %s: %+v", hsPortBindingIP, portString, p) +} + +func getPortBinding(hsPortBindingIP string, hostPort string) (network.PortBinding, error) { + hostAddr, err := netip.ParseAddr(hsPortBindingIP) + if err != nil { + return network.PortBinding{}, fmt.Errorf("hsPortBindingIP %s failed to be parsed: %v", hsPortBindingIP, err) + } + return network.PortBinding{ + HostIP: hostAddr, + HostPort: hostPort, + }, nil } type result struct { diff --git a/internal/docker/deployer.go b/internal/docker/deployer.go index 6255a9454..ad453aabd 100644 --- a/internal/docker/deployer.go +++ b/internal/docker/deployer.go @@ -30,14 +30,14 @@ import ( "sync" "time" - "github.com/docker/docker/client" "github.com/matrix-org/complement/internal" complementRuntime "github.com/matrix-org/complement/runtime" + "github.com/moby/moby/client" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/api/types/image" - "github.com/docker/docker/api/types/mount" - "github.com/docker/docker/api/types/network" + "github.com/moby/moby/api/types/container" + "github.com/moby/moby/api/types/image" + "github.com/moby/moby/api/types/mount" + "github.com/moby/moby/api/types/network" "github.com/matrix-org/complement/config" ) @@ -140,7 +140,7 @@ func (d *Deployer) Deploy(ctx context.Context, blueprintName string) (*Deploymen HS: make(map[string]*HomeserverDeployment), Config: d.config, } - images, err := d.Docker.ImageList(ctx, image.ListOptions{ + images, err := d.Docker.ImageList(ctx, client.ImageListOptions{ Filters: label( "complement_pkg="+d.config.PackageNamespace, "complement_blueprint="+blueprintName, @@ -149,7 +149,7 @@ func (d *Deployer) Deploy(ctx context.Context, blueprintName string) (*Deploymen if err != nil { return nil, fmt.Errorf("Deploy: failed to ImageList: %w", err) } - if len(images) == 0 { + if len(images.Items) == 0 { return nil, fmt.Errorf("Deploy: No images have been built for blueprint %s", blueprintName) } networkName, err := createNetworkIfNotExists(d.Docker, d.config.PackageNamespace, blueprintName) @@ -160,7 +160,7 @@ func (d *Deployer) Deploy(ctx context.Context, blueprintName string) (*Deploymen // deploy images in parallel var mu sync.Mutex // protects mutable values like the counter and errors var wg sync.WaitGroup - wg.Add(len(images)) // ensure we wait until all images have deployed + wg.Add(len(images.Items)) // ensure we wait until all images have deployed deployImg := func(img image.Summary) error { defer wg.Done() mu.Lock() @@ -197,7 +197,7 @@ func (d *Deployer) Deploy(ctx context.Context, blueprintName string) (*Deploymen } var lastErr error - for _, img := range images { + for _, img := range images.Items { go func(i image.Summary) { err := deployImg(i) if err != nil { @@ -224,7 +224,7 @@ func (d *Deployer) Destroy(dep *Deployment, printServerLogs bool, testName strin // If we want the logs we gracefully stop the containers to allow // the logs to be flushed. oneSecond := 1 - err := d.Docker.ContainerStop(context.Background(), hsDep.ContainerID, container.StopOptions{ + _, err := d.Docker.ContainerStop(context.Background(), hsDep.ContainerID, client.ContainerStopOptions{ Timeout: &oneSecond, }) if err != nil { @@ -247,7 +247,7 @@ func (d *Deployer) Destroy(dep *Deployment, printServerLogs bool, testName strin log.Printf("Post test script result: %s", string(result)) } - err = d.Docker.ContainerRemove(context.Background(), hsDep.ContainerID, container.RemoveOptions{ + _, err = d.Docker.ContainerRemove(context.Background(), hsDep.ContainerID, client.ContainerRemoveOptions{ Force: true, }) if err != nil { @@ -267,7 +267,7 @@ func (d *Deployer) executePostScript(hsDep *HomeserverDeployment, testName strin func (d *Deployer) PauseServer(hsDep *HomeserverDeployment) error { ctx := context.Background() - err := d.Docker.ContainerPause(ctx, hsDep.ContainerID) + _, err := d.Docker.ContainerPause(ctx, hsDep.ContainerID, client.ContainerPauseOptions{}) if err != nil { return fmt.Errorf("failed to pause container %s: %s", hsDep.ContainerID, err) } @@ -276,7 +276,7 @@ func (d *Deployer) PauseServer(hsDep *HomeserverDeployment) error { func (d *Deployer) UnpauseServer(hsDep *HomeserverDeployment) error { ctx := context.Background() - err := d.Docker.ContainerUnpause(ctx, hsDep.ContainerID) + _, err := d.Docker.ContainerUnpause(ctx, hsDep.ContainerID, client.ContainerUnpauseOptions{}) if err != nil { return fmt.Errorf("failed to unpause container %s: %s", hsDep.ContainerID, err) } @@ -286,7 +286,7 @@ func (d *Deployer) UnpauseServer(hsDep *HomeserverDeployment) error { 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{ + _, err := d.Docker.ContainerStop(ctx, hsDep.ContainerID, client.ContainerStopOptions{ Timeout: &secs, }) if err != nil { @@ -308,7 +308,7 @@ func (d *Deployer) Restart(hsDep *HomeserverDeployment) error { func (d *Deployer) StartServer(hsDep *HomeserverDeployment) error { ctx := context.Background() - err := d.Docker.ContainerStart(ctx, hsDep.ContainerID, container.StartOptions{}) + _, err := d.Docker.ContainerStart(ctx, hsDep.ContainerID, client.ContainerStartOptions{}) if err != nil { return fmt.Errorf("failed to start container %s: %s", hsDep.ContainerID, err) } @@ -375,49 +375,55 @@ func deployImage( log.Printf("Sharing %v host environment variables with container", env) } - body, err := docker.ContainerCreate(ctx, &container.Config{ - Image: imageID, - Env: env, - //Cmd: d.ImageArgs, - Labels: map[string]string{ - complementLabel: contextStr, - "complement_blueprint": blueprintName, - "complement_pkg": pkgNamespace, - "complement_hs_name": hsName, + body, err := docker.ContainerCreate(ctx, client.ContainerCreateOptions{ + Config: &container.Config{ + Image: imageID, + Env: env, + //Cmd: d.ImageArgs, + Labels: map[string]string{ + complementLabel: contextStr, + "complement_blueprint": blueprintName, + "complement_pkg": pkgNamespace, + "complement_hs_name": hsName, + }, }, - }, &container.HostConfig{ - CapAdd: []string{"NET_ADMIN"}, // TODO : this should be some sort of option - // We use `PublishAllPorts` because although Complement only requires the ports 8008 - // and 8448 to be accessible in the image, other custom out-of-repo tests may use - // additional ports that are specific to their own application. - // - // Ideally, we would only bind to `cfg.HSPortBindingIP` but there isn't a way to - // specify the `HostIP` when using `PublishAllPorts`. And although, we could specify - // a manual port mapping, it's not compatible with also having `PublishAllPorts` set - // to true (we run into `address already in use` errors). Binding to all interfaces - // means we're also listening on `cfg.HSPortBindingIP` so it's good enough. - PublishAllPorts: true, - ExtraHosts: extraHosts, - Mounts: mounts, - // https://docs.docker.com/engine/containers/resource_constraints/ - Resources: container.Resources{ - // Constrain the the number of CPU cores this container can use - // - // The number of CPU cores in 1e9 increments + HostConfig: &container.HostConfig{ + CapAdd: []string{"NET_ADMIN"}, // TODO : this should be some sort of option + // We use `PublishAllPorts` because although Complement only requires the ports 8008 + // and 8448 to be accessible in the image, other custom out-of-repo tests may use + // additional ports that are specific to their own application. // - // `NanoCPUs` is the option that is "Applicable to all platforms" instead of - // `CPUPeriod`/`CPUQuota` (Unix only) or `CPUCount`/`CPUPercent` (Windows only). - NanoCPUs: int64(cfg.ContainerCPUCores * 1e9), - // Constrain the maximum memory the container can use - Memory: cfg.ContainerMemoryBytes, + // Ideally, we would only bind to `cfg.HSPortBindingIP` but there isn't a way to + // specify the `HostIP` when using `PublishAllPorts`. And although, we could specify + // a manual port mapping, it's not compatible with also having `PublishAllPorts` set + // to true (we run into `address already in use` errors). Binding to all interfaces + // means we're also listening on `cfg.HSPortBindingIP` so it's good enough. + PublishAllPorts: true, + ExtraHosts: extraHosts, + Mounts: mounts, + // https://docs.docker.com/engine/containers/resource_constraints/ + Resources: container.Resources{ + // Constrain the the number of CPU cores this container can use + // + // The number of CPU cores in 1e9 increments + // + // `NanoCPUs` is the option that is "Applicable to all platforms" instead of + // `CPUPeriod`/`CPUQuota` (Unix only) or `CPUCount`/`CPUPercent` (Windows only). + NanoCPUs: int64(cfg.ContainerCPUCores * 1e9), + // Constrain the maximum memory the container can use + Memory: cfg.ContainerMemoryBytes, + }, }, - }, &network.NetworkingConfig{ - EndpointsConfig: map[string]*network.EndpointSettings{ - networkName: { - Aliases: []string{hsName}, + NetworkingConfig: &network.NetworkingConfig{ + EndpointsConfig: map[string]*network.EndpointSettings{ + networkName: { + Aliases: []string{hsName}, + }, }, }, - }, nil, containerName) + Platform: nil, + Name: containerName, + }) if err != nil { return nil, fmt.Errorf("ContainerCreate: %s", err) } @@ -472,7 +478,7 @@ func deployImage( return stubDeployment, fmt.Errorf("failed to copy CA key to container: %s", err) } - err = docker.ContainerStart(ctx, containerID, container.StartOptions{}) + _, err = docker.ContainerStart(ctx, containerID, client.ContainerStartOptions{}) if err != nil { return stubDeployment, fmt.Errorf("ContainerStart: %s", err) } @@ -493,11 +499,11 @@ func deployImage( ) } - inspect, err := docker.ContainerInspect(ctx, containerID) + inspect, err := docker.ContainerInspect(ctx, containerID, client.ContainerInspectOptions{}) if err != nil { return stubDeployment, fmt.Errorf("ContainerInspect: %s", err) } - for vol := range inspect.Config.Volumes { + for vol := range inspect.Container.Config.Volumes { log.Printf( "WARNING: %s has a named VOLUME %s - volumes can lead to unpredictable behaviour due to "+ "test pollution. Remove the VOLUME in the Dockerfile to suppress this message.", containerName, vol, @@ -508,9 +514,9 @@ func deployImage( BaseURL: baseURL, FedBaseURL: fedBaseURL, ContainerID: containerID, - AccessTokens: tokensFromLabels(inspect.Config.Labels), - ApplicationServices: asIDToRegistrationFromLabels(inspect.Config.Labels), - DeviceIDs: deviceIDsFromLabels(inspect.Config.Labels), + AccessTokens: tokensFromLabels(inspect.Container.Config.Labels), + ApplicationServices: asIDToRegistrationFromLabels(inspect.Container.Config.Labels), + DeviceIDs: deviceIDsFromLabels(inspect.Container.Config.Labels), Network: networkName, } @@ -543,7 +549,9 @@ func copyToContainer(docker *client.Client, containerID, path string, data []byt tw.Close() // Put our new fake file in the container volume - err = docker.CopyToContainer(context.Background(), containerID, "/", &buf, container.CopyToContainerOptions{ + _, err = docker.CopyToContainer(context.Background(), containerID, client.CopyToContainerOptions{ + DestinationPath: "/", + Content: &buf, AllowOverwriteDirWithFile: false, }) if err != nil { @@ -567,12 +575,12 @@ func assertHostnameEqual(inputUrl string, expectedHostname string) error { // getHostAccessibleHomeserverURLs returns URLs that are accessible from the host // machine (outside the container) for the homeserver's client API and federation API. func getHostAccessibleHomeserverURLs(ctx context.Context, docker *client.Client, containerID string, hsPortBindingIP string) (baseURL string, fedBaseURL string, err error) { - inspectResponse, err := inspectContainer(ctx, docker, containerID) + inspectResult, err := inspectContainer(ctx, docker, containerID) if err != nil { return "", "", fmt.Errorf("failed to inspect ports: %w", err) } - baseURL, fedBaseURL, err = endpoints(inspectResponse.NetworkSettings.Ports, hsPortBindingIP, 8008, 8448) + baseURL, fedBaseURL, err = endpoints(inspectResult.Container.NetworkSettings.Ports, hsPortBindingIP, 8008, 8448) // Sanity check that the URLs match the expected configured binding IP. It's // also important that we use the canonical publicly accessible hostname for the @@ -595,15 +603,15 @@ func waitForPorts(ctx context.Context, docker *client.Client, containerID string // We need to hammer the inspect endpoint until the ports show up, they don't appear immediately. inspectStartTime := time.Now() for time.Since(inspectStartTime) < time.Second { - inspectResponse, err := inspectContainer(ctx, docker, containerID) + inspectResult, err := inspectContainer(ctx, docker, containerID) if inspectionErr, ok := err.(*containerInspectionError); ok && inspectionErr.Fatal { // If the error is fatal, we should not retry. return fmt.Errorf("Fatal inspection error: %s", err) } // Check to see if we can see the ports yet - _, csPortErr := findPortBinding(inspectResponse.NetworkSettings.Ports, hsPortBindingIP, 8008) - _, ssPortErr := findPortBinding(inspectResponse.NetworkSettings.Ports, hsPortBindingIP, 8448) + _, csPortErr := findPortBinding(inspectResult.Container.NetworkSettings.Ports, hsPortBindingIP, 8008) + _, ssPortErr := findPortBinding(inspectResult.Container.NetworkSettings.Ports, hsPortBindingIP, 8448) if csPortErr == nil && ssPortErr == nil { break } @@ -630,23 +638,23 @@ func inspectContainer( ctx context.Context, docker *client.Client, containerID string, -) (inspectResponse container.InspectResponse, err error) { - inspectResponse, err = docker.ContainerInspect(ctx, containerID) +) (inspectResult client.ContainerInspectResult, err error) { + inspectResult, err = docker.ContainerInspect(ctx, containerID, client.ContainerInspectOptions{}) if err != nil { - return container.InspectResponse{}, &containerInspectionError{ + return client.ContainerInspectResult{}, &containerInspectionError{ msg: err.Error(), Fatal: false, } } - if inspectResponse.State != nil && !inspectResponse.State.Running { + if inspectResult.Container.State != nil && !inspectResult.Container.State.Running { // the container exited, bail out with a container ID for logs - return container.InspectResponse{}, &containerInspectionError{ - msg: fmt.Sprintf("container (%s) is not running, state=%v", containerID, inspectResponse.State.Status), + return client.ContainerInspectResult{}, &containerInspectionError{ + msg: fmt.Sprintf("container (%s) is not running, state=%v", containerID, inspectResult.Container.State.Status), Fatal: true, } } - return inspectResponse, nil + return inspectResult, nil } // waitForContainer waits until a homeserver deployment is ready to serve requests. @@ -660,15 +668,15 @@ func waitForContainer(ctx context.Context, docker *client.Client, hsDep *Homeser lastErr = fmt.Errorf("timed out checking for homeserver to be up: %s", lastErr) return } - inspect, err := docker.ContainerInspect(ctx, hsDep.ContainerID) + inspect, err := docker.ContainerInspect(ctx, hsDep.ContainerID, client.ContainerInspectOptions{}) if err != nil { lastErr = fmt.Errorf("inspect container %s => error: %s", hsDep.ContainerID, err) time.Sleep(50 * time.Millisecond) continue } - if inspect.State.Health != nil && - inspect.State.Health.Status != "healthy" { - lastErr = fmt.Errorf("inspect container %s => health: %s", hsDep.ContainerID, inspect.State.Health.Status) + if inspect.Container.State.Health != nil && + inspect.Container.State.Health.Status != "healthy" { + lastErr = fmt.Errorf("inspect container %s => health: %s", hsDep.ContainerID, inspect.Container.State.Health.Status) time.Sleep(50 * time.Millisecond) continue } diff --git a/internal/docker/labels.go b/internal/docker/labels.go index 98f5caf94..69ed96fc9 100644 --- a/internal/docker/labels.go +++ b/internal/docker/labels.go @@ -3,15 +3,15 @@ package docker import ( "strings" - "github.com/docker/docker/api/types/filters" + "github.com/moby/moby/client" "github.com/matrix-org/complement/b" ) // label returns a filter for the presence of certain labels ("complement_context") or a match of // labels ("complement_blueprint=foo"). -func label(labelFilters ...string) filters.Args { - f := filters.NewArgs() +func label(labelFilters ...string) client.Filters { + f := client.Filters{} // label= or label== for _, in := range labelFilters { f.Add("label", in) diff --git a/runtime/hs.go b/runtime/hs.go index 2037953fa..317e225a0 100644 --- a/runtime/hs.go +++ b/runtime/hs.go @@ -2,9 +2,10 @@ package runtime import ( "context" + "slices" - "github.com/docker/docker/client" "github.com/matrix-org/complement/ct" + "github.com/moby/moby/client" ) const ( @@ -12,14 +13,18 @@ const ( Synapse = "synapse" Conduit = "conduit" Conduwuit = "conduwuit" + Venator = "venator" ) var Homeserver string // ContainerKillFunc is used to destroy a container, it can be overwritten by Homeserver implementations // to e.g. gracefully stop a container. -var ContainerKillFunc = func(client *client.Client, containerID string) error { - return client.ContainerKill(context.Background(), containerID, "KILL") +var ContainerKillFunc = func(cli *client.Client, containerID string) error { + _, err := cli.ContainerKill(context.Background(), containerID, client.ContainerKillOptions{ + Signal: "SIGKILL", + }) + return err } // Skip the test (via t.Skipf) if the homeserver being tested matches one of the homeservers, else return. @@ -50,3 +55,19 @@ func SkipIf(t ct.TestLike, hses ...string) { ) } } + +// SkipUnless is the inverse of SkipIf: if the homeserver being tested is not present in the provided set, the test is skipped. +// This also means running without a blacklist tag will always skip. +func SkipUnless(t ct.TestLike, hses ...string) { + t.Helper() + if slices.Contains(hses, Homeserver) { + return + } + if Homeserver == "" { + t.Logf( + "WARNING: %s called runtime.SkipUnless(%v) but Complement doesn't know which HS is running as it was run without a *_blacklist tag: not executing test.", + t.Name(), hses, + ) + } + t.Skipf("test only runs on specific homeservers: %v", hses) +} diff --git a/runtime/hs_dendrite.go b/runtime/hs_dendrite.go index 54ad99281..a80899e76 100644 --- a/runtime/hs_dendrite.go +++ b/runtime/hs_dendrite.go @@ -6,18 +6,18 @@ package runtime import ( "context" - "github.com/docker/docker/api/types/container" - "github.com/docker/docker/client" + "github.com/moby/moby/client" ) func init() { Homeserver = Dendrite // For Dendrite, we want to always stop the container gracefully, as this is needed to // extract e.g. coverage reports. - ContainerKillFunc = func(client *client.Client, containerID string) error { + ContainerKillFunc = func(cli *client.Client, containerID string) error { oneSecond := 1 - return client.ContainerStop(context.Background(), containerID, container.StopOptions{ + _, err := cli.ContainerStop(context.Background(), containerID, client.ContainerStopOptions{ Timeout: &oneSecond, }) + return err } } diff --git a/runtime/hs_venator.go b/runtime/hs_venator.go new file mode 100644 index 000000000..6c5de40df --- /dev/null +++ b/runtime/hs_venator.go @@ -0,0 +1,7 @@ +//go:build venator_blacklist + +package runtime + +func init() { + Homeserver = Venator +} diff --git a/tests/csapi/account_change_password_pushers_test.go b/tests/csapi/account_change_password_pushers_test.go index 6607c002a..db95271d4 100644 --- a/tests/csapi/account_change_password_pushers_test.go +++ b/tests/csapi/account_change_password_pushers_test.go @@ -1,5 +1,7 @@ -//go:build !dendrite_blacklist -// +build !dendrite_blacklist +//go:build !dendrite_blacklist && !venator_blacklist +// +build !dendrite_blacklist,!venator_blacklist + +// Venator: https://github.com/matrix-org/complement/issues/897 package csapi_tests diff --git a/tests/csapi/account_change_password_test.go b/tests/csapi/account_change_password_test.go index 671a686ff..3d65fae21 100644 --- a/tests/csapi/account_change_password_test.go +++ b/tests/csapi/account_change_password_test.go @@ -9,11 +9,16 @@ import ( "github.com/matrix-org/complement/helpers" "github.com/matrix-org/complement/match" "github.com/matrix-org/complement/must" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" ) func TestChangePassword(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/897 + // Omitting the entire file via build tag breaks other test files due to the definition of createSession + runtime.SkipIf(t, runtime.Venator) + deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) password1 := "superuser" diff --git a/tests/csapi/account_deactivate_test.go b/tests/csapi/account_deactivate_test.go index 9b2eaaa83..cffc5dd5a 100644 --- a/tests/csapi/account_deactivate_test.go +++ b/tests/csapi/account_deactivate_test.go @@ -4,6 +4,7 @@ import ( "net/http" "testing" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -73,6 +74,8 @@ func TestDeactivateAccount(t *testing.T) { // sytest: Can't deactivate account with wrong password t.Run("Can't deactivate account with wrong password", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/898 + runtime.SkipIf(t, runtime.Venator) res := deactivateAccount(t, authedClient, "wrong_password") must.MatchResponse(t, res, match.HTTPResponse{ StatusCode: 401, @@ -83,6 +86,8 @@ func TestDeactivateAccount(t *testing.T) { }) // sytest: Can deactivate account t.Run("Can deactivate account", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/898 + runtime.SkipIf(t, runtime.Venator) res := deactivateAccount(t, authedClient, password) must.MatchResponse(t, res, match.HTTPResponse{ @@ -91,6 +96,8 @@ func TestDeactivateAccount(t *testing.T) { }) // sytest: After deactivating account, can't log in with password t.Run("After deactivating account, can't log in with password", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/898 + runtime.SkipIf(t, runtime.Venator) reqBody := client.WithJSONBody(t, map[string]interface{}{ "identifier": map[string]interface{}{ diff --git a/tests/csapi/apidoc_content_test.go b/tests/csapi/apidoc_content_test.go index 522f6e2e9..72fa9e36b 100644 --- a/tests/csapi/apidoc_content_test.go +++ b/tests/csapi/apidoc_content_test.go @@ -14,6 +14,8 @@ import ( func TestContent(t *testing.T) { // Synapse no longer allows downloads over the unauthenticated media endpoints by default runtime.SkipIf(t, runtime.Synapse) + // Venator is too young for any media to be available over the unauthenticated API, and always returns M_NOT_FOUND + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/csapi/apidoc_device_management_test.go b/tests/csapi/apidoc_device_management_test.go index 430ba39bf..9c811e86e 100644 --- a/tests/csapi/apidoc_device_management_test.go +++ b/tests/csapi/apidoc_device_management_test.go @@ -3,6 +3,7 @@ package csapi_tests import ( "testing" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -126,6 +127,8 @@ func TestDeviceManagement(t *testing.T) { // sytest: DELETE /device/{deviceId} t.Run("DELETE /device/{deviceId}", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/899 + runtime.SkipIf(t, runtime.Venator) newDeviceID, session2 := createSession(t, deployment, authedClient.UserID, "superuser") session2.MustSync(t, client.SyncReq{}) @@ -196,6 +199,8 @@ func TestDeviceManagement(t *testing.T) { }) // sytest: DELETE /device/{deviceId} requires UI auth user to match device owner t.Run("DELETE /device/{deviceId} requires UI auth user to match device owner", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/899 + runtime.SkipIf(t, runtime.Venator) bob := deployment.Register(t, "hs1", helpers.RegistrationOpts{ LocalpartSuffix: "bob", Password: "bobspassword", diff --git a/tests/csapi/apidoc_presence_test.go b/tests/csapi/apidoc_presence_test.go index 937f9917e..b072b98f0 100644 --- a/tests/csapi/apidoc_presence_test.go +++ b/tests/csapi/apidoc_presence_test.go @@ -1,7 +1,8 @@ -//go:build !dendrite_blacklist -// +build !dendrite_blacklist +//go:build !dendrite_blacklist && !venator_blacklist +// +build !dendrite_blacklist,!venator_blacklist // Rationale for being included in Dendrite's blacklist: https://github.com/matrix-org/complement/pull/104#discussion_r617646624 +// Venator: Does not implement presence package csapi_tests diff --git a/tests/csapi/apidoc_register_test.go b/tests/csapi/apidoc_register_test.go index 965c08575..b876abeaf 100644 --- a/tests/csapi/apidoc_register_test.go +++ b/tests/csapi/apidoc_register_test.go @@ -11,6 +11,7 @@ import ( "net/url" "testing" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -62,6 +63,8 @@ func TestRegistration(t *testing.T) { }) // sytest: POST /register can create a user t.Run("POST /register can create a user", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/893 + runtime.SkipIf(t, runtime.Venator) t.Parallel() res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ "auth": { @@ -79,6 +82,8 @@ func TestRegistration(t *testing.T) { }) // sytest: POST /register downcases capitals in usernames t.Run("POST /register downcases capitals in usernames", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/893 + runtime.SkipIf(t, runtime.Venator) t.Parallel() res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ "auth": { @@ -96,6 +101,8 @@ func TestRegistration(t *testing.T) { }) // sytest: POST /register returns the same device_id as that in the request t.Run("POST /register returns the same device_id as that in the request", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/893 + runtime.SkipIf(t, runtime.Venator) t.Parallel() deviceID := "my_device_id" res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ @@ -115,6 +122,8 @@ func TestRegistration(t *testing.T) { }) // sytest: POST /register rejects registration of usernames with '$q' t.Run("POST /register rejects usernames with special characters", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/893 + runtime.SkipIf(t, runtime.Venator) t.Parallel() specialChars := []string{ `!`, @@ -151,6 +160,8 @@ func TestRegistration(t *testing.T) { } }) t.Run("POST /register rejects if user already exists", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/893 + runtime.SkipIf(t, runtime.Venator) t.Parallel() res := unauthedClient.Do(t, "POST", []string{"_matrix", "client", "v3", "register"}, client.WithRawBody(json.RawMessage(`{ "auth": { @@ -178,6 +189,8 @@ func TestRegistration(t *testing.T) { }) // sytest: POST /register allows registration of usernames with '$chr' t.Run("POST /register allows registration of usernames with ", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/893 + runtime.SkipIf(t, runtime.Venator) testChars := []rune("q3._=-/") for x := range testChars { localpart := fmt.Sprintf("chrtestuser%s", string(testChars[x])) diff --git a/tests/csapi/apidoc_room_alias_test.go b/tests/csapi/apidoc_room_alias_test.go index 921c8c6ff..1a4c05f39 100644 --- a/tests/csapi/apidoc_room_alias_test.go +++ b/tests/csapi/apidoc_room_alias_test.go @@ -5,6 +5,7 @@ import ( "testing" "time" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -279,6 +280,8 @@ func TestRoomDeleteAlias(t *testing.T) { // sytest: Can delete canonical alias t.Run("Can delete canonical alias", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/900 + runtime.SkipIf(t, runtime.Venator) t.Parallel() roomID := alice.MustCreateRoom(t, map[string]interface{}{}) @@ -393,6 +396,8 @@ func TestRoomDeleteAlias(t *testing.T) { // sytest: Users can't delete other's aliases t.Run("Users can't delete other's aliases", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/900 + runtime.SkipIf(t, runtime.Venator) t.Parallel() roomID := alice.MustCreateRoom(t, map[string]interface{}{}) @@ -426,6 +431,9 @@ func TestRoomDeleteAlias(t *testing.T) { // sytest: Users with sufficient power-level can delete other's aliases t.Run("Users with sufficient power-level can delete other's aliases", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/900 + // This technically passes, but not because of the behaviour this test is testing for. + runtime.SkipIf(t, runtime.Venator) t.Parallel() roomID := alice.MustCreateRoom(t, map[string]interface{}{}) diff --git a/tests/csapi/apidoc_room_create_test.go b/tests/csapi/apidoc_room_create_test.go index 1b5e63bba..3a8960edc 100644 --- a/tests/csapi/apidoc_room_create_test.go +++ b/tests/csapi/apidoc_room_create_test.go @@ -158,6 +158,8 @@ func TestRoomCreate(t *testing.T) { }) // sytest: POST /createRoom creates a room with the given version t.Run("POST /createRoom creates a room with the given version", func(t *testing.T) { + // Venator: does not support room v2 (>=v10 only) + runtime.SkipIf(t, runtime.Venator) t.Parallel() roomID := alice.MustCreateRoom(t, map[string]interface{}{ "room_version": "2", diff --git a/tests/csapi/apidoc_room_forget_test.go b/tests/csapi/apidoc_room_forget_test.go index e292a301e..87048d055 100644 --- a/tests/csapi/apidoc_room_forget_test.go +++ b/tests/csapi/apidoc_room_forget_test.go @@ -6,6 +6,7 @@ import ( "net/url" "testing" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -19,6 +20,8 @@ import ( // These tests ensure that forgetting about rooms works as intended func TestRoomForget(t *testing.T) { + // Venator: does not implement manual room forgetting (is always done automatically on leave) + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/csapi/apidoc_room_state_test.go b/tests/csapi/apidoc_room_state_test.go index 68489bd89..ff085efc3 100644 --- a/tests/csapi/apidoc_room_state_test.go +++ b/tests/csapi/apidoc_room_state_test.go @@ -6,6 +6,7 @@ import ( "testing" "time" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -59,6 +60,8 @@ func TestRoomState(t *testing.T) { }) // sytest: GET /rooms/:room_id/state/m.room.power_levels fetches powerlevels t.Run("GET /rooms/:room_id/state/m.room.power_levels fetches powerlevels", func(t *testing.T) { + // Venator doesn't marshal default values so the presence check fails despite being valid. + runtime.SkipIf(t, runtime.Venator) t.Parallel() roomID := authedClient.MustCreateRoom(t, map[string]interface{}{ @@ -329,6 +332,8 @@ func TestRoomState(t *testing.T) { }) }) t.Run("GET /rooms/:room_id/joined_members is forbidden after leaving room", func(t *testing.T) { + // Venator: does not implement API version r0 + runtime.SkipIf(t, runtime.Venator) t.Parallel() roomID := authedClient.MustCreateRoom(t, map[string]interface{}{}) authedClient.MustLeaveRoom(t, roomID) diff --git a/tests/csapi/device_lists_test.go b/tests/csapi/device_lists_test.go index 7012efa70..2b93cf465 100644 --- a/tests/csapi/device_lists_test.go +++ b/tests/csapi/device_lists_test.go @@ -449,16 +449,34 @@ func TestDeviceListUpdates(t *testing.T) { defer deployment.Destroy(t) t.Run("when local user joins a room", func(t *testing.T) { testOtherUserJoin(t, deployment, "hs1", "hs1") }) - t.Run("when remote user joins a room", func(t *testing.T) { testOtherUserJoin(t, deployment, "hs1", "hs2") }) + t.Run("when remote user joins a room", func(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) + testOtherUserJoin(t, deployment, "hs1", "hs2") + }) t.Run("when joining a room with a local user", func(t *testing.T) { testJoin(t, deployment, "hs1", "hs1") }) - t.Run("when joining a room with a remote user", func(t *testing.T) { testJoin(t, deployment, "hs1", "hs2") }) + t.Run("when joining a room with a remote user", func(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) + testJoin(t, deployment, "hs1", "hs2") + }) t.Run("when local user leaves a room", func(t *testing.T) { testOtherUserLeave(t, deployment, "hs1", "hs1") }) - t.Run("when remote user leaves a room", func(t *testing.T) { testOtherUserLeave(t, deployment, "hs1", "hs2") }) + t.Run("when remote user leaves a room", func(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) + testOtherUserLeave(t, deployment, "hs1", "hs2") + }) t.Run("when leaving a room with a local user", func(t *testing.T) { testLeave(t, deployment, "hs1", "hs1") }) t.Run("when leaving a room with a remote user", func(t *testing.T) { runtime.SkipIf(t, runtime.Synapse) // FIXME: https://github.com/matrix-org/synapse/issues/13650 + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) testLeave(t, deployment, "hs1", "hs2") }) t.Run("when local user rejoins a room", func(t *testing.T) { testOtherUserRejoin(t, deployment, "hs1", "hs1") }) - t.Run("when remote user rejoins a room", func(t *testing.T) { testOtherUserRejoin(t, deployment, "hs1", "hs2") }) + t.Run("when remote user rejoins a room", func(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) + testOtherUserRejoin(t, deployment, "hs1", "hs2") + }) } diff --git a/tests/csapi/invalid_test.go b/tests/csapi/invalid_test.go index 697ae832c..3ebd888d5 100644 --- a/tests/csapi/invalid_test.go +++ b/tests/csapi/invalid_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not support room version 6 (>=v10 only) + package csapi_tests import ( diff --git a/tests/csapi/keychanges_test.go b/tests/csapi/keychanges_test.go index 63437bdc3..d1ced440b 100644 --- a/tests/csapi/keychanges_test.go +++ b/tests/csapi/keychanges_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not implement r0 API, which part of this test depends on + package csapi_tests import ( diff --git a/tests/csapi/media_async_uploads_test.go b/tests/csapi/media_async_uploads_test.go index 49ca8252c..ccb4716c4 100644 --- a/tests/csapi/media_async_uploads_test.go +++ b/tests/csapi/media_async_uploads_test.go @@ -31,6 +31,9 @@ func TestAsyncUpload(t *testing.T) { }) t.Run("Not yet uploaded", func(t *testing.T) { + // Venator is too young for any media to be available over the unauthenticated API, + // and always returns M_NOT_FOUND + runtime.SkipIf(t, runtime.Venator) mxcURI := alice.CreateMedia(t) parts := strings.Split(mxcURI, "/") mediaID := parts[len(parts)-1] diff --git a/tests/csapi/media_misc_test.go b/tests/csapi/media_misc_test.go index 6efa39a59..900f3d8c5 100644 --- a/tests/csapi/media_misc_test.go +++ b/tests/csapi/media_misc_test.go @@ -63,6 +63,8 @@ func TestRoomImageRoundtrip(t *testing.T) { // sytest: Can read configuration endpoint func TestMediaConfig(t *testing.T) { + // Venator: does not permit the use of the legacy media API (always returns M_NOT_FOUND) + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/csapi/power_levels_test.go b/tests/csapi/power_levels_test.go index 350837407..a28e6b818 100644 --- a/tests/csapi/power_levels_test.go +++ b/tests/csapi/power_levels_test.go @@ -4,6 +4,7 @@ import ( "fmt" "testing" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -86,6 +87,10 @@ func TestPowerLevels(t *testing.T) { // sytest: GET /rooms/:room_id/state/m.room.power_levels can fetch levels t.Run("GET /rooms/:room_id/state/m.room.power_levels can fetch levels", func(t *testing.T) { + // Venator skips marshalling default values, which means all of these checks fail: + // > MatchJSONBytes key 'ban' missing with input = {} + // This is a feature :D + runtime.SkipIf(t, runtime.Venator) // Test if the old state still exists // note: before v10 we technically cannot assume that powerlevel integers are json numbers, // as they can be both strings and numbers. diff --git a/tests/csapi/room_leave_test.go b/tests/csapi/room_leave_test.go index b56edc348..8d44de3ac 100644 --- a/tests/csapi/room_leave_test.go +++ b/tests/csapi/room_leave_test.go @@ -5,6 +5,7 @@ import ( "strings" "testing" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -127,6 +128,8 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Can get rooms/{roomId}/state for a departed room (SPEC-216) t.Run("Can get rooms/{roomId}/state for a departed room", func(t *testing.T) { + // Venator: rooms are automatically forgotten on leave, so this functionality conflicts + runtime.SkipIf(t, runtime.Venator) // Bob gets the old state content := bob.MustGetStateEventContent(t, roomID, madeUpStateKey, "") must.MatchGJSON(t, content, match.JSONKeyEqual("body", beforeMadeUpState)) @@ -138,6 +141,8 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Can get rooms/{roomId}/members for a departed room (SPEC-216) t.Run("Can get rooms/{roomId}/members for a departed room", func(t *testing.T) { + // Venator: rooms are automatically forgotten on leave, so this functionality conflicts + runtime.SkipIf(t, runtime.Venator) resp := bob.MustDo( t, "GET", @@ -163,6 +168,8 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Can get rooms/{roomId}/messages for a departed room (SPEC-216) t.Run("Can get rooms/{roomId}/messages for a departed room", func(t *testing.T) { + // Venator: rooms are automatically forgotten on leave, so this functionality conflicts + runtime.SkipIf(t, runtime.Venator) resp := bob.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(url.Values{ "dir": []string{"b"}, "limit": []string{"3"}, @@ -188,6 +195,8 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Can get 'm.room.name' state for a departed room (SPEC-216) t.Run("Can get 'm.room.name' state for a departed room", func(t *testing.T) { + // Venator: rooms are automatically forgotten on leave, so this functionality conflicts + runtime.SkipIf(t, runtime.Venator) // Bob gets the old name content := bob.MustGetStateEventContent(t, roomID, "m.room.name", "") must.MatchGJSON(t, content, match.JSONKeyEqual("name", beforeRoomName)) @@ -199,6 +208,8 @@ func TestLeftRoomFixture(t *testing.T) { // sytest: Getting messages going forward is limited for a departed room (SPEC-216) t.Run("Getting messages going forward is limited for a departed room", func(t *testing.T) { + // Venator: rooms are automatically forgotten on leave, so this functionality conflicts + runtime.SkipIf(t, runtime.Venator) // TODO: try this with the most recent since token too resp := bob.MustDo(t, "GET", []string{"_matrix", "client", "v3", "rooms", roomID, "messages"}, client.WithQueries(url.Values{ "dir": []string{"f"}, diff --git a/tests/csapi/room_messages_test.go b/tests/csapi/room_messages_test.go index b21aa55a7..4e2208ff8 100644 --- a/tests/csapi/room_messages_test.go +++ b/tests/csapi/room_messages_test.go @@ -242,6 +242,8 @@ type MessagesTestCase struct { } func TestMessagesOverFederation(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) diff --git a/tests/csapi/room_upgrade_test.go b/tests/csapi/room_upgrade_test.go index 17cd8686d..283b2cb3b 100644 --- a/tests/csapi/room_upgrade_test.go +++ b/tests/csapi/room_upgrade_test.go @@ -21,6 +21,9 @@ import ( // perhaps that just needs a clarification/MSC to document the state of things. Synapse // and Dendrite do this for example. func TestPushRuleRoomUpgrade(t *testing.T) { + // Venator: does not implement this functionality (needs spec change). + // Venator: additionally does not implement federation (which several tests depend on). + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) diff --git a/tests/csapi/rooms_members_local_test.go b/tests/csapi/rooms_members_local_test.go index b715ddce1..d2db90847 100644 --- a/tests/csapi/rooms_members_local_test.go +++ b/tests/csapi/rooms_members_local_test.go @@ -52,6 +52,8 @@ func TestMembersLocal(t *testing.T) { // Split into initial and incremental sync cases in Complement. t.Run("Existing members see new members' presence (in initial sync)", func(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/matrix-spec/issues/1374 + // Venator: does not implement presence + runtime.SkipIf(t, runtime.Venator) t.Parallel() // First we sync to make sure bob to have joined the room... alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(bob.UserID, roomID)) @@ -65,6 +67,8 @@ func TestMembersLocal(t *testing.T) { // sytest: Existing members see new members' presence // Split into initial and incremental sync cases in Complement. t.Run("Existing members see new members' presence (in incremental sync)", func(t *testing.T) { + // Venator: does not implement presence + runtime.SkipIf(t, runtime.Venator) t.Parallel() alice.MustSyncUntil(t, client.SyncReq{Since: incrementalSyncTokenBeforeBobJoinsRoom}, client.SyncJoinedTo(bob.UserID, roomID), diff --git a/tests/csapi/rooms_state_test.go b/tests/csapi/rooms_state_test.go index 4f2a54510..e2657d624 100644 --- a/tests/csapi/rooms_state_test.go +++ b/tests/csapi/rooms_state_test.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -89,6 +90,8 @@ func TestRoomCreationReportsEventsToMyself(t *testing.T) { // sytest: Setting state twice is idempotent t.Run("Setting state twice is idempotent", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/901 + runtime.SkipIf(t, runtime.Venator) t.Parallel() stateEvent := b.Event{ @@ -109,6 +112,9 @@ func TestRoomCreationReportsEventsToMyself(t *testing.T) { // sytest: Joining room twice is idempotent t.Run("Joining room twice is idempotent", func(t *testing.T) { + // Venator: https://github.com/matrix-org/complement/issues/901 + // Test passes illegitimately + runtime.SkipIf(t, runtime.Venator) t.Parallel() roomID := bob.MustCreateRoom(t, map[string]interface{}{ diff --git a/tests/csapi/sync_archive_test.go b/tests/csapi/sync_archive_test.go index f8ed18aa3..3d0dcb065 100644 --- a/tests/csapi/sync_archive_test.go +++ b/tests/csapi/sync_archive_test.go @@ -1,9 +1,10 @@ package csapi_tests import ( - "github.com/tidwall/gjson" "testing" + "github.com/tidwall/gjson" + "github.com/matrix-org/complement" "github.com/matrix-org/complement/b" "github.com/matrix-org/complement/client" @@ -49,6 +50,8 @@ func TestSyncLeaveSection(t *testing.T) { // sytest: Left rooms appear in the leave section of sync t.Run("Left rooms appear in the leave section of sync", func(t *testing.T) { + // Venator: rooms are automatically forgotten on leave, which results in conflicting behaviour + runtime.SkipIf(t, runtime.Venator) // SyncLeftFrom does "active" probing of rooms.leave if userID == clientUserID alice.MustSyncUntil(t, client.SyncReq{ Filter: includeLeaveFilter, @@ -57,6 +60,8 @@ func TestSyncLeaveSection(t *testing.T) { // sytest: Left rooms appear in the leave section of full state sync t.Run("Left rooms appear in the leave section of full state sync", func(t *testing.T) { + // Venator: rooms are automatically forgotten on leave, which results in conflicting behaviour + runtime.SkipIf(t, runtime.Venator) alice.MustSyncUntil(t, client.SyncReq{ Since: fullStateSince, Filter: includeLeaveFilter, @@ -75,6 +80,8 @@ func TestSyncLeaveSection(t *testing.T) { // sytest: Newly left rooms appear in the leave section of gapped sync func TestGappedSyncLeaveSection(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/1323 + // Venator: rooms are automatically forgotten on leave, which results in conflicting behaviour + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) @@ -117,6 +124,8 @@ func TestGappedSyncLeaveSection(t *testing.T) { // ... plus later additions func TestArchivedRoomsHistory(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/1323 + // Venator: rooms are automatically forgotten on leave, which results in conflicting behaviour + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/csapi/sync_test.go b/tests/csapi/sync_test.go index 3dec9ea51..5a9d6b063 100644 --- a/tests/csapi/sync_test.go +++ b/tests/csapi/sync_test.go @@ -210,6 +210,8 @@ func TestSync(t *testing.T) { // sytest: Newly joined room includes presence in incremental sync t.Run("Newly joined room includes presence in incremental sync", func(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/1324 + // Venator: does not implement presence + runtime.SkipIf(t, runtime.Venator) roomID := alice.MustCreateRoom(t, map[string]interface{}{"preset": "public_chat"}) alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, roomID)) _, nextBatch := bob.MustSync(t, client.SyncReq{}) @@ -230,6 +232,8 @@ func TestSync(t *testing.T) { // sytest: Get presence for newly joined members in incremental sync t.Run("Get presence for newly joined members in incremental sync", func(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/1324 + // Venator: does not implement presence + runtime.SkipIf(t, runtime.Venator) roomID := alice.MustCreateRoom(t, map[string]interface{}{"preset": "public_chat"}) nextBatch := alice.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(alice.UserID, roomID)) sendMessages(t, alice, roomID, "dummy message", 1) @@ -276,6 +280,8 @@ func TestSync(t *testing.T) { // in the order we send them, but in practice it seems to get close // enough. + // Venator: does not yet implement federation, so this test cannot function (see third paragraph of above) + runtime.SkipIf(t, runtime.Venator) t.Parallel() // alice creates two rooms, which charlie (on our test server) joins @@ -450,6 +456,8 @@ func TestSync(t *testing.T) { // events, with the `limited` flag set. func TestSyncTimelineGap(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) + // Venator: does not yet implement federation (so this test cannot function) + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) @@ -626,6 +634,8 @@ func TestSyncTimelineGap(t *testing.T) { // Test presence from people in 2 different rooms in incremental sync func TestPresenceSyncDifferentRooms(t *testing.T) { + // Venator: does not implement presence + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/csapi/txnid_test.go b/tests/csapi/txnid_test.go index 04fb8d1e4..621afe03a 100644 --- a/tests/csapi/txnid_test.go +++ b/tests/csapi/txnid_test.go @@ -214,8 +214,8 @@ func TestTxnIdempotency(t *testing.T) { // TestTxnIdWithRefreshToken tests that when a client refreshes its access token, // it still gets back a transaction ID in the sync response and idempotency is respected. func TestTxnIdWithRefreshToken(t *testing.T) { - // Dendrite and Conduit don't support refresh tokens yet. - runtime.SkipIf(t, runtime.Dendrite, runtime.Conduit) + // Dendrite, Conduit, and Venator don't support refresh tokens yet. + runtime.SkipIf(t, runtime.Dendrite, runtime.Conduit, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/csapi/url_preview_test.go b/tests/csapi/url_preview_test.go index fc1ef2c7a..73b729d85 100644 --- a/tests/csapi/url_preview_test.go +++ b/tests/csapi/url_preview_test.go @@ -41,6 +41,8 @@ var oGraphHtml = fmt.Sprintf(` // sytest: Test URL preview func TestUrlPreview(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/621 + // Venator: does not allow the use of the unauthenticated media API (always returns M_NOT_FOUND) + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/direct_messaging_test.go b/tests/direct_messaging_test.go index 2282507a4..bb06ae795 100644 --- a/tests/direct_messaging_test.go +++ b/tests/direct_messaging_test.go @@ -12,6 +12,7 @@ import ( "github.com/matrix-org/complement/helpers" "github.com/matrix-org/complement/match" "github.com/matrix-org/complement/must" + "github.com/matrix-org/complement/runtime" "github.com/matrix-org/gomatrixserverlib/fclient" "github.com/matrix-org/gomatrixserverlib" @@ -102,6 +103,8 @@ func TestIsDirectFlagLocal(t *testing.T) { // Test that the `is_direct` flag on m.room.member invites propagate to the target user. Users // are on different homeservers. func TestIsDirectFlagFederation(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/federation_acl_test.go b/tests/federation_acl_test.go index 9810c5efc..7f7c5d8a6 100644 --- a/tests/federation_acl_test.go +++ b/tests/federation_acl_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation. ACLs are implemented, but not in a way that can be exposed to these tests + package tests import ( diff --git a/tests/federation_device_list_update_test.go b/tests/federation_device_list_update_test.go index 770535c8a..95ba69bc0 100644 --- a/tests/federation_device_list_update_test.go +++ b/tests/federation_device_list_update_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_event_auth_test.go b/tests/federation_event_auth_test.go index f49b4e667..333a91c46 100644 --- a/tests/federation_event_auth_test.go +++ b/tests/federation_event_auth_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_media_content_test.go b/tests/federation_media_content_test.go index c2cfd16ef..03f2a9d0a 100644 --- a/tests/federation_media_content_test.go +++ b/tests/federation_media_content_test.go @@ -1,11 +1,16 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( "bytes" + "testing" + "github.com/matrix-org/complement" "github.com/matrix-org/complement/helpers" "github.com/matrix-org/complement/internal/data" - "testing" ) func TestContentMediaV1(t *testing.T) { diff --git a/tests/federation_presence_test.go b/tests/federation_presence_test.go index 9e11ca7f1..c4d0cfd83 100644 --- a/tests/federation_presence_test.go +++ b/tests/federation_presence_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation, nor presence + package tests import ( diff --git a/tests/federation_query_profile_test.go b/tests/federation_query_profile_test.go index f901c7c6e..1c1c50a2d 100644 --- a/tests/federation_query_profile_test.go +++ b/tests/federation_query_profile_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_redaction_test.go b/tests/federation_redaction_test.go index 94bb03a59..909c16b99 100644 --- a/tests/federation_redaction_test.go +++ b/tests/federation_redaction_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_room_alias_test.go b/tests/federation_room_alias_test.go index a2a90c77d..ba412e1e6 100644 --- a/tests/federation_room_alias_test.go +++ b/tests/federation_room_alias_test.go @@ -8,10 +8,13 @@ import ( "github.com/matrix-org/complement/helpers" "github.com/matrix-org/complement/match" "github.com/matrix-org/complement/must" + "github.com/matrix-org/complement/runtime" ) // sytest: Remote room alias queries can handle Unicode func TestRemoteAliasRequestsUnderstandUnicode(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) diff --git a/tests/federation_room_ban_test.go b/tests/federation_room_ban_test.go index 29d3d53c2..9f370f04f 100644 --- a/tests/federation_room_ban_test.go +++ b/tests/federation_room_ban_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_room_event_auth_test.go b/tests/federation_room_event_auth_test.go index f209b40c1..b17faccfd 100644 --- a/tests/federation_room_event_auth_test.go +++ b/tests/federation_room_event_auth_test.go @@ -1,6 +1,8 @@ // These tests currently fail on Dendrite, due to Dendrite bugs. -//go:build !dendrite_blacklist -// +build !dendrite_blacklist +//go:build !dendrite_blacklist && !venator_blacklist +// +build !dendrite_blacklist,!venator_blacklist + +// Venator: does not yet implement federation package tests diff --git a/tests/federation_room_get_missing_events_test.go b/tests/federation_room_get_missing_events_test.go index 9743e4325..d6ddaa546 100644 --- a/tests/federation_room_get_missing_events_test.go +++ b/tests/federation_room_get_missing_events_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_room_invite_test.go b/tests/federation_room_invite_test.go index fca50315f..cf8f1bcdc 100644 --- a/tests/federation_room_invite_test.go +++ b/tests/federation_room_invite_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_room_join_test.go b/tests/federation_room_join_test.go index 03b12ee03..bd18286fe 100644 --- a/tests/federation_room_join_test.go +++ b/tests/federation_room_join_test.go @@ -39,6 +39,10 @@ import ( // m.room.create event would pick that up. We also can't tear down the Complement // server because otherwise signing key lookups will fail. func TestJoinViaRoomIDAndServerName(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) @@ -89,6 +93,10 @@ func TestJoinViaRoomIDAndServerName(t *testing.T) { // This tests that joining a room with multiple ?server_name=s works correctly. // The join should succeed even if the first server is not in the room. func TestJoinFederatedRoomFailOver(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) @@ -132,6 +140,10 @@ func TestJoinFederatedRoomFailOver(t *testing.T) { // the properties listed above, then asking HS1 to join them and make sure that // they 200 OK. func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) @@ -298,6 +310,10 @@ func TestJoinFederatedRoomWithUnverifiableEvents(t *testing.T) { // This test checks that users cannot circumvent the auth checks via send_join. func TestBannedUserCannotSendJoin(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) @@ -365,21 +381,37 @@ func TestBannedUserCannotSendJoin(t *testing.T) { // This test checks that we cannot submit anything via /v1/send_join except a join. func TestCannotSendNonJoinViaSendJoinV1(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) testValidationForSendMembershipEndpoint(t, "/_matrix/federation/v1/send_join", "join", nil) } // This test checks that we cannot submit anything via /v2/send_join except a join. func TestCannotSendNonJoinViaSendJoinV2(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) testValidationForSendMembershipEndpoint(t, "/_matrix/federation/v2/send_join", "join", nil) } // This test checks that we cannot submit anything via /v1/send_leave except a leave. func TestCannotSendNonLeaveViaSendLeaveV1(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) testValidationForSendMembershipEndpoint(t, "/_matrix/federation/v1/send_leave", "leave", nil) } // This test checks that we cannot submit anything via /v2/send_leave except a leave. func TestCannotSendNonLeaveViaSendLeaveV2(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) testValidationForSendMembershipEndpoint(t, "/_matrix/federation/v2/send_leave", "leave", nil) } @@ -494,6 +526,10 @@ func testValidationForSendMembershipEndpoint(t *testing.T, baseApiPath, expected // // Will be skipped if the server returns a full-state response. func TestSendJoinPartialStateResponse(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) // start with a homeserver with two users deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) @@ -580,6 +616,10 @@ func typeAndStateKeyForEvent(result gjson.Result) string { } func TestJoinFederatedRoomFromApplicationServiceBridgeUser(t *testing.T) { + // Venator: does not yet implement federation. The entire file cannot be ignored as + // testValidationForSendMembershipEndpoint is referenced elsewhere, which causes compile errors if elided by build + // constraints. + runtime.SkipIf(t, runtime.Venator) // Dendrite doesn't read AS registration files from Complement yet runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/complement/issues/514 diff --git a/tests/federation_room_send_test.go b/tests/federation_room_send_test.go index acc318be3..376e4bfbe 100644 --- a/tests/federation_room_send_test.go +++ b/tests/federation_room_send_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_room_typing_test.go b/tests/federation_room_typing_test.go index 7e4a9b124..9fcb7bb02 100644 --- a/tests/federation_room_typing_test.go +++ b/tests/federation_room_typing_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_rooms_invite_test.go b/tests/federation_rooms_invite_test.go index d5386014d..cff49d64a 100644 --- a/tests/federation_rooms_invite_test.go +++ b/tests/federation_rooms_invite_test.go @@ -1,6 +1,8 @@ // These tests currently fail on Dendrite, due to Dendrite bugs. -//go:build !dendrite_blacklist -// +build !dendrite_blacklist +//go:build !dendrite_blacklist && !venator_blacklist +// +build !dendrite_blacklist,!venator_blacklist + +// Venator: does not yet implement federation package tests diff --git a/tests/federation_sync_test.go b/tests/federation_sync_test.go index 23f67c5bb..44ab13bca 100644 --- a/tests/federation_sync_test.go +++ b/tests/federation_sync_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_to_device_test.go b/tests/federation_to_device_test.go index 8a4d98ed0..1eb8634e0 100644 --- a/tests/federation_to_device_test.go +++ b/tests/federation_to_device_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_unreject_rejected_test.go b/tests/federation_unreject_rejected_test.go index ef7f016b1..f2dad2df0 100644 --- a/tests/federation_unreject_rejected_test.go +++ b/tests/federation_unreject_rejected_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/federation_upload_keys_test.go b/tests/federation_upload_keys_test.go index 2f91485e9..feab976de 100644 --- a/tests/federation_upload_keys_test.go +++ b/tests/federation_upload_keys_test.go @@ -1,3 +1,7 @@ +//go:build !venator_blacklist + +// Venator: does not yet implement federation + package tests import ( diff --git a/tests/knock_restricted_test.go b/tests/knock_restricted_test.go index ec2035a3d..9876a8953 100644 --- a/tests/knock_restricted_test.go +++ b/tests/knock_restricted_test.go @@ -13,6 +13,7 @@ import ( "github.com/matrix-org/complement" "github.com/matrix-org/complement/helpers" + "github.com/matrix-org/complement/runtime" ) var ( @@ -32,6 +33,8 @@ func TestKnockRoomsInPublicRoomsDirectoryInMSC3787Room(t *testing.T) { // See TestCannotSendKnockViaSendKnock func TestCannotSendKnockViaSendKnockInMSC3787Room(t *testing.T) { + // Venator: does not yet implement federation. + runtime.SkipIf(t, runtime.Venator) testValidationForSendMembershipEndpoint(t, "/_matrix/federation/v1/send_knock", "knock", map[string]interface{}{ "preset": "public_chat", @@ -57,6 +60,8 @@ func TestRestrictedRoomsLocalJoinInMSC3787Room(t *testing.T) { // See TestRestrictedRoomsRemoteJoin func TestRestrictedRoomsRemoteJoinInMSC3787Room(t *testing.T) { + // Venator: does not yet implement federation. + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) @@ -72,6 +77,8 @@ func TestRestrictedRoomsRemoteJoinInMSC3787Room(t *testing.T) { // See TestRestrictedRoomsRemoteJoinLocalUser func TestRestrictedRoomsRemoteJoinLocalUserInMSC3787Room(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) doTestRestrictedRoomsRemoteJoinLocalUser(t, roomVersion, joinRule) } diff --git a/tests/knocking_test.go b/tests/knocking_test.go index 449911d91..ee9c7201d 100644 --- a/tests/knocking_test.go +++ b/tests/knocking_test.go @@ -16,6 +16,7 @@ import ( "time" "github.com/matrix-org/complement" + "github.com/matrix-org/complement/runtime" "github.com/matrix-org/gomatrixserverlib" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/tidwall/gjson" @@ -40,6 +41,8 @@ func TestKnocking(t *testing.T) { } func doTestKnocking(t *testing.T, roomVersion string, joinRule string) { + // Venator: does not yet implement federation. + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) @@ -361,6 +364,8 @@ func knockOnRoomWithStatus(t *testing.T, c *client.CSAPI, roomID, reason string, // representing a knock room. For sanity-checking, this test will also create a public room and ensure it has a // 'join_rule' representing a publicly-joinable room. func TestKnockRoomsInPublicRoomsDirectory(t *testing.T) { + // Venator: does not support room v7 (>=v10 only) + runtime.SkipIf(t, runtime.Venator) // v7 is required for knocking doTestKnockRoomsInPublicRoomsDirectory(t, "7", "knock") } @@ -451,6 +456,8 @@ func publishAndCheckRoomJoinRule(t *testing.T, c *client.CSAPI, roomID, expected // TestCannotSendNonKnockViaSendKnock checks that we cannot submit anything via /send_knock except a knock func TestCannotSendNonKnockViaSendKnock(t *testing.T) { + // Venator: does not yet implement federation, nor room v7 (>=v10 only) + runtime.SkipIf(t, runtime.Venator) testValidationForSendMembershipEndpoint(t, "/_matrix/federation/v1/send_knock", "knock", map[string]interface{}{ "preset": "public_chat", diff --git a/tests/media_filename_test.go b/tests/media_filename_test.go index d5a857d56..bbb742ebe 100644 --- a/tests/media_filename_test.go +++ b/tests/media_filename_test.go @@ -43,6 +43,9 @@ func TestMediaFilenames(t *testing.T) { t.Run(fmt.Sprintf("Can download file '%s'", filename), func(t *testing.T) { // Synapse no longer allows downloads over the unauthenticated media endpoints by default runtime.SkipIf(t, runtime.Synapse) + // Venator is too young for any media to be available over the unauthenticated API, + // and always returns M_NOT_FOUND + runtime.SkipIf(t, runtime.Venator) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixPng, filename, "image/png") @@ -73,6 +76,9 @@ func TestMediaFilenames(t *testing.T) { t.Run("Can download specifying a different ASCII file name", func(t *testing.T) { // Synapse no longer allows downloads over the unauthenticated media endpoints by default runtime.SkipIf(t, runtime.Synapse) + // Venator is too young for any media to be available over the unauthenticated API, + // and always returns M_NOT_FOUND + runtime.SkipIf(t, runtime.Venator) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixPng, asciiFileName, "image/png") @@ -113,6 +119,9 @@ func TestMediaFilenames(t *testing.T) { t.Run("Can download specifying a different Unicode file name", func(t *testing.T) { // Synapse no longer allows downloads over the unauthenticated media endpoints by default runtime.SkipIf(t, runtime.Synapse) + // Venator is too young for any media to be available over the unauthenticated API, + // and always returns M_NOT_FOUND + runtime.SkipIf(t, runtime.Venator) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixPng, unicodeFileName, "image/png") @@ -144,6 +153,9 @@ func TestMediaFilenames(t *testing.T) { t.Run("Can download with Unicode file name locally", func(t *testing.T) { // Synapse no longer allows downloads over the unauthenticated media endpoints by default runtime.SkipIf(t, runtime.Synapse) + // Venator is too young for any media to be available over the unauthenticated API, + // and always returns M_NOT_FOUND + runtime.SkipIf(t, runtime.Venator) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixPng, unicodeFileName, "image/png") @@ -171,6 +183,9 @@ func TestMediaFilenames(t *testing.T) { t.Run("Can download with Unicode file name over federation", func(t *testing.T) { // Synapse no longer allows downloads over the unauthenticated media endpoints by default runtime.SkipIf(t, runtime.Synapse) + // Venator is too young for any media to be available over the unauthenticated API, + // and always returns M_NOT_FOUND. It also doesn't implement federation yet. + runtime.SkipIf(t, runtime.Venator) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixPng, unicodeFileName, "image/png") @@ -183,6 +198,8 @@ func TestMediaFilenames(t *testing.T) { }) t.Run("Can download with Unicode file name over federation via _matrix/client/v1/media/download", func(t *testing.T) { + // Venator: doesn't implement federation yet. + runtime.SkipIf(t, runtime.Venator) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixPng, unicodeFileName, "image/png") @@ -195,13 +212,11 @@ func TestMediaFilenames(t *testing.T) { }) t.Run("Will serve safe media types as inline", func(t *testing.T) { - if runtime.Homeserver != runtime.Conduwuit { - // We need to check that this security behaviour is being correctly run in - // conduwuit, but since this is not part of the Matrix spec we do not assume - // other homeservers are doing so. - // Skip Synapse because it no longer allows downloads over the unauthenticated media endpoints by default - t.Skip("Skipping test of Content-Disposition header requirements on non-conduwuit homeserver") - } + // We need to check that this security behaviour is being correctly run in + // conduwuit, but since this is not part of the Matrix spec we do not assume + // other homeservers are doing so. + // Skip Synapse because it no longer allows downloads over the unauthenticated media endpoints by default + runtime.SkipUnless(t, runtime.Conduwuit) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixPng, "", "image/png") @@ -214,12 +229,10 @@ func TestMediaFilenames(t *testing.T) { }) t.Run("Will serve safe media types as inline via _matrix/client/v1/media/download", func(t *testing.T) { - if runtime.Homeserver != runtime.Synapse && runtime.Homeserver != runtime.Conduwuit { - // We need to check that this security behaviour is being correctly run in - // Synapse or conduwuit, but since this is not part of the Matrix spec we do not assume - // other homeservers are doing so. - t.Skip("Skipping test of Content-Disposition header requirements on non-Synapse and non-conduwuit homeserver") - } + // We need to check that this security behaviour is being correctly run in + // Synapse or conduwuit, but since this is not part of the Matrix spec we do not assume + // other homeservers are doing so. + runtime.SkipUnless(t, runtime.Synapse, runtime.Conduwuit) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixPng, "", "image/png") @@ -232,13 +245,11 @@ func TestMediaFilenames(t *testing.T) { }) t.Run("Will serve safe media types with parameters as inline", func(t *testing.T) { - if runtime.Homeserver != runtime.Conduwuit { - // We need to check that this security behaviour is being correctly run in - // conduwuit, but since this is not part of the Matrix spec we do not assume - // other homeservers are doing so. - // Skip Synapse because it no longer allows downloads over the unauthenticated media endpoints by default - t.Skip("Skipping test of Content-Disposition header requirements on non-conduwuit homeserver") - } + // We need to check that this security behaviour is being correctly run in + // conduwuit, but since this is not part of the Matrix spec we do not assume + // other homeservers are doing so. + // Skip Synapse because it no longer allows downloads over the unauthenticated media endpoints by default + runtime.SkipUnless(t, runtime.Conduwuit) t.Parallel() // Add parameters and upper-case, which should be parsed as text/plain. @@ -252,12 +263,10 @@ func TestMediaFilenames(t *testing.T) { }) t.Run("Will serve safe media types with parameters as inline via _matrix/client/v1/media/download", func(t *testing.T) { - if runtime.Homeserver != runtime.Synapse && runtime.Homeserver != runtime.Conduwuit { - // We need to check that this security behaviour is being correctly run in - // Synapse or conduwuit, but since this is not part of the Matrix spec we do not assume - // other homeservers are doing so. - t.Skip("Skipping test of Content-Disposition header requirements on non-Synapse and non-conduwuit homeserver") - } + // We need to check that this security behaviour is being correctly run in + // Synapse or conduwuit, but since this is not part of the Matrix spec we do not assume + // other homeservers are doing so. + runtime.SkipUnless(t, runtime.Synapse, runtime.Conduwuit) t.Parallel() // Add parameters and upper-case, which should be parsed as text/plain. @@ -271,13 +280,11 @@ func TestMediaFilenames(t *testing.T) { }) t.Run("Will serve unsafe media types as attachments", func(t *testing.T) { - if runtime.Homeserver != runtime.Conduwuit { - // We need to check that this security behaviour is being correctly run in - // conduwuit, but since this is not part of the Matrix spec we do not assume - // other homeservers are doing so. - // Skip Synapse because it no longer allows downloads over the unauthenticated media endpoints by default - t.Skip("Skipping test of Content-Disposition header requirements on non-conduwuit homeserver") - } + // We need to check that this security behaviour is being correctly run in + // conduwuit, but since this is not part of the Matrix spec we do not assume + // other homeservers are doing so. + // Skip Synapse because it no longer allows downloads over the unauthenticated media endpoints by default + runtime.SkipUnless(t, runtime.Conduwuit) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixSvg, "", "image/svg") @@ -290,12 +297,10 @@ func TestMediaFilenames(t *testing.T) { }) t.Run("Will serve unsafe media types as attachments via _matrix/client/v1/media/download", func(t *testing.T) { - if runtime.Homeserver != runtime.Synapse && runtime.Homeserver != runtime.Conduwuit { - // We need to check that this security behaviour is being correctly run in - // Synapse or conduwuit, but since this is not part of the Matrix spec we do not assume - // other homeservers are doing so. - t.Skip("Skipping test of Content-Disposition header requirements on non-Synapse and non-conduwuit homeserver") - } + // We need to check that this security behaviour is being correctly run in + // Synapse or conduwuit, but since this is not part of the Matrix spec we do not assume + // other homeservers are doing so. + runtime.SkipUnless(t, runtime.Synapse, runtime.Conduwuit) t.Parallel() mxcUri := alice.UploadContent(t, data.MatrixSvg, "", "image/svg") diff --git a/tests/media_nofilename_test.go b/tests/media_nofilename_test.go index d72791af5..5c057439a 100644 --- a/tests/media_nofilename_test.go +++ b/tests/media_nofilename_test.go @@ -17,6 +17,8 @@ import ( func TestMediaWithoutFileName(t *testing.T) { // Synapse no longer allows downloads over the unauthenticated media endpoints by default runtime.SkipIf(t, runtime.Synapse) + // Venator is too young for any media to be available over the unauthenticated API, and always returns M_NOT_FOUND + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) @@ -103,6 +105,8 @@ func TestMediaWithoutFileName(t *testing.T) { // same test as above, but for the new _matrix/client/v1/media endpoint func TestMediaWithoutFileNameCSMediaV1(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) diff --git a/tests/media_thumbnail_test.go b/tests/media_thumbnail_test.go index dd499f189..2f1a30c21 100644 --- a/tests/media_thumbnail_test.go +++ b/tests/media_thumbnail_test.go @@ -39,6 +39,9 @@ func TestLocalPngThumbnail(t *testing.T) { t.Run("test /_matrix/media/v3 endpoint", func(t *testing.T) { // Synapse no longer allows downloads over the unauthenticated media endpoints by default runtime.SkipIf(t, runtime.Synapse) + // Venator is too young for any media to be available over the unauthenticated API, + // and always returns M_NOT_FOUND + runtime.SkipIf(t, runtime.Venator) fetchAndValidateThumbnail(t, alice, uri, false) }) @@ -51,6 +54,8 @@ func TestLocalPngThumbnail(t *testing.T) { // sytest: Remote media can be thumbnailed func TestRemotePngThumbnail(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) @@ -84,6 +89,8 @@ func TestRemotePngThumbnail(t *testing.T) { func TestFederationThumbnail(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) diff --git a/tests/msc4429/main_test.go b/tests/msc4429/main_test.go new file mode 100644 index 000000000..29daa335c --- /dev/null +++ b/tests/msc4429/main_test.go @@ -0,0 +1,11 @@ +package tests + +import ( + "testing" + + "github.com/matrix-org/complement" +) + +func TestMain(m *testing.M) { + complement.TestMain(m, "msc4429") +} diff --git a/tests/msc4429/msc4429_test.go b/tests/msc4429/msc4429_test.go new file mode 100644 index 000000000..8cd318ce1 --- /dev/null +++ b/tests/msc4429/msc4429_test.go @@ -0,0 +1,365 @@ +package tests + +import ( + "encoding/json" + "fmt" + "testing" + + "github.com/tidwall/gjson" + + "github.com/matrix-org/complement" + "github.com/matrix-org/complement/client" + "github.com/matrix-org/complement/helpers" + "github.com/matrix-org/complement/match" +) + +const ( + // TODO: Support stable prefix once MSC4429 is accepted. + // msc4429UsersStable = "users" + msc4429UsersUnstable = "org\\.matrix\\.msc4429\\.users" +) + +func TestMSC4429ProfileUpdates(t *testing.T) { + deployment := complement.Deploy(t, 1) + defer deployment.Destroy(t) + + t.Run("Initial sync includes requested profile fields and filters others", func(t *testing.T) { + alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "alice-initial"}) + bob := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "bob-initial"}) + + mustCreateSharedRoom(t, alice, bob) + + // Bob sets their displayname. + bob.MustSetDisplayName(t, "Bob Display") + // Bob sets their status. + mustSetProfileField(t, bob, "m.status", map[string]interface{}{ + "text": "busy", + "emoji": "🛑", + }) + + // Alice /sync's, but only asks for "m.status" changes. + // Exclude 'displayname'. + filter := mustBuildMSC4429Filter(t, []string{"m.status"}) + res, _ := alice.MustSync(t, client.SyncReq{Filter: filter}) + + // We should see the m.status profile update. + alice.MustSyncUntil(t, client.SyncReq{Filter: filter}, syncHasProfileUpdate(bob.UserID, "m.status", map[string]interface{}{ + "text": "busy", + "emoji": "🛑", + })) + + // We should NOT see a displayname profile update. + assertNoProfileUpdate(t, res, bob.UserID, "displayname") + }) + + // Receiving profile updates are an opt-in mechanism, according to MSC4429. + t.Run("No updates without profile_fields filter", func(t *testing.T) { + alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "alice-nofilter"}) + bob := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "bob-nofilter"}) + charlie := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "charlie-nofilter"}) + + mustCreateSharedRoom(t, alice, bob, charlie) + + // Perform an initial sync to get a since token. + _, since := alice.MustSync(t, client.SyncReq{}) + + // Bob sets their status. + mustSetProfileField(t, bob, "m.status", map[string]interface{}{ + "text": "away", + "emoji": "🟡", + }) + + // Assert that charlie receives bob's profile update in an incremental sync + // with the appropriate filter set. + filter := mustBuildMSC4429Filter(t, []string{"m.status"}) + charlie.MustSyncUntil(t, client.SyncReq{Filter: filter, Since: since}, syncHasProfileUpdate(bob.UserID, "m.status", map[string]interface{}{ + "text": "away", + "emoji": "🟡", + })) + + // Assert that alice does not receive the profile update in an incremental sync. + res, _ := alice.MustSync(t, client.SyncReq{Since: since}) + assertNoProfileUpdate(t, res, bob.UserID, "m.status") + }) + + t.Run("Widening profile_fields filter does not return old filtered updates", func(t *testing.T) { + alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "alice-widen"}) + bob := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "bob-widen"}) + + mustCreateSharedRoom(t, alice, bob) + + madeUpProfileField := "complement.made-up-profile-field" + + // Get a sync token for alice. + _, since := alice.MustSync(t, client.SyncReq{}) + + // Bob updates their profile with two fields. + mustSetProfileField(t, bob, madeUpProfileField, "foo") + mustSetProfileField(t, bob, "m.status", map[string]interface{}{ + "text": "away", + }) + + // Alice advances their sync token requesting just one of the profile fields. + // Widening the filter later must not make this old status update appear. + filter := mustBuildMSC4429Filter(t, []string{madeUpProfileField}) + // We should have only received the `complement.made-up-profile-field` field. + since = alice.MustSyncUntil( + t, + client.SyncReq{Since: since, Filter: filter}, + syncHasProfileUpdateWithoutFields(bob.UserID, madeUpProfileField, "foo", "m.status"), + ) + + // Bob updates a third profile field. + bob.MustSetDisplayName(t, "Bob Widened") + + // Alice should only receive the `displayname` update.` + filter = mustBuildMSC4429Filter(t, []string{madeUpProfileField, "m.status", "displayname"}) + alice.MustSyncUntil( + t, + client.SyncReq{Since: since, Filter: filter}, + syncHasProfileUpdateWithoutFields(bob.UserID, "displayname", "Bob Widened", "m.status", madeUpProfileField), + ) + }) + + // Check that only the latest update is returned per-user per-field. + t.Run("Incremental sync returns the latest update", func(t *testing.T) { + alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "alice-latest"}) + bob := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "bob-latest"}) + + mustCreateSharedRoom(t, alice, bob) + + filter := mustBuildMSC4429Filter(t, []string{"m.status"}) + _, since := alice.MustSync(t, client.SyncReq{Filter: filter}) + + mustSetProfileField(t, bob, "m.status", map[string]interface{}{ + "text": "first", + }) + mustSetProfileField(t, bob, "m.status", map[string]interface{}{ + "text": "second", + }) + + alice.MustSyncUntil( + t, + client.SyncReq{Since: since, Filter: filter}, + syncHasProfileUpdate(bob.UserID, "m.status", map[string]interface{}{ + "text": "second", + }), + ) + }) + + // Test that the homeserver informs the client when a profile field is cleared. + t.Run("Cleared profile field is returned as null", func(t *testing.T) { + alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "alice-clear"}) + bob := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "bob-clear"}) + + mustCreateSharedRoom(t, alice, bob) + + filter := mustBuildMSC4429Filter(t, []string{"m.status"}) + _, since := alice.MustSync(t, client.SyncReq{Filter: filter}) + + // Bob sets a status. + mustSetProfileField(t, bob, "m.status", map[string]interface{}{ + "text": "busy", + }) + + // Wait until alice can see the status. + since = alice.MustSyncUntil( + t, + client.SyncReq{Since: since, Filter: filter}, + syncHasProfileUpdate(bob.UserID, "m.status", map[string]interface{}{ + "text": "busy", + }), + ) + + // Bob clears their status. + mustSetProfileField(t, bob, "m.status", nil) + + // Wait until alice sees the status be set to `null` (nil). + alice.MustSyncUntil( + t, + client.SyncReq{Since: since, Filter: filter}, + syncHasProfileUpdate(bob.UserID, "m.status", nil), + ) + }) + + t.Run("A user leaving the last shared room returns a profile update of null", func(t *testing.T) { + alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "alice-leave"}) + bob := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "bob-leave"}) + + roomID := mustCreateSharedRoom(t, alice, bob) + + filter := mustBuildMSC4429Filter(t, []string{"m.status"}) + since := alice.MustSyncUntil( + t, + client.SyncReq{Filter: filter}, + client.SyncJoinedTo(alice.UserID, roomID), + ) + + // Bob sets a status while Alice and Bob share a room. + mustSetProfileField(t, bob, "m.status", map[string]interface{}{ + "text": "busy", + }) + + // Alice receives Bob's changed profile field. + since = alice.MustSyncUntil( + t, + client.SyncReq{Since: since, Filter: filter}, + syncHasProfileUpdate(bob.UserID, "m.status", map[string]interface{}{ + "text": "busy", + }), + ) + + // Bob leaves the only room shared with Alice. + bob.MustLeaveRoom(t, roomID) + + // Alice receives a null profile_updates value for Bob. This tells + // clients to clear their local cache for Bob's profile. + alice.MustSyncUntil( + t, + client.SyncReq{Since: since, Filter: filter}, + // Check that bob left the room and we get a null profile field for them. + // + // `MustSyncUntil` will loop until both checks are true. That + // doesn't necessarily have to happen in the same sync response. + client.SyncLeftFrom(bob.UserID, roomID), + syncHasProfileUpdatesNull(bob.UserID), + ) + }) +} + +// mustBuildMSC4429Filter builds a filter that can be used to limit the field +// IDs returned in a `/sync` response. +func mustBuildMSC4429Filter(t *testing.T, ids []string) string { + t.Helper() + filter := map[string]interface{}{ + "profile_fields": map[string]interface{}{ + "ids": ids, + }, + "org.matrix.msc4429.profile_fields": map[string]interface{}{ + "ids": ids, + }, + } + encoded, err := json.Marshal(filter) + if err != nil { + t.Fatalf("failed to marshal MSC4429 filter: %s", err) + } + return string(encoded) +} + +// mustCreateSharedRoom creates a shared room between `alice` and `bob` and returns the +// room ID. +func mustCreateSharedRoom(t *testing.T, users ...*client.CSAPI) string { + t.Helper() + + // Use one of the users to create the room. + roomID := users[0].MustCreateRoom(t, map[string]interface{}{ + "preset": "public_chat", + }) + + // Join all of the given users to the room. + for _, user := range users { + user.MustJoinRoom(t, roomID, nil) + user.MustSyncUntil(t, client.SyncReq{}, client.SyncJoinedTo(user.UserID, roomID)) + } + + return roomID +} + +// mustSetProfileField sets the given profile field ID to the given value on the given user's +// profile. +func mustSetProfileField(t *testing.T, user *client.CSAPI, field string, value interface{}) { + t.Helper() + user.MustDo(t, "PUT", []string{"_matrix", "client", "v3", "profile", user.UserID, field}, + client.WithJSONBody(t, map[string]interface{}{ + field: value, + }), + ) +} + +// getProfileUpdate extracts the given profile updates for a given user by field +// ID from a legacy `/sync` response. +func getProfileUpdate(res gjson.Result, userID, field string) (gjson.Result, bool) { + unstablePath := msc4429UsersUnstable + "." + client.GjsonEscape(userID) + ".profile_updates." + client.GjsonEscape(field) + unstableRes := res.Get(unstablePath) + if unstableRes.Exists() { + return unstableRes, true + } + return gjson.Result{}, false +} + +// getProfileUpdates extracts all profile updates for a given user from a legacy +// `/sync` response. +func getProfileUpdates(res gjson.Result, userID string) (gjson.Result, bool) { + unstablePath := msc4429UsersUnstable + "." + client.GjsonEscape(userID) + ".profile_updates" + unstableRes := res.Get(unstablePath) + if unstableRes.Exists() { + return unstableRes, true + } + return gjson.Result{}, false +} + +// assertNoProfileUpdate asserts that a user has not updated a field of their +// profile in the given legacy /sync response JSON. +func assertNoProfileUpdate(t *testing.T, res gjson.Result, userID, field string) { + t.Helper() + if update, ok := getProfileUpdate(res, userID, field); ok { + t.Fatalf("expected no profile update for %s %s: %s", userID, field, update.Raw) + } +} + +// syncHasProfileUpdate checks whether a given sync response contains a profile +// update of the given, expected field and value. +func syncHasProfileUpdate(userID, field string, expected interface{}) client.SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + update, ok := getProfileUpdate(topLevelSyncJSON, userID, field) + if !ok { + return fmt.Errorf("missing profile update for %s %s", userID, field) + } + if expected == nil { + if update.Type != gjson.Null { + return fmt.Errorf("expected null profile update for %s %s, got %s", userID, field, update.Type) + } + return nil + } + if err := match.JSONKeyEqual("", expected)(update); err != nil { + return fmt.Errorf("profile update mismatch for %s %s: %w", userID, field, err) + } + return nil + } +} + +// syncHasProfileUpdateWithoutField checks whether a sync response contains a +// profile update for one field and does not contain another field for the same +// user. +func syncHasProfileUpdateWithoutFields(userID, field string, expected interface{}, withoutFields ...string) client.SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + // Check that we have one field. + if err := syncHasProfileUpdate(userID, field, expected)(clientUserID, topLevelSyncJSON); err != nil { + return err + } + + // But not the `withoutField` fields. + for _, fieldName := range withoutFields { + if update, ok := getProfileUpdate(topLevelSyncJSON, userID, fieldName); ok { + return fmt.Errorf("unexpected profile update for %s %s: %s", userID, fieldName, update.Raw) + } + } + + return nil + } +} + +// syncHasProfileUpdatesNull checks whether a sync response contains a null +// profile_updates value for the given user. +func syncHasProfileUpdatesNull(userID string) client.SyncCheckOpt { + return func(clientUserID string, topLevelSyncJSON gjson.Result) error { + updates, ok := getProfileUpdates(topLevelSyncJSON, userID) + if !ok { + return fmt.Errorf("missing profile updates for %s", userID) + } + if updates.Type != gjson.Null { + return fmt.Errorf("expected a null profile update for %s, got %s", userID, updates.Type) + } + return nil + } +} diff --git a/tests/restricted_room_hierarchy_test.go b/tests/restricted_room_hierarchy_test.go index 32ad0f0ad..a9d80eeda 100644 --- a/tests/restricted_room_hierarchy_test.go +++ b/tests/restricted_room_hierarchy_test.go @@ -5,6 +5,7 @@ package tests import ( "testing" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -121,6 +122,8 @@ func TestRestrictedRoomsSpacesSummaryLocal(t *testing.T) { // different homeservers, and one might not have the proper information needed to // decide if a user is in a room. func TestRestrictedRoomsSpacesSummaryFederation(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) diff --git a/tests/restricted_rooms_test.go b/tests/restricted_rooms_test.go index efcd7e7ba..b72b630c0 100644 --- a/tests/restricted_rooms_test.go +++ b/tests/restricted_rooms_test.go @@ -187,6 +187,8 @@ func checkRestrictedRoom(t *testing.T, deployment complement.Deployment, alice * // Test joining a room with join rules restricted to membership in another room. func TestRestrictedRoomsLocalJoin(t *testing.T) { + // Venator: does not support room version 8 (>=v10 only) + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) @@ -218,11 +220,15 @@ func TestRestrictedRoomsRemoteJoin(t *testing.T) { // A server will do a remote join for a local user if it is unable to to issue // joins in a restricted room it is already participating in. func TestRestrictedRoomsRemoteJoinLocalUser(t *testing.T) { + // Venator: does not support room version 8 (>=v10 only) + runtime.SkipIf(t, runtime.Venator) doTestRestrictedRoomsRemoteJoinLocalUser(t, "8", "restricted") } func doTestRestrictedRoomsRemoteJoinLocalUser(t *testing.T, roomVersion string, joinRule string) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/2801 + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) @@ -331,6 +337,8 @@ func TestRestrictedRoomsRemoteJoinFailOver(t *testing.T) { func doTestRestrictedRoomsRemoteJoinFailOver(t *testing.T, roomVersion string, joinRule string) { runtime.SkipIf(t, runtime.Dendrite) // FIXME: https://github.com/matrix-org/dendrite/issues/2801 + // Venator: does not yet implement federation. + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 3) defer deployment.Destroy(t) @@ -469,6 +477,8 @@ func TestRestrictedRoomsLocalJoinNoCreatorsUsesPowerLevelsV11(t *testing.T) { } func doTestRestrictedRoomsLocalJoinNoCreatorsUsesPowerLevels(t *testing.T, roomVersion string, joinRule string) { + // Venator: does not yet implement federation. + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) // Create the room diff --git a/tests/room_hierarchy_test.go b/tests/room_hierarchy_test.go index 0d58fcbf2..4980ba8a1 100644 --- a/tests/room_hierarchy_test.go +++ b/tests/room_hierarchy_test.go @@ -18,6 +18,7 @@ import ( "net/url" "testing" + "github.com/matrix-org/complement/runtime" "github.com/tidwall/gjson" "github.com/matrix-org/complement" @@ -544,6 +545,8 @@ func TestClientSpacesSummaryJoinRules(t *testing.T) { // Tests that: // - Querying from root returns the entire graph func TestFederatedClientSpaces(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) diff --git a/tests/room_summary_test.go b/tests/room_summary_test.go index 31d87f470..40dbd19fa 100644 --- a/tests/room_summary_test.go +++ b/tests/room_summary_test.go @@ -1,3 +1,5 @@ +//go:build !dendrite_blacklist + // Tests the GET /_matrix/client/v1/room_summary/{roomIdOrAlias} endpoint // as specified in https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv1room_summaryroomidoralias diff --git a/tests/room_timestamp_to_event_test.go b/tests/room_timestamp_to_event_test.go index fbc83e225..028315cc6 100644 --- a/tests/room_timestamp_to_event_test.go +++ b/tests/room_timestamp_to_event_test.go @@ -21,12 +21,15 @@ import ( "github.com/matrix-org/complement/helpers" "github.com/matrix-org/complement/match" "github.com/matrix-org/complement/must" + "github.com/matrix-org/complement/runtime" "github.com/matrix-org/gomatrixserverlib/spec" "github.com/tidwall/gjson" "golang.org/x/exp/slices" ) func TestJumpToDateEndpoint(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.OldDeploy(t, b.BlueprintHSWithApplicationService) defer deployment.Destroy(t) diff --git a/tests/unknown_endpoints_test.go b/tests/unknown_endpoints_test.go index 21761a37c..f45701e33 100644 --- a/tests/unknown_endpoints_test.go +++ b/tests/unknown_endpoints_test.go @@ -9,6 +9,7 @@ import ( "github.com/matrix-org/complement/helpers" "github.com/matrix-org/complement/match" "github.com/matrix-org/complement/must" + "github.com/matrix-org/complement/runtime" ) func queryUnknownEndpoint(t *testing.T, user *client.CSAPI, paths []string) { @@ -73,7 +74,11 @@ func TestUnknownEndpoints(t *testing.T) { // v3 should exist, but not v3/unknown. queryUnknownEndpoint(t, alice, []string{"_matrix", "key", "v2", "unknown"}) - queryUnknownMethod(t, alice, "PUT", []string{"_matrix", "key", "v2", "query"}) + if runtime.Homeserver != runtime.Venator { + // Venator does not implement this endpoint at all - since it doesn't know what the expected methods are, + // it returns 404 M_UNRECOGNIZED, instead of 405 M_UNRECOGNIZED, which causes this to fail. + queryUnknownMethod(t, alice, "PUT", []string{"_matrix", "key", "v2", "query"}) + } }) // Unknown media endpoints. diff --git a/tests/v12_test.go b/tests/v12_test.go index 6139bc6f3..611783d04 100644 --- a/tests/v12_test.go +++ b/tests/v12_test.go @@ -53,6 +53,9 @@ func TestMSC4289PrivilegedRoomCreators(t *testing.T) { } t.Run("PL event is missing creator in users map", func(t *testing.T) { + // Venator: default values (including empty) for power levels are skipped during marshalling, so this test + // flakes as the empty users object is not present (which is legal) + runtime.SkipIf(t, runtime.Venator) roomID := alice.MustCreateRoom(t, map[string]interface{}{ "room_version": roomVersion12, }) @@ -136,6 +139,7 @@ func TestMSC4289PrivilegedRoomCreators(t *testing.T) { // technically not a MSC4289 thing but implementations may set the creator PL to be // above the value expressible in canonical JSON to implement "infinite". t.Run("power level cannot be set beyond max canonical JSON int", func(t *testing.T) { + runtime.SkipIf(t, runtime.Venator) roomID := alice.MustCreateRoom(t, map[string]interface{}{ "room_version": roomVersion12, "preset": "public_chat", @@ -183,6 +187,8 @@ func TestMSC4289PrivilegedRoomCreators(t *testing.T) { }) }) t.Run("admin with >PL100 sorts after the room creator for state resolution", func(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) srv := federation.NewServer(t, deployment, federation.HandleKeyRequests(), federation.HandleMakeSendJoinRequests(), @@ -615,6 +621,8 @@ func TestMSC4291RoomIDAsHashOfCreateEvent(t *testing.T) { } func TestComplementCanCreateValidV12Rooms(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) @@ -645,6 +653,8 @@ func TestComplementCanCreateValidV12Rooms(t *testing.T) { } func TestMSC4291RoomIDAsHashOfCreateEvent_AuthEventsOmitsCreateEvent(t *testing.T) { + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{}) @@ -915,6 +925,8 @@ func assertCreateEventIsRoomID(t ct.TestLike, client *client.CSAPI, roomID strin // in other words we apply state resolution to (Alice leave, 250th Charlie display name change). func TestMSC4297StateResolutionV2_1_starts_from_empty_set(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // needs additional fixes + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) srv := federation.NewServer(t, deployment, @@ -1096,6 +1108,8 @@ func TestMSC4297StateResolutionV2_1_starts_from_empty_set(t *testing.T) { func TestMSC4297StateResolutionV2_1_includes_conflicted_subgraph(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // needs additional fixes + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 1) defer deployment.Destroy(t) srv := federation.NewServer(t, deployment, @@ -1340,6 +1354,8 @@ func asEventIDs(pdus []gomatrixserverlib.PDU) []string { func TestMSC4311FullCreateEventOnStrippedState(t *testing.T) { runtime.SkipIf(t, runtime.Dendrite) // does not implement it yet + // Venator: does not yet implement federation + runtime.SkipIf(t, runtime.Venator) deployment := complement.Deploy(t, 2) defer deployment.Destroy(t) alice := deployment.Register(t, "hs1", helpers.RegistrationOpts{LocalpartSuffix: "alice"})