Merge branch 'main' into kegan/complement

This commit is contained in:
Kegan Dougal 2023-10-11 16:49:52 +01:00
commit 54c3e573d1
5 changed files with 116 additions and 22 deletions

41
.github/workflows/release.yml vendored Normal file
View File

@ -0,0 +1,41 @@
name: "Create draft release with binaries after tag"
on:
push:
tags: ["v*"]
permissions:
contents: write # to upload the binaries to the release
jobs:
build:
runs-on: ubuntu-latest
strategy:
matrix:
os: ["linux"]
arch: ["amd64", "arm64"]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v4
with:
go-version: "1.20"
- run: mkdir build
- run: go build -trimpath -o build/syncv3_${{ matrix.os }}_${{ matrix.arch }} ./cmd/syncv3
env:
GOOS: ${{ matrix.os }}
GOARCH: ${{ matrix.arch }}
- name: "Upload binary as artifact"
uses: actions/upload-artifact@v3
with:
name: build
path: build/syncv3_${{ matrix.os }}_${{ matrix.arch }}
create-release:
needs: ["build"]
runs-on: ubuntu-latest
steps:
- name: "Fetch all binaries"
uses: actions/download-artifact@v3
- name: "Create release"
uses: softprops/action-gh-release@de2c0eb89ae2a093876385947365aca7b0e5f844 # v1
with:
files: build/*
draft: True
fail_on_unmatched_files: true

7
RELEASING.md Normal file
View File

@ -0,0 +1,7 @@
0. Ensure that CI passes against the commit you want to release.
1. Tag that release. The tag name should start with `v`. Push it to GitHub.
2. GitHub should see tag and trigger [a GHA workflow](https://github.com/matrix-org/sliding-sync/actions/workflows/release.yml). It should:
- build binaries,
- create a draft release for this tag, and
- uploads the binaries as artifacts to this release.
3. Go to https://github.com/matrix-org/sliding-sync/releases/ to find your release. Check that the binaries are attached successfully. Write release notes. When you're happy, publish.

View File

@ -28,7 +28,7 @@ import (
var GitCommit string
const version = "0.99.10"
const version = "0.99.11"
var (
flags = flag.NewFlagSet("goose", flag.ExitOnError)

View File

@ -10,12 +10,31 @@ import (
"github.com/matrix-org/sliding-sync/pubsub"
)
type syncSlice[T any] struct {
slice []T
mu sync.Mutex
}
func (s *syncSlice[T]) append(item T) {
s.mu.Lock()
defer s.mu.Unlock()
s.slice = append(s.slice, item)
}
func (s *syncSlice[T]) clone() []T {
s.mu.Lock()
defer s.mu.Unlock()
result := make([]T, len(s.slice))
copy(result, s.slice)
return result
}
func TestDeviceTickerBasic(t *testing.T) {
duration := time.Millisecond
ticker := NewDeviceDataTicker(duration)
var payloads []*pubsub.V2DeviceData
var payloads syncSlice[*pubsub.V2DeviceData]
ticker.SetCallback(func(payload *pubsub.V2DeviceData) {
payloads = append(payloads, payload)
payloads.append(payload)
})
var wg sync.WaitGroup
wg.Add(1)
@ -31,29 +50,31 @@ func TestDeviceTickerBasic(t *testing.T) {
DeviceID: "b",
})
time.Sleep(duration * 2)
if len(payloads) != 1 {
t.Fatalf("expected 1 callback, got %d", len(payloads))
result := payloads.clone()
if len(result) != 1 {
t.Fatalf("expected 1 callback, got %d", len(result))
}
want := map[string][]string{
"a": {"b"},
}
assertPayloadEqual(t, payloads[0].UserIDToDeviceIDs, want)
assertPayloadEqual(t, result[0].UserIDToDeviceIDs, want)
// check stopping works
payloads = []*pubsub.V2DeviceData{}
payloads = syncSlice[*pubsub.V2DeviceData]{}
ticker.Stop()
wg.Wait()
time.Sleep(duration * 2)
if len(payloads) != 0 {
t.Fatalf("got extra payloads: %+v", payloads)
result = payloads.clone()
if len(result) != 0 {
t.Fatalf("got extra payloads: %+v", result)
}
}
func TestDeviceTickerBatchesCorrectly(t *testing.T) {
duration := 100 * time.Millisecond
ticker := NewDeviceDataTicker(duration)
var payloads []*pubsub.V2DeviceData
var payloads syncSlice[*pubsub.V2DeviceData]
ticker.SetCallback(func(payload *pubsub.V2DeviceData) {
payloads = append(payloads, payload)
payloads.append(payload)
})
go ticker.Run()
defer ticker.Stop()
@ -74,23 +95,23 @@ func TestDeviceTickerBatchesCorrectly(t *testing.T) {
DeviceID: "y", // new device and user
})
time.Sleep(duration * 2)
if len(payloads) != 1 {
t.Fatalf("expected 1 callback, got %d", len(payloads))
result := payloads.clone()
if len(result) != 1 {
t.Fatalf("expected 1 callback, got %d", len(result))
}
want := map[string][]string{
"a": {"b", "bb"},
"x": {"y"},
}
assertPayloadEqual(t, payloads[0].UserIDToDeviceIDs, want)
assertPayloadEqual(t, result[0].UserIDToDeviceIDs, want)
}
func TestDeviceTickerForgetsAfterEmitting(t *testing.T) {
duration := time.Millisecond
ticker := NewDeviceDataTicker(duration)
var payloads []*pubsub.V2DeviceData
var payloads syncSlice[*pubsub.V2DeviceData]
ticker.SetCallback(func(payload *pubsub.V2DeviceData) {
payloads = append(payloads, payload)
payloads.append(payload)
})
ticker.Remember(PollerID{
UserID: "a",
@ -104,8 +125,9 @@ func TestDeviceTickerForgetsAfterEmitting(t *testing.T) {
DeviceID: "b",
})
time.Sleep(10 * duration)
if len(payloads) != 1 {
t.Fatalf("got %d payloads, want 1", len(payloads))
result := payloads.clone()
if len(result) != 1 {
t.Fatalf("got %d payloads, want 1", len(result))
}
}

View File

@ -18,6 +18,31 @@ import (
const initialSinceToken = "0"
// monkey patch out time.Since with a test controlled value.
// This is done in the init block so we can make sure we swap it out BEFORE any pollers
// start. If we wait until pollers exist, we get data races. This includes pollers in tests
// which don't use timeSince, hence the init block.
var (
timeSinceMu sync.Mutex
timeSinceValue = time.Duration(0) // 0 means use the real impl
)
func setTimeSinceValue(val time.Duration) {
timeSinceMu.Lock()
timeSinceValue = val
timeSinceMu.Unlock()
}
func init() {
timeSince = func(t time.Time) time.Duration {
timeSinceMu.Lock()
defer timeSinceMu.Unlock()
if timeSinceValue == 0 {
return time.Since(t)
}
return timeSinceValue
}
}
// Tests that EnsurePolling works in the happy case
func TestPollerMapEnsurePolling(t *testing.T) {
nextSince := "next"
@ -528,9 +553,8 @@ func TestPollerPollUpdateDeviceSincePeriodically(t *testing.T) {
wantSinceFromSync = next
// 4. ... some time has passed, this triggers the 1min limit
timeSince = func(d time.Time) time.Duration {
return time.Minute * 2
}
setTimeSinceValue(time.Minute * 2)
defer setTimeSinceValue(0) // reset
next = "10"
syncResponses <- &SyncResponse{NextBatch: next}
mustEqualSince(t, <-syncCalledWithSince, wantSinceFromSync)