Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
e9b95ce
feat: add 16 user integration tests for chat test parity
mogita Feb 25, 2026
1e450b7
feat: add 27 message integration tests for chat test parity
mogita Feb 25, 2026
604b974
feat: add 2 polls integration tests for chat test parity
mogita Feb 25, 2026
9f72360
feat: add 19 misc chat integration tests for chat test parity
mogita Feb 25, 2026
14f5b98
feat: add 3 moderation integration tests for chat test parity
mogita Feb 25, 2026
b2eed21
feat: add 18 video integration tests for SDK test parity
mogita Feb 25, 2026
c84e34a
Merge branch 'master' into cha-1578_openapi-refactor-codegen
mogita Feb 25, 2026
ce5af33
test: blocklist deletion cleanup
mogita Feb 25, 2026
f50f44d
test: minor tweaks
mogita Feb 25, 2026
0be572d
test: case fixes and performance improvement
mogita Feb 25, 2026
22d9cf0
test: improve loop time
mogita Feb 25, 2026
b9da3ed
style: fix format issues
mogita Feb 25, 2026
3c75941
test: re-get to verify updated channel
mogita Feb 25, 2026
4bbb03e
style: fix code formatting
mogita Feb 25, 2026
8d8e7d3
test: fine tuning for api limits
mogita Feb 25, 2026
ef50f1c
test: fine tuning
mogita Feb 25, 2026
4f030f9
test: fine tuning
mogita Feb 25, 2026
78cbd34
test: fine tuning
mogita Feb 26, 2026
e6b67df
test: fine tuning for rate limiting
mogita Feb 26, 2026
d0110d7
test: fine tuning
mogita Feb 26, 2026
88605ce
test: fine tuning
mogita Feb 26, 2026
49f166f
feat: update by openapi refactor
mogita Feb 26, 2026
5299865
test: add test for user group
mogita Feb 26, 2026
8465a9c
style: fix code formatting
mogita Feb 26, 2026
c8087e0
test: fine tuning
mogita Feb 26, 2026
f2891a2
style: fix code formatting
mogita Feb 26, 2026
669ad55
test: fine tuning
mogita Feb 26, 2026
12172d3
test: fine tuning
mogita Feb 26, 2026
06c757e
style: fix code formatting
mogita Feb 26, 2026
48bf3d7
test: fine tuning
mogita Feb 27, 2026
bed63c9
ci: add pre-release workflow and update changelog
mogita Mar 2, 2026
9ae47b9
feat: update by openapi refactor
mogita Mar 4, 2026
f0b239b
feat: update by openapi refactor
mogita Mar 4, 2026
d56266c
test: unique group ids
mogita Mar 4, 2026
4984ed9
test: unique group ids
mogita Mar 4, 2026
059b9e7
feat: update by openapi refactor
mogita Mar 4, 2026
f98750f
feat: update by openapi refactor
mogita Mar 4, 2026
214e015
test: chat and video clients
mogita Mar 5, 2026
fbd42e0
style: fix code formatting
mogita Mar 5, 2026
537765c
ci: rename non-video step
mogita Mar 5, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
817 changes: 817 additions & 0 deletions spec/integration/chat_channel_integration_spec.rb

Large diffs are not rendered by default.

604 changes: 604 additions & 0 deletions spec/integration/chat_message_integration_spec.rb

Large diffs are not rendered by default.

641 changes: 641 additions & 0 deletions spec/integration/chat_misc_integration_spec.rb

Large diffs are not rendered by default.

220 changes: 220 additions & 0 deletions spec/integration/chat_moderation_integration_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,220 @@
# frozen_string_literal: true

require 'rspec'
require 'securerandom'
require 'json'
require_relative 'chat_test_helpers'

RSpec.describe 'Chat Moderation Integration', type: :integration do
include ChatTestHelpers

before(:all) do
init_chat_client
@shared_user_ids, _resp = create_test_users(4)
@user1 = @shared_user_ids[0]
@user2 = @shared_user_ids[1]
@user3 = @shared_user_ids[2]
@user4 = @shared_user_ids[3]
end

after(:all) do
cleanup_chat_resources
end

# ---------------------------------------------------------------------------
# Ban / Unban User
# ---------------------------------------------------------------------------

describe 'BanUnbanUser' do
it 'bans a user from a channel, verifies, and unbans' do
_type, channel_id, _resp = create_test_channel_with_members(@user1, [@user1, @user2])
cid = "messaging:#{channel_id}"

# Ban user in channel
@client.moderation.ban(
GetStream::Generated::Models::BanRequest.new(
target_user_id: @user2,
banned_by_id: @user1,
channel_cid: cid,
reason: 'moderation test ban',
timeout: 60
)
)

# Verify via query banned users
resp = @client.make_request(:get, '/api/v2/chat/query_banned_users', query_params: {
'payload' => JSON.generate({
filter_conditions: { 'channel_cid' => { '$eq' => cid } }
})
})
bans = resp.bans || []
expect(bans.length).to be >= 1

banned_user_ids = bans.map do |b|
h = b.is_a?(Hash) ? b : b.to_h
target = h['user'] || {}
target = target.is_a?(Hash) ? target : target.to_h
target['id']
end
expect(banned_user_ids).to include(@user2)

