github.com/anycable/anycable-go@v1.5.1/streams/controller_test.go (about) 1 package streams 2 3 import ( 4 "fmt" 5 "log/slog" 6 "testing" 7 8 "github.com/anycable/anycable-go/common" 9 "github.com/stretchr/testify/assert" 10 "github.com/stretchr/testify/require" 11 ) 12 13 const ( 14 key = "s3Krit" 15 // Turbo.signed_stream_verifier_key = 's3Krit' 16 // Turbo::StreamsChannel.signed_stream_name([:chat, "2021"]) 17 stream = "ImNoYXQ6MjAyMSI=--f9ee45dbccb1da04d8ceb99cc820207804370ba0d06b46fc3b8b373af1315628" 18 ) 19 20 func TestNewController(t *testing.T) { 21 t.Run("No stream name", func(t *testing.T) { 22 resolver := func(string) (*SubscribeRequest, error) { 23 return &SubscribeRequest{}, nil 24 } 25 26 subject := NewController(key, resolver, slog.Default()) 27 28 require.NotNil(t, subject) 29 30 res, err := subject.Subscribe("42", nil, "name=jack", "") 31 32 require.Error(t, err) 33 require.NotNil(t, res) 34 35 assert.Equal(t, common.FAILURE, res.Status) 36 assert.Equal(t, []string{common.RejectionMessage("")}, res.Transmissions) 37 }) 38 } 39 40 func TestStreamsController(t *testing.T) { 41 t.Run("Subscribe - public", func(t *testing.T) { 42 conf := NewConfig() 43 conf.Public = true 44 subject := NewStreamsController(&conf, slog.Default()) 45 46 require.NotNil(t, subject) 47 48 res, err := subject.Subscribe("42", nil, "name=jack", `{"channel":"$pubsub","stream_name":"chat:2024"}`) 49 50 require.NoError(t, err) 51 require.NotNil(t, res) 52 require.Equal(t, common.SUCCESS, res.Status) 53 assert.Equal(t, []string{common.ConfirmationMessage(`{"channel":"$pubsub","stream_name":"chat:2024"}`)}, res.Transmissions) 54 assert.Equal(t, []string{"chat:2024"}, res.Streams) 55 assert.Equal(t, -1, res.DisconnectInterest) 56 assert.Equal(t, "chat:2024", res.IState[common.WHISPER_STREAM_STATE]) 57 }) 58 59 t.Run("Subscribe - no public allowed", func(t *testing.T) { 60 conf := NewConfig() 61 subject := NewStreamsController(&conf, slog.Default()) 62 63 require.NotNil(t, subject) 64 65 res, err := subject.Subscribe("42", nil, "name=jack", `{"channel":"$pubsub","stream_name":"chat:2024"}`) 66 67 require.Error(t, err) 68 require.NotNil(t, res) 69 assert.Equal(t, []string{common.RejectionMessage(`{"channel":"$pubsub","stream_name":"chat:2024"}`)}, res.Transmissions) 70 }) 71 72 t.Run("Subscribe - signed", func(t *testing.T) { 73 conf := NewConfig() 74 conf.Secret = key 75 subject := NewStreamsController(&conf, slog.Default()) 76 77 require.NotNil(t, subject) 78 79 identifier := `{"channel":"$pubsub","signed_stream_name":"` + stream + `"}` 80 81 res, err := subject.Subscribe("42", nil, "name=jack", identifier) 82 83 require.NoError(t, err) 84 require.NotNil(t, res) 85 require.Equal(t, common.SUCCESS, res.Status) 86 assert.Equal(t, []string{common.ConfirmationMessage(identifier)}, res.Transmissions) 87 assert.Equal(t, []string{"chat:2021"}, res.Streams) 88 assert.Equal(t, -1, res.DisconnectInterest) 89 assert.Nil(t, res.IState) 90 }) 91 92 t.Run("Subscribe - signed - whisper", func(t *testing.T) { 93 conf := NewConfig() 94 conf.Secret = key 95 conf.Whisper = true 96 subject := NewStreamsController(&conf, slog.Default()) 97 98 require.NotNil(t, subject) 99 100 identifier := `{"channel":"$pubsub","signed_stream_name":"` + stream + `"}` 101 102 res, err := subject.Subscribe("42", nil, "name=jack", identifier) 103 104 require.NoError(t, err) 105 require.NotNil(t, res) 106 require.Equal(t, common.SUCCESS, res.Status) 107 assert.Equal(t, []string{common.ConfirmationMessage(identifier)}, res.Transmissions) 108 assert.Equal(t, []string{"chat:2021"}, res.Streams) 109 assert.Equal(t, -1, res.DisconnectInterest) 110 assert.Equal(t, "chat:2021", res.IState[common.WHISPER_STREAM_STATE]) 111 }) 112 } 113 114 func TestTurboController(t *testing.T) { 115 env := common.NewSessionEnv("ws://demo.anycable.io/cable", &map[string]string{"cookie": "val=1;"}) 116 subject := NewTurboController(key, slog.Default()) 117 118 t.Run("Subscribe (success)", func(t *testing.T) { 119 channel := fmt.Sprintf("{\"channel\":\"Turbo::StreamsChannel\",\"signed_stream_name\":\"%s\"}", stream) 120 121 res, err := subject.Subscribe("42", env, "name=jack", channel) 122 123 require.NoError(t, err) 124 require.NotNil(t, res) 125 require.Equal(t, common.SUCCESS, res.Status) 126 assert.Equal(t, []string{common.ConfirmationMessage(channel)}, res.Transmissions) 127 assert.Equal(t, []string{"chat:2021"}, res.Streams) 128 assert.Equal(t, -1, res.DisconnectInterest) 129 }) 130 131 t.Run("Subscribe (failure)", func(t *testing.T) { 132 channel := fmt.Sprintf("{\"channel\":\"Turbo::StreamsChannel\",\"signed_stream_name\":\"%s\"}", "fake_id") 133 134 res, err := subject.Subscribe("42", env, "name=jack", channel) 135 136 require.NoError(t, err) 137 require.NotNil(t, res) 138 require.Equal(t, common.FAILURE, res.Status) 139 assert.Equal(t, []string{common.RejectionMessage(channel)}, res.Transmissions) 140 }) 141 142 t.Run("Subscribe (failure + not a string)", func(t *testing.T) { 143 signed := "WyJjaGF0LzIwMjMiLDE2ODUwMjQwMTdd--5b6661024d4c463c4936cd1542bc9a7672dd8039ac407d0b6c901697190e8aeb" 144 channel := fmt.Sprintf("{\"channel\":\"Turbo::StreamsChannel\",\"signed_stream_name\":\"%s\"}", signed) 145 146 res, err := subject.Subscribe("42", env, "name=jack", channel) 147 148 require.NoError(t, err) 149 require.NotNil(t, res) 150 require.Equal(t, common.FAILURE, res.Status) 151 assert.Equal(t, []string{common.RejectionMessage(channel)}, res.Transmissions) 152 }) 153 154 t.Run("Unsubscribe", func(t *testing.T) { 155 channel := fmt.Sprintf("{\"channel\":\"Turbo::StreamsChannel\",\"signed_stream_name\":\"%s\"}", stream) 156 157 res, err := subject.Unsubscribe("42", env, "name=jack", channel) 158 159 require.NoError(t, err) 160 require.NotNil(t, res) 161 require.Equal(t, common.SUCCESS, res.Status) 162 assert.Equal(t, []string{}, res.Transmissions) 163 assert.Equal(t, []string{}, res.Streams) 164 assert.Equal(t, true, res.StopAllStreams) 165 }) 166 } 167 168 func TestCableReadyController(t *testing.T) { 169 env := common.NewSessionEnv("ws://demo.anycable.io/cable", &map[string]string{"cookie": "val=1;"}) 170 subject := NewCableReadyController(key, slog.Default()) 171 172 t.Run("Subscribe (success)", func(t *testing.T) { 173 channel := fmt.Sprintf("{\"channel\":\"CableReady::Stream\",\"identifier\":\"%s\"}", stream) 174 175 res, err := subject.Subscribe("42", env, "name=jack", channel) 176 177 require.NoError(t, err) 178 require.NotNil(t, res) 179 require.Equal(t, common.SUCCESS, res.Status) 180 assert.Equal(t, []string{common.ConfirmationMessage(channel)}, res.Transmissions) 181 assert.Equal(t, []string{"chat:2021"}, res.Streams) 182 assert.Equal(t, -1, res.DisconnectInterest) 183 }) 184 185 t.Run("Subscribe (failure)", func(t *testing.T) { 186 channel := fmt.Sprintf("{\"channel\":\"CableReady::Stream\",\"identifier\":\"%s\"}", "fake_id") 187 188 res, err := subject.Subscribe("42", env, "name=jack", channel) 189 190 require.NoError(t, err) 191 require.NotNil(t, res) 192 require.Equal(t, common.FAILURE, res.Status) 193 assert.Equal(t, []string{common.RejectionMessage(channel)}, res.Transmissions) 194 }) 195 196 t.Run("Subscribe (failure + not a string)", func(t *testing.T) { 197 signed := "WyJjaGF0LzIwMjMiLDE2ODUwMjQwMTdd--5b6661024d4c463c4936cd1542bc9a7672dd8039ac407d0b6c901697190e8aeb" 198 channel := fmt.Sprintf("{\"channel\":\"CableReady::Stream\",\"identifier\":\"%s\"}", signed) 199 200 res, err := subject.Subscribe("42", env, "name=jack", channel) 201 202 require.NoError(t, err) 203 require.NotNil(t, res) 204 require.Equal(t, common.FAILURE, res.Status) 205 assert.Equal(t, []string{common.RejectionMessage(channel)}, res.Transmissions) 206 }) 207 208 t.Run("Unsubscribe", func(t *testing.T) { 209 channel := fmt.Sprintf("{\"channel\":\"CableReady::Stream\",\"identifier\":\"%s\"}", stream) 210 211 res, err := subject.Unsubscribe("42", env, "name=jack", channel) 212 213 require.NoError(t, err) 214 require.NotNil(t, res) 215 require.Equal(t, common.SUCCESS, res.Status) 216 assert.Equal(t, []string{}, res.Transmissions) 217 assert.Equal(t, []string{}, res.Streams) 218 assert.Equal(t, true, res.StopAllStreams) 219 }) 220 }