spec/lib/release_tools/release_managers/slack_client_spec.rb (157 lines of code) (raw):
# frozen_string_literal: true
require 'spec_helper'
describe ReleaseTools::ReleaseManagers::SlackClient do
let(:slack_url) { described_class::SLACK_URL }
let(:slack_token) { 'my-secret-token' }
subject(:client) do
ClimateControl.modify(SLACK_APP_ADMIN_TOKEN: slack_token) do
described_class.new
end
end
describe 'initialize' do
context 'when SLACK_APP_ADMIN_TOKEN is not set' do
let(:slack_token) { nil }
it 'raises an error' do
expect { client }.to raise_error('Missing environment variable `SLACK_APP_ADMIN_TOKEN`')
end
end
it { expect { client }.not_to raise_error }
end
describe '#sync_membership' do
let(:url) { "https://slack.com/api/usergroups.users.update" }
it 'sends a POST request with IDS and the provided token' do
user_ids = %w[UID1 UID2 UID3]
request = stub_request(:post, url)
.with(
headers: { Authorization: "Bearer #{slack_token}", 'Content-Type': 'application/x-www-form-urlencoded' },
body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS, users: user_ids.join(','))
).to_return(body: { ok: true }.to_json)
client.sync_membership(user_ids)
expect(request).to have_been_requested
end
context 'when the request is unauthorized' do
it 'keeps track of the error' do
request =
stub_request(:post, url)
.with(
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS, users: 'UID1')
).to_return(status: 401)
client.sync_membership(%w[UID1])
expect(request).to have_been_requested
expect(subject.sync_errors).to contain_exactly(an_instance_of(ReleaseTools::ReleaseManagers::Client::UnauthorizedError))
end
end
context 'when the request is forbidden' do
it 'keeps track of the error' do
request =
stub_request(:post, url)
.with(body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS, users: 'UID1'))
.to_return(status: 403)
client.sync_membership(%w[UID1])
expect(request).to have_been_requested
expect(subject.sync_errors).to contain_exactly(an_instance_of(ReleaseTools::ReleaseManagers::Client::UnauthorizedError))
end
end
context "with a Bad request (or any other failure)" do
it 'keeps track of the error' do
request =
stub_request(:post, url)
.with(body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS, users: 'UID1'))
.to_return(status: 400)
client.sync_membership(%w[UID1])
expect(request).to have_been_requested
expect(subject.sync_errors).to contain_exactly(an_instance_of(ReleaseTools::ReleaseManagers::Client::SyncError))
end
end
context 'when slack returns a failure' do
it 'keeps track of the error' do
user_ids = %w[NOTEXISTING]
request = stub_request(:post, url)
.with(
headers: { Authorization: "Bearer #{slack_token}" },
body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS, users: 'NOTEXISTING')
).to_return(status: 200, body: { ok: false, error: 'invalid_users' }.to_json)
client.sync_membership(user_ids)
expect(request).to have_been_requested
expect(subject.sync_errors).to contain_exactly(an_instance_of(ReleaseTools::ReleaseManagers::Client::SyncError))
expect(subject.sync_errors.first.message).to eq('invalid_users')
end
end
end
describe '#members' do
let(:url) { "#{slack_url}/usergroups.users.list" }
it 'sends a GET request with the provided token' do
user_ids = %w[UID1 UID2 UID3]
request = stub_request(:post, url)
.with(headers: { Authorization: "Bearer #{slack_token}" }, body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS))
.to_return(body: { ok: true, users: user_ids }.to_json)
expect(client.members).to eq(user_ids)
expect(request).to have_been_requested
end
context 'when the request is unauthorized' do
it 'keeps track of the error' do
request = stub_request(:post, url)
.with(body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS))
.to_return(status: 401)
expect { client.members }.to raise_error(ReleaseTools::ReleaseManagers::Client::UnauthorizedError)
expect(request).to have_been_requested
end
end
context 'when the request is forbidden' do
it 'keeps track of the error' do
request = stub_request(:post, url)
.with(body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS))
.to_return(status: 403)
expect { client.members }.to raise_error(ReleaseTools::ReleaseManagers::Client::UnauthorizedError, 'Invalid token')
expect(request).to have_been_requested
end
end
context "with a Bad request (or any other failure)" do
it 'keeps track of the error' do
request = stub_request(:post, url).to_return(status: 400)
expect { client.members }.to raise_error(ReleaseTools::ReleaseManagers::Client::SyncError, 'Bad Request')
expect(request).to have_been_requested
end
end
end
describe '#join' do
let(:user_ids) { %w[UID1 UID2 UID3] }
let!(:members_request) do
stub_request(:post, "#{slack_url}/usergroups.users.list")
.with(body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS))
.to_return(body: { ok: true, users: user_ids }.to_json)
end
it 'adds a new user to the group' do
new_user = 'UID4'
expect(subject).to receive(:sync_membership).with(user_ids + [new_user])
client.join(new_user)
expect(members_request).to have_been_requested
end
it 'does not add users already belonging to the group' do
new_user = user_ids[0]
expect(subject).not_to receive(:sync_membership)
client.join(new_user)
expect(members_request).to have_been_requested
end
end
describe '#leave' do
let(:user_ids) { %w[UID1 UID2 UID3] }
let!(:members_request) do
stub_request(:post, "#{slack_url}/usergroups.users.list")
.with(body: hash_including(usergroup: ReleaseTools::Slack::RELEASE_MANAGERS))
.to_return(body: { ok: true, users: user_ids }.to_json)
end
it 'removes a user from the group' do
new_user = user_ids[0]
expect(subject).to receive(:sync_membership).with(user_ids - [new_user])
client.leave(new_user)
expect(members_request).to have_been_requested
end
it 'does not remove users not belonging to the group' do
new_user = 'UID4'
expect(subject).not_to receive(:sync_membership)
client.leave(new_user)
expect(members_request).to have_been_requested
end
end
end