# Unban user
@client.moderation.unban(
GetStream::Generated::Models::UnbanRequest.new,
@user2,
cid
)

# Verify ban is removed
resp2 = @client.make_request(:get, '/api/v2/chat/query_banned_users', query_params: {
'payload' => JSON.generate({
filter_conditions: { 'channel_cid' => { '$eq' => cid } }
})
})
bans2 = resp2.bans || []
banned_ids_after = bans2.map do |b|
h = b.is_a?(Hash) ? b : b.to_h
target = h['user'] || {}
target = target.is_a?(Hash) ? target : target.to_h
target['id']
end
expect(banned_ids_after).not_to include(@user2)
end

it 'bans a user app-wide, verifies, and unbans' do
# Ban user app-wide (no channel_cid)
@client.moderation.ban(
GetStream::Generated::Models::BanRequest.new(
target_user_id: @user3,
banned_by_id: @user1,
reason: 'app-wide moderation test ban',
timeout: 60
)
)

# Verify via query banned users (app-level)
resp = @client.make_request(:get, '/api/v2/chat/query_banned_users', query_params: {
'payload' => JSON.generate({
filter_conditions: { 'user_id' => { '$eq' => @user3 } }
})
})
bans = resp.bans || []
expect(bans.length).to be >= 1

# Unban user app-wide
@client.moderation.unban(
GetStream::Generated::Models::UnbanRequest.new,
@user3
)

# Verify ban is removed
resp2 = @client.make_request(:get, '/api/v2/chat/query_banned_users', query_params: {
'payload' => JSON.generate({
filter_conditions: { 'user_id' => { '$eq' => @user3 } }
})
})
bans2 = resp2.bans || []
expect(bans2.length).to eq(0), "App-wide ban should be removed after unban"
end
end

# ---------------------------------------------------------------------------
# Mute / Unmute User
# ---------------------------------------------------------------------------

describe 'MuteUnmuteUser' do
it 'mutes a user, verifies via query, and unmutes' do
# Mute user
mute_resp = @client.moderation.mute(
GetStream::Generated::Models::MuteRequest.new(
target_ids: [@user4],
user_id: @user1
)
)
expect(mute_resp.mutes).not_to be_nil
expect(mute_resp.mutes.length).to be >= 1

mute_h = mute_resp.mutes[0].is_a?(Hash) ? mute_resp.mutes[0] : mute_resp.mutes[0].to_h
target = mute_h['target'] || {}
target = target.is_a?(Hash) ? target : target.to_h
expect(target['id']).to eq(@user4)

# Verify via QueryUsers that muter has mutes
q_resp = @client.common.query_users(JSON.generate({
filter_conditions: { 'id' => { '$eq' => @user1 } }
}))
expect(q_resp.users).not_to be_nil
expect(q_resp.users.length).to be >= 1
user_h = q_resp.users[0].is_a?(Hash) ? q_resp.users[0] : q_resp.users[0].to_h
expect(user_h['mutes']).not_to be_nil
expect(user_h['mutes'].length).to be >= 1

muted_ids = user_h['mutes'].map do |m|
t = m.is_a?(Hash) ? m : m.to_h
tgt = t['target'] || {}
tgt = tgt.is_a?(Hash) ? tgt : tgt.to_h
tgt['id']
end
expect(muted_ids).to include(@user4)

# Unmute user
@client.moderation.unmute(
GetStream::Generated::Models::UnmuteRequest.new(
target_ids: [@user4],
user_id: @user1
)
)

# Verify mute is removed
q_resp2 = @client.common.query_users(JSON.generate({
filter_conditions: { 'id' => { '$eq' => @user1 } }
}))
user_h2 = q_resp2.users[0].is_a?(Hash) ? q_resp2.users[0] : q_resp2.users[0].to_h
mutes_after = user_h2['mutes'] || []
muted_ids_after = mutes_after.map do |m|
t = m.is_a?(Hash) ? m : m.to_h
tgt = t['target'] || {}
tgt = tgt.is_a?(Hash) ? tgt : tgt.to_h
tgt['id']
end
expect(muted_ids_after).not_to include(@user4)
end
end

# ---------------------------------------------------------------------------
# Flag Message and User
# ---------------------------------------------------------------------------

describe 'FlagMessageAndUser' do
it 'flags a message and verifies response' do
_type, channel_id, _resp = create_test_channel_with_members(@user1, [@user1, @user2])
msg_id = send_test_message('messaging', channel_id, @user1, "Flaggable message #{SecureRandom.hex(4)}")

# Flag message
flag_resp = @client.moderation.flag(
GetStream::Generated::Models::FlagRequest.new(
entity_type: 'stream:chat:v1:message',
entity_id: msg_id,
entity_creator_id: @user1,
reason: 'inappropriate content',
user_id: @user2
)
)
expect(flag_resp).not_to be_nil
end

it 'flags a user and verifies response' do
# Flag user
flag_resp = @client.moderation.flag(
GetStream::Generated::Models::FlagRequest.new(
entity_type: 'stream:user',
entity_id: @user3,
entity_creator_id: @user3,
reason: 'spam behavior',
user_id: @user1
)
)
expect(flag_resp).not_to be_nil
end
end
end
169 changes: 169 additions & 0 deletions spec/integration/chat_polls_integration_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
# frozen_string_literal: true

require 'rspec'
require 'securerandom'
require 'json'
require_relative 'chat_test_helpers'

RSpec.describe 'Chat Polls Integration', type: :integration do
include ChatTestHelpers

before(:all) do
init_chat_client
@shared_user_ids, _resp = create_test_users(2)
@user1 = @shared_user_ids[0]
@user2 = @shared_user_ids[1]
@created_poll_ids = []
end

after(:all) do
# Delete polls before channels/users (polls reference users)
@created_poll_ids&.each do |poll_id|
@client.common.delete_poll(poll_id, @user1)
rescue StandardError => e
puts "Warning: Failed to delete poll #{poll_id}: #{e.message}"
end

cleanup_chat_resources
end

# ---------------------------------------------------------------------------
# Poll API wrappers
# ---------------------------------------------------------------------------

def create_poll(name, user_id, options: [], enforce_unique_vote: nil, description: nil)
poll_options = options.map do |text|
GetStream::Generated::Models::PollOptionInput.new(text: text)
end

req = GetStream::Generated::Models::CreatePollRequest.new(
name: name,
user_id: user_id,
options: poll_options,
enforce_unique_vote: enforce_unique_vote,
description: description
)

resp = @client.common.create_poll(req)
poll_id = resp.poll.id
@created_poll_ids << poll_id
resp
end

def get_poll(poll_id)
@client.common.get_poll(poll_id)
end

def query_polls(filter, user_id)
req = GetStream::Generated::Models::QueryPollsRequest.new(filter: filter)
@client.common.query_polls(req, user_id)
end

def delete_poll(poll_id, user_id)
@client.common.delete_poll(poll_id, user_id)
end

def cast_poll_vote(message_id, poll_id, user_id, option_id)
body = {
user_id: user_id,
vote: { option_id: option_id }
}
@client.make_request(
:post,
"/api/v2/chat/messages/#{message_id}/polls/#{poll_id}/vote",
body: body
)
end

# ---------------------------------------------------------------------------
# Tests
# ---------------------------------------------------------------------------

describe 'CreateAndQueryPoll' do
it 'creates a poll with options, gets it, and queries it' do
poll_name = "Favorite color? #{SecureRandom.hex(4)}"

# Create poll with options
create_resp = create_poll(
poll_name,
@user1,
options: %w[Red Blue Green],
enforce_unique_vote: true,
description: 'Pick your favorite color'
)
expect(create_resp.poll).not_to be_nil
poll_id = create_resp.poll.id
expect(poll_id).not_to be_nil
expect(create_resp.poll.name).to eq(poll_name)
expect(create_resp.poll.enforce_unique_vote).to eq(true)

poll_h = create_resp.poll.to_h
expect(poll_h['options'].length).to eq(3)

# Get poll by ID
get_resp = get_poll(poll_id)
expect(get_resp.poll).not_to be_nil
expect(get_resp.poll.id).to eq(poll_id)
expect(get_resp.poll.name).to eq(poll_name)

# Query polls with filter
query_resp = query_polls({ 'id' => poll_id }, @user1)
expect(query_resp.polls).not_to be_nil
expect(query_resp.polls.length).to be >= 1

found = query_resp.polls.any? do |p|
h = p.is_a?(Hash) ? p : p.to_h
h['id'] == poll_id
end
expect(found).to be true
rescue StandardError => e
skip('Polls not enabled for this app') if e.message.include?('Polls') || e.message.include?('polls')
raise
end
end

describe 'CastPollVote' do
it 'creates a poll, attaches to message, casts vote, and verifies' do
# Create poll
poll_name = "Vote test #{SecureRandom.hex(4)}"
create_resp = create_poll(
poll_name,
@user1,
options: %w[Yes No],
enforce_unique_vote: true
)
poll_id = create_resp.poll.id
poll_h = create_resp.poll.to_h
option_id = poll_h['options'][0]['id']
expect(option_id).not_to be_nil

# Create channel with both users as members
_type, channel_id, _resp = create_test_channel_with_members(@user1, [@user1, @user2])

# Send message with poll attached
body = {
message: {
text: 'Please vote!',
user_id: @user1,
poll_id: poll_id
}
}
msg_resp = send_message('messaging', channel_id, body)
msg_id = msg_resp.message.id
expect(msg_id).not_to be_nil

# Cast a vote as user2
vote_resp = cast_poll_vote(msg_id, poll_id, @user2, option_id)
expect(vote_resp.vote).not_to be_nil
vote_h = vote_resp.vote.to_h
expect(vote_h['option_id']).to eq(option_id)

# Verify poll has votes
get_resp = get_poll(poll_id)
expect(get_resp.poll.vote_count).to eq(1)
rescue StandardError => e
skip('Polls not enabled for this app') if e.message.include?('Polls') || e.message.include?('polls')
raise
end
end
end
Loading
Loading