feat: add support for WorkspaceUpdates to WebsocketDialer (#15534)

closes #14730

Adds support for WorkspaceUpdates to the WebsocketDialer. This allows us to dial the new endpoint added in #14847 and connect it up to a `tailnet.Controllers` to connect to all agents over the tailnet.

I refactored the fakeWorkspaceUpdatesProvider to a mock and moved it to `tailnettest` so it could be more easily reused.  The Mock is a little more full-featured.
This commit is contained in:
Spike Curtis
2024-11-18 10:54:11 +04:00
committed by GitHub
parent 16992ee548
commit 747f7ce173
9 changed files with 305 additions and 78 deletions
+11 -31
View File
@@ -11,6 +11,7 @@ import (
"github.com/google/uuid"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
"golang.org/x/xerrors"
"tailscale.com/tailcfg"
@@ -236,8 +237,8 @@ func TestClientUserCoordinateeAuth(t *testing.T) {
agentID2 := uuid.UUID{0x02}
clientID := uuid.UUID{0x03}
updatesCh := make(chan *proto.WorkspaceUpdate, 1)
updatesProvider := &fakeUpdatesProvider{ch: updatesCh}
ctrl := gomock.NewController(t)
updatesProvider := tailnettest.NewMockWorkspaceUpdatesProvider(ctrl)
fCoord, client := createUpdateService(t, ctx, clientID, updatesProvider)
@@ -271,8 +272,10 @@ func TestWorkspaceUpdates(t *testing.T) {
t.Parallel()
ctx := testutil.Context(t, testutil.WaitShort)
ctrl := gomock.NewController(t)
updatesProvider := tailnettest.NewMockWorkspaceUpdatesProvider(ctrl)
mSub := tailnettest.NewMockSubscription(ctrl)
updatesCh := make(chan *proto.WorkspaceUpdate, 1)
updatesProvider := &fakeUpdatesProvider{ch: updatesCh}
clientID := uuid.UUID{0x03}
wsID := uuid.UUID{0x04}
@@ -293,6 +296,11 @@ func TestWorkspaceUpdates(t *testing.T) {
DeletedAgents: []*proto.Agent{},
}
updatesCh <- expected
updatesProvider.EXPECT().Subscribe(gomock.Any(), clientID).
Times(1).
Return(mSub, nil)
mSub.EXPECT().Updates().MinTimes(1).Return(updatesCh)
mSub.EXPECT().Close().Times(1).Return(nil)
updatesStream, err := client.WorkspaceUpdates(ctx, &proto.WorkspaceUpdatesRequest{
WorkspaceOwnerId: tailnet.UUIDToByteSlice(clientID),
@@ -354,34 +362,6 @@ func createUpdateService(t *testing.T, ctx context.Context, clientID uuid.UUID,
return fCoord, client
}
type fakeUpdatesProvider struct {
ch chan *proto.WorkspaceUpdate
}
func (*fakeUpdatesProvider) Close() error {
return nil
}
func (f *fakeUpdatesProvider) Subscribe(context.Context, uuid.UUID) (tailnet.Subscription, error) {
return &fakeSubscription{ch: f.ch}, nil
}
type fakeSubscription struct {
ch chan *proto.WorkspaceUpdate
}
func (*fakeSubscription) Close() error {
return nil
}
func (f *fakeSubscription) Updates() <-chan *proto.WorkspaceUpdate {
return f.ch
}
var _ tailnet.Subscription = (*fakeSubscription)(nil)
var _ tailnet.WorkspaceUpdatesProvider = (*fakeUpdatesProvider)(nil)
type fakeTunnelAuth struct{}
// AuthorizeTunnel implements tailnet.TunnelAuthorizer.
+68
View File
@@ -0,0 +1,68 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/coder/coder/v2/tailnet (interfaces: Subscription)
//
// Generated by this command:
//
// mockgen -destination ./subscriptionmock.go -package tailnettest github.com/coder/coder/v2/tailnet Subscription
//
// Package tailnettest is a generated GoMock package.
package tailnettest
import (
reflect "reflect"
proto "github.com/coder/coder/v2/tailnet/proto"
gomock "go.uber.org/mock/gomock"
)
// MockSubscription is a mock of Subscription interface.
type MockSubscription struct {
ctrl *gomock.Controller
recorder *MockSubscriptionMockRecorder
}
// MockSubscriptionMockRecorder is the mock recorder for MockSubscription.
type MockSubscriptionMockRecorder struct {
mock *MockSubscription
}
// NewMockSubscription creates a new mock instance.
func NewMockSubscription(ctrl *gomock.Controller) *MockSubscription {
mock := &MockSubscription{ctrl: ctrl}
mock.recorder = &MockSubscriptionMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockSubscription) EXPECT() *MockSubscriptionMockRecorder {
return m.recorder
}
// Close mocks base method.
func (m *MockSubscription) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
ret0, _ := ret[0].(error)
return ret0
}
// Close indicates an expected call of Close.
func (mr *MockSubscriptionMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockSubscription)(nil).Close))
}
// Updates mocks base method.
func (m *MockSubscription) Updates() <-chan *proto.WorkspaceUpdate {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Updates")
ret0, _ := ret[0].(<-chan *proto.WorkspaceUpdate)
return ret0
}
// Updates indicates an expected call of Updates.
func (mr *MockSubscriptionMockRecorder) Updates() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Updates", reflect.TypeOf((*MockSubscription)(nil).Updates))
}
+2
View File
@@ -26,6 +26,8 @@ import (
//go:generate mockgen -destination ./coordinatormock.go -package tailnettest github.com/coder/coder/v2/tailnet Coordinator
//go:generate mockgen -destination ./coordinateemock.go -package tailnettest github.com/coder/coder/v2/tailnet Coordinatee
//go:generate mockgen -destination ./workspaceupdatesprovidermock.go -package tailnettest github.com/coder/coder/v2/tailnet WorkspaceUpdatesProvider
//go:generate mockgen -destination ./subscriptionmock.go -package tailnettest github.com/coder/coder/v2/tailnet Subscription
type derpAndSTUNCfg struct {
DisableSTUN bool
@@ -0,0 +1,71 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: github.com/coder/coder/v2/tailnet (interfaces: WorkspaceUpdatesProvider)
//
// Generated by this command:
//
// mockgen -destination ./workspaceupdatesprovidermock.go -package tailnettest github.com/coder/coder/v2/tailnet WorkspaceUpdatesProvider
//
// Package tailnettest is a generated GoMock package.
package tailnettest
import (
context "context"
reflect "reflect"
tailnet "github.com/coder/coder/v2/tailnet"
uuid "github.com/google/uuid"
gomock "go.uber.org/mock/gomock"
)
// MockWorkspaceUpdatesProvider is a mock of WorkspaceUpdatesProvider interface.
type MockWorkspaceUpdatesProvider struct {
ctrl *gomock.Controller
recorder *MockWorkspaceUpdatesProviderMockRecorder
}
// MockWorkspaceUpdatesProviderMockRecorder is the mock recorder for MockWorkspaceUpdatesProvider.
type MockWorkspaceUpdatesProviderMockRecorder struct {
mock *MockWorkspaceUpdatesProvider
}
// NewMockWorkspaceUpdatesProvider creates a new mock instance.
func NewMockWorkspaceUpdatesProvider(ctrl *gomock.Controller) *MockWorkspaceUpdatesProvider {
mock := &MockWorkspaceUpdatesProvider{ctrl: ctrl}
mock.recorder = &MockWorkspaceUpdatesProviderMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockWorkspaceUpdatesProvider) EXPECT() *MockWorkspaceUpdatesProviderMockRecorder {
return m.recorder
}
// Close mocks base method.
func (m *MockWorkspaceUpdatesProvider) Close() error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Close")
ret0, _ := ret[0].(error)
return ret0
}
// Close indicates an expected call of Close.
func (mr *MockWorkspaceUpdatesProviderMockRecorder) Close() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Close", reflect.TypeOf((*MockWorkspaceUpdatesProvider)(nil).Close))
}
// Subscribe mocks base method.
func (m *MockWorkspaceUpdatesProvider) Subscribe(arg0 context.Context, arg1 uuid.UUID) (tailnet.Subscription, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Subscribe", arg0, arg1)
ret0, _ := ret[0].(tailnet.Subscription)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Subscribe indicates an expected call of Subscribe.
func (mr *MockWorkspaceUpdatesProviderMockRecorder) Subscribe(arg0, arg1 any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Subscribe", reflect.TypeOf((*MockWorkspaceUpdatesProvider)(nil).Subscribe), arg0, arg1)
}