Commit fc772299 authored by Siddharth Asthana's avatar Siddharth Asthana Committed by Alex Kalderimis

Force user to re-enter integration password

Ensure that model validation fails when the password is reset
due to other related model changes.

Changelog: changed
EE: true
parent 6be45816
...@@ -18,7 +18,7 @@ module Integrations ...@@ -18,7 +18,7 @@ module Integrations
attr_accessor :response attr_accessor :response
before_update :reset_password before_validation :reset_password
def reset_password def reset_password
if bamboo_url_changed? && !password_touched? if bamboo_url_changed? && !password_touched?
......
...@@ -8,7 +8,7 @@ module Integrations ...@@ -8,7 +8,7 @@ module Integrations
prop_accessor :jenkins_url, :project_name, :username, :password prop_accessor :jenkins_url, :project_name, :username, :password
before_update :reset_password before_validation :reset_password
validates :jenkins_url, presence: true, addressable_url: true, if: :activated? validates :jenkins_url, presence: true, addressable_url: true, if: :activated?
validates :project_name, presence: true, if: :activated? validates :project_name, presence: true, if: :activated?
......
...@@ -33,7 +33,7 @@ module Integrations ...@@ -33,7 +33,7 @@ module Integrations
data_field :username, :password, :url, :api_url, :jira_issue_transition_automatic, :jira_issue_transition_id, :project_key, :issues_enabled, data_field :username, :password, :url, :api_url, :jira_issue_transition_automatic, :jira_issue_transition_id, :project_key, :issues_enabled,
:vulnerabilities_enabled, :vulnerabilities_issuetype :vulnerabilities_enabled, :vulnerabilities_issuetype
before_update :reset_password before_validation :reset_password
after_commit :update_deployment_type, on: [:create, :update], if: :update_deployment_type? after_commit :update_deployment_type, on: [:create, :update], if: :update_deployment_type?
enum comment_detail: { enum comment_detail: {
...@@ -65,7 +65,10 @@ module Integrations ...@@ -65,7 +65,10 @@ module Integrations
end end
def reset_password def reset_password
data_fields.password = nil if reset_password? return unless reset_password?
data_fields.password = nil
properties.delete('password') if properties
end end
def set_default_data def set_default_data
......
...@@ -18,7 +18,7 @@ module Integrations ...@@ -18,7 +18,7 @@ module Integrations
attr_accessor :response attr_accessor :response
before_update :reset_password before_validation :reset_password
class << self class << self
def to_param def to_param
......
...@@ -131,7 +131,7 @@ RSpec.describe Integrations::JiraSerializers::IssueDetailEntity do ...@@ -131,7 +131,7 @@ RSpec.describe Integrations::JiraSerializers::IssueDetailEntity do
context 'with only url' do context 'with only url' do
before do before do
stub_jira_integration_test stub_jira_integration_test
jira_integration.update!(api_url: nil) jira_integration.update!(api_url: nil, password: 'password')
end end
it 'returns URLs with the web url' do it 'returns URLs with the web url' do
......
...@@ -95,7 +95,7 @@ RSpec.describe Integrations::JiraSerializers::IssueEntity do ...@@ -95,7 +95,7 @@ RSpec.describe Integrations::JiraSerializers::IssueEntity do
context 'with only url' do context 'with only url' do
before do before do
stub_jira_integration_test stub_jira_integration_test
jira_integration.update!(api_url: nil) jira_integration.update!(api_url: nil, password: 'password')
end end
it 'returns URLs with the web url' do it 'returns URLs with the web url' do
......
...@@ -43,15 +43,15 @@ RSpec.describe Admin::IntegrationsController do ...@@ -43,15 +43,15 @@ RSpec.describe Admin::IntegrationsController do
stub_jira_integration_test stub_jira_integration_test
allow(PropagateIntegrationWorker).to receive(:perform_async) allow(PropagateIntegrationWorker).to receive(:perform_async)
put :update, params: { id: integration.class.to_param, service: { url: url } } put :update, params: { id: integration.class.to_param, service: params }
end end
context 'valid params' do context 'valid params' do
let(:url) { 'https://jira.gitlab-example.com' } let(:params) { { url: 'https://jira.gitlab-example.com', password: 'password' } }
it 'updates the integration' do it 'updates the integration' do
expect(response).to have_gitlab_http_status(:found) expect(response).to have_gitlab_http_status(:found)
expect(integration.reload.url).to eq(url) expect(integration.reload).to have_attributes(params)
end end
it 'calls to PropagateIntegrationWorker' do it 'calls to PropagateIntegrationWorker' do
...@@ -60,12 +60,12 @@ RSpec.describe Admin::IntegrationsController do ...@@ -60,12 +60,12 @@ RSpec.describe Admin::IntegrationsController do
end end
context 'invalid params' do context 'invalid params' do
let(:url) { 'invalid' } let(:params) { { url: 'invalid', password: 'password' } }
it 'does not update the integration' do it 'does not update the integration' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:edit) expect(response).to render_template(:edit)
expect(integration.reload.url).not_to eq(url) expect(integration.reload).not_to have_attributes(params)
end end
it 'does not call to PropagateIntegrationWorker' do it 'does not call to PropagateIntegrationWorker' do
......
...@@ -69,25 +69,25 @@ RSpec.describe Groups::Settings::IntegrationsController do ...@@ -69,25 +69,25 @@ RSpec.describe Groups::Settings::IntegrationsController do
group.add_owner(user) group.add_owner(user)
stub_jira_integration_test stub_jira_integration_test
put :update, params: { group_id: group, id: integration.class.to_param, service: { url: url } } put :update, params: { group_id: group, id: integration.class.to_param, service: params }
end end
context 'valid params' do context 'valid params' do
let(:url) { 'https://jira.gitlab-example.com' } let(:params) { { url: 'https://jira.gitlab-example.com', password: 'password' } }
it 'updates the integration' do it 'updates the integration' do
expect(response).to have_gitlab_http_status(:found) expect(response).to have_gitlab_http_status(:found)
expect(integration.reload.url).to eq(url) expect(integration.reload).to have_attributes(params)
end end
end end
context 'invalid params' do context 'invalid params' do
let(:url) { 'invalid' } let(:params) { { url: 'invalid', password: 'password' } }
it 'does not update the integration' do it 'does not update the integration' do
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to render_template(:edit) expect(response).to render_template(:edit)
expect(integration.reload.url).not_to eq(url) expect(integration.reload).not_to have_attributes(params)
end end
end end
end end
......
...@@ -239,22 +239,39 @@ RSpec.describe Projects::ServicesController do ...@@ -239,22 +239,39 @@ RSpec.describe Projects::ServicesController do
end end
context 'when update succeeds' do context 'when update succeeds' do
let(:integration_params) { { url: 'http://example.com' } } let(:integration_params) { { url: 'http://example.com', password: 'password' } }
it 'returns JSON response with no errors' do it 'returns success response' do
expect(response).to be_successful expect(response).to be_successful
expect(json_response).to include('active' => true, 'errors' => {}) expect(json_response).to include(
'active' => true,
'errors' => {}
)
end
end
context 'when update fails with missing password' do
let(:integration_params) { { url: 'http://example.com' } }
it 'returns JSON response errors' do
expect(response).not_to be_successful
expect(json_response).to include(
'active' => true,
'errors' => {
'password' => ["can't be blank"]
}
)
end end
end end
context 'when update fails' do context 'when update fails with invalid URL' do
let(:integration_params) { { url: '' } } let(:integration_params) { { url: '', password: 'password' } }
it 'returns JSON response with errors' do it 'returns JSON response with errors' do
expect(response).to have_gitlab_http_status(:unprocessable_entity) expect(response).to have_gitlab_http_status(:unprocessable_entity)
expect(json_response).to include( expect(json_response).to include(
'active' => true, 'active' => true,
'errors' => { 'url' => ['must be a valid URL', %(can't be blank)] } 'errors' => { 'url' => ['must be a valid URL', "can't be blank"] }
) )
end end
end end
......
...@@ -53,7 +53,7 @@ FactoryBot.define do ...@@ -53,7 +53,7 @@ FactoryBot.define do
transient do transient do
create_data { true } create_data { true }
url { 'https://jira.example.com' } url { 'https://jira.example.com' }
api_url { nil } api_url { '' }
username { 'jira_username' } username { 'jira_username' }
password { 'jira_password' } password { 'jira_password' }
jira_issue_transition_automatic { false } jira_issue_transition_automatic { false }
......
...@@ -2592,7 +2592,7 @@ TeamcityService ...@@ -2592,7 +2592,7 @@ TeamcityService
should not validate that :username cannot be empty/falsy should not validate that :username cannot be empty/falsy
should not validate that :password cannot be empty/falsy should not validate that :password cannot be empty/falsy
Callbacks Callbacks
before_update :reset_password before_validation :reset_password
saves password if new url is set together with password when no password was previously set saves password if new url is set together with password when no password was previously set
when a password was previously set when a password was previously set
resets password if url changed resets password if url changed
......
...@@ -12,6 +12,7 @@ RSpec.describe Integrations::Bamboo, :use_clean_rails_memory_store_caching do ...@@ -12,6 +12,7 @@ RSpec.describe Integrations::Bamboo, :use_clean_rails_memory_store_caching do
subject(:integration) do subject(:integration) do
described_class.create!( described_class.create!(
active: true,
project: project, project: project,
properties: { properties: {
bamboo_url: bamboo_url, bamboo_url: bamboo_url,
...@@ -74,27 +75,27 @@ RSpec.describe Integrations::Bamboo, :use_clean_rails_memory_store_caching do ...@@ -74,27 +75,27 @@ RSpec.describe Integrations::Bamboo, :use_clean_rails_memory_store_caching do
end end
describe 'Callbacks' do describe 'Callbacks' do
describe 'before_update :reset_password' do describe 'before_validation :reset_password' do
context 'when a password was previously set' do context 'when a password was previously set' do
it 'resets password if url changed' do it 'resets password if url changed' do
integration.bamboo_url = 'http://gitlab1.com' integration.bamboo_url = 'http://gitlab1.com'
integration.save!
expect(integration).not_to be_valid
expect(integration.password).to be_nil expect(integration.password).to be_nil
end end
it 'does not reset password if username changed' do it 'does not reset password if username changed' do
integration.username = 'some_name' integration.username = 'some_name'
integration.save!
expect(integration).to be_valid
expect(integration.password).to eq('password') expect(integration.password).to eq('password')
end end
it "does not reset password if new url is set together with password, even if it's the same password" do it "does not reset password if new url is set together with password, even if it's the same password" do
integration.bamboo_url = 'http://gitlab_edited.com' integration.bamboo_url = 'http://gitlab_edited.com'
integration.password = 'password' integration.password = 'password'
integration.save!
expect(integration).to be_valid
expect(integration.password).to eq('password') expect(integration.password).to eq('password')
expect(integration.bamboo_url).to eq('http://gitlab_edited.com') expect(integration.bamboo_url).to eq('http://gitlab_edited.com')
end end
...@@ -107,8 +108,10 @@ RSpec.describe Integrations::Bamboo, :use_clean_rails_memory_store_caching do ...@@ -107,8 +108,10 @@ RSpec.describe Integrations::Bamboo, :use_clean_rails_memory_store_caching do
integration.password = 'password' integration.password = 'password'
integration.save! integration.save!
expect(integration.password).to eq('password') expect(integration.reload).to have_attributes(
expect(integration.bamboo_url).to eq('http://gitlab_edited.com') bamboo_url: 'http://gitlab_edited.com',
password: 'password'
)
end end
end end
end end
......
...@@ -200,21 +200,21 @@ RSpec.describe Integrations::Jenkins do ...@@ -200,21 +200,21 @@ RSpec.describe Integrations::Jenkins do
it 'resets password if url changed' do it 'resets password if url changed' do
jenkins_integration.jenkins_url = 'http://jenkins-edited.example.com/' jenkins_integration.jenkins_url = 'http://jenkins-edited.example.com/'
jenkins_integration.save! jenkins_integration.valid?
expect(jenkins_integration.password).to be_nil expect(jenkins_integration.password).to be_nil
end end
it 'resets password if username is blank' do it 'resets password if username is blank' do
jenkins_integration.username = '' jenkins_integration.username = ''
jenkins_integration.save! jenkins_integration.valid?
expect(jenkins_integration.password).to be_nil expect(jenkins_integration.password).to be_nil
end end
it 'does not reset password if username changed' do it 'does not reset password if username changed' do
jenkins_integration.username = 'some_name' jenkins_integration.username = 'some_name'
jenkins_integration.save! jenkins_integration.valid?
expect(jenkins_integration.password).to eq('password') expect(jenkins_integration.password).to eq('password')
end end
...@@ -222,7 +222,7 @@ RSpec.describe Integrations::Jenkins do ...@@ -222,7 +222,7 @@ RSpec.describe Integrations::Jenkins do
it 'does not reset password if new url is set together with password, even if it\'s the same password' do it 'does not reset password if new url is set together with password, even if it\'s the same password' do
jenkins_integration.jenkins_url = 'http://jenkins_edited.example.com/' jenkins_integration.jenkins_url = 'http://jenkins_edited.example.com/'
jenkins_integration.password = 'password' jenkins_integration.password = 'password'
jenkins_integration.save! jenkins_integration.valid?
expect(jenkins_integration.password).to eq('password') expect(jenkins_integration.password).to eq('password')
expect(jenkins_integration.jenkins_url).to eq('http://jenkins_edited.example.com/') expect(jenkins_integration.jenkins_url).to eq('http://jenkins_edited.example.com/')
...@@ -231,7 +231,7 @@ RSpec.describe Integrations::Jenkins do ...@@ -231,7 +231,7 @@ RSpec.describe Integrations::Jenkins do
it 'resets password if url changed, even if setter called multiple times' do it 'resets password if url changed, even if setter called multiple times' do
jenkins_integration.jenkins_url = 'http://jenkins1.example.com/' jenkins_integration.jenkins_url = 'http://jenkins1.example.com/'
jenkins_integration.jenkins_url = 'http://jenkins1.example.com/' jenkins_integration.jenkins_url = 'http://jenkins1.example.com/'
jenkins_integration.save! jenkins_integration.valid?
expect(jenkins_integration.password).to be_nil expect(jenkins_integration.password).to be_nil
end end
...@@ -253,8 +253,10 @@ RSpec.describe Integrations::Jenkins do ...@@ -253,8 +253,10 @@ RSpec.describe Integrations::Jenkins do
jenkins_integration.password = 'password' jenkins_integration.password = 'password'
jenkins_integration.save! jenkins_integration.save!
expect(jenkins_integration.password).to eq('password') expect(jenkins_integration.reload).to have_attributes(
expect(jenkins_integration.jenkins_url).to eq('http://jenkins_edited.example.com/') jenkins_url: 'http://jenkins_edited.example.com/',
password: 'password'
)
end end
end end
end end
......
...@@ -280,7 +280,7 @@ RSpec.describe Integrations::Jira do ...@@ -280,7 +280,7 @@ RSpec.describe Integrations::Jira do
expect(integration.jira_tracker_data.deployment_server?).to be_truthy expect(integration.jira_tracker_data.deployment_server?).to be_truthy
integration.update!(api_url: 'http://another.url') integration.update!(api_url: 'http://another.url', password: password)
integration.jira_tracker_data.reload integration.jira_tracker_data.reload
expect(integration.jira_tracker_data.deployment_cloud?).to be_truthy expect(integration.jira_tracker_data.deployment_cloud?).to be_truthy
...@@ -301,13 +301,13 @@ RSpec.describe Integrations::Jira do ...@@ -301,13 +301,13 @@ RSpec.describe Integrations::Jira do
end end
it 'calls serverInfo for url' do it 'calls serverInfo for url' do
integration.update!(url: 'http://first.url') integration.update!(url: 'http://first.url', password: password)
expect(WebMock).to have_requested(:get, /serverInfo/) expect(WebMock).to have_requested(:get, /serverInfo/)
end end
it 'calls serverInfo for api_url' do it 'calls serverInfo for api_url' do
integration.update!(api_url: 'http://another.url') integration.update!(api_url: 'http://another.url', password: password)
expect(WebMock).to have_requested(:get, /serverInfo/) expect(WebMock).to have_requested(:get, /serverInfo/)
end end
...@@ -358,33 +358,33 @@ RSpec.describe Integrations::Jira do ...@@ -358,33 +358,33 @@ RSpec.describe Integrations::Jira do
it 'resets password if url changed' do it 'resets password if url changed' do
integration integration
integration.url = 'http://jira_edited.example.com' integration.url = 'http://jira_edited.example.com'
integration.save!
expect(integration.reload.url).to eq('http://jira_edited.example.com') expect(integration).not_to be_valid
expect(integration.url).to eq('http://jira_edited.example.com')
expect(integration.password).to be_nil expect(integration.password).to be_nil
end end
it 'does not reset password if url "changed" to the same url as before' do it 'does not reset password if url "changed" to the same url as before' do
integration.url = 'http://jira.example.com' integration.url = 'http://jira.example.com'
integration.save!
expect(integration.reload.url).to eq('http://jira.example.com') expect(integration).to be_valid
expect(integration.url).to eq('http://jira.example.com')
expect(integration.password).not_to be_nil expect(integration.password).not_to be_nil
end end
it 'resets password if url not changed but api url added' do it 'resets password if url not changed but api url added' do
integration.api_url = 'http://jira_edited.example.com/rest/api/2' integration.api_url = 'http://jira_edited.example.com/rest/api/2'
integration.save!
expect(integration.reload.api_url).to eq('http://jira_edited.example.com/rest/api/2') expect(integration).not_to be_valid
expect(integration.api_url).to eq('http://jira_edited.example.com/rest/api/2')
expect(integration.password).to be_nil expect(integration.password).to be_nil
end end
it 'does not reset password if new url is set together with password, even if it\'s the same password' do it 'does not reset password if new url is set together with password, even if it\'s the same password' do
integration.url = 'http://jira_edited.example.com' integration.url = 'http://jira_edited.example.com'
integration.password = password integration.password = password
integration.save!
expect(integration).to be_valid
expect(integration.password).to eq(password) expect(integration.password).to eq(password)
expect(integration.url).to eq('http://jira_edited.example.com') expect(integration.url).to eq('http://jira_edited.example.com')
end end
...@@ -392,32 +392,32 @@ RSpec.describe Integrations::Jira do ...@@ -392,32 +392,32 @@ RSpec.describe Integrations::Jira do
it 'resets password if url changed, even if setter called multiple times' do it 'resets password if url changed, even if setter called multiple times' do
integration.url = 'http://jira1.example.com/rest/api/2' integration.url = 'http://jira1.example.com/rest/api/2'
integration.url = 'http://jira1.example.com/rest/api/2' integration.url = 'http://jira1.example.com/rest/api/2'
integration.save!
expect(integration).not_to be_valid
expect(integration.password).to be_nil expect(integration.password).to be_nil
end end
it 'does not reset password if username changed' do it 'does not reset password if username changed' do
integration.username = 'some_name' integration.username = 'some_name'
integration.save!
expect(integration.reload.password).to eq(password) expect(integration).to be_valid
expect(integration.password).to eq(password)
end end
it 'does not reset password if password changed' do it 'does not reset password if password changed' do
integration.url = 'http://jira_edited.example.com' integration.url = 'http://jira_edited.example.com'
integration.password = 'new_password' integration.password = 'new_password'
integration.save!
expect(integration.reload.password).to eq('new_password') expect(integration).to be_valid
expect(integration.password).to eq('new_password')
end end
it 'does not reset password if the password is touched and same as before' do it 'does not reset password if the password is touched and same as before' do
integration.url = 'http://jira_edited.example.com' integration.url = 'http://jira_edited.example.com'
integration.password = password integration.password = password
integration.save!
expect(integration.reload.password).to eq(password) expect(integration).to be_valid
expect(integration.password).to eq(password)
end end
end end
...@@ -432,22 +432,23 @@ RSpec.describe Integrations::Jira do ...@@ -432,22 +432,23 @@ RSpec.describe Integrations::Jira do
it 'resets password if api url changed' do it 'resets password if api url changed' do
integration.api_url = 'http://jira_edited.example.com/rest/api/2' integration.api_url = 'http://jira_edited.example.com/rest/api/2'
integration.save!
expect(integration).not_to be_valid
expect(integration.password).to be_nil expect(integration.password).to be_nil
end end
it 'does not reset password if url changed' do it 'does not reset password if url changed' do
integration.url = 'http://jira_edited.example.com' integration.url = 'http://jira_edited.example.com'
integration.save!
expect(integration).to be_valid
expect(integration.password).to eq(password) expect(integration.password).to eq(password)
end end
it 'resets password if api url set to empty' do it 'resets password if api url set to empty' do
integration.update!(api_url: '') integration.api_url = ''
expect(integration.reload.password).to be_nil expect(integration).not_to be_valid
expect(integration.password).to be_nil
end end
end end
end end
...@@ -463,8 +464,11 @@ RSpec.describe Integrations::Jira do ...@@ -463,8 +464,11 @@ RSpec.describe Integrations::Jira do
integration.url = 'http://jira_edited.example.com/rest/api/2' integration.url = 'http://jira_edited.example.com/rest/api/2'
integration.password = 'password' integration.password = 'password'
integration.save! integration.save!
expect(integration.reload.password).to eq('password')
expect(integration.reload.url).to eq('http://jira_edited.example.com/rest/api/2') expect(integration.reload).to have_attributes(
url: 'http://jira_edited.example.com/rest/api/2',
password: 'password'
)
end end
end end
end end
...@@ -492,7 +496,7 @@ RSpec.describe Integrations::Jira do ...@@ -492,7 +496,7 @@ RSpec.describe Integrations::Jira do
context 'when data are stored in both properties and separated fields' do context 'when data are stored in both properties and separated fields' do
let(:properties) { data_params } let(:properties) { data_params }
let(:integration) do let(:integration) do
create(:jira_integration, :without_properties_callback, active: false, properties: properties).tap do |integration| create(:jira_integration, :without_properties_callback, properties: properties).tap do |integration|
create(:jira_tracker_data, data_params.merge(integration: integration)) create(:jira_tracker_data, data_params.merge(integration: integration))
end end
end end
......
...@@ -76,18 +76,18 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do ...@@ -76,18 +76,18 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do
describe 'Callbacks' do describe 'Callbacks' do
let(:teamcity_integration) { integration } let(:teamcity_integration) { integration }
describe 'before_update :reset_password' do describe 'before_validation :reset_password' do
context 'when a password was previously set' do context 'when a password was previously set' do
it 'resets password if url changed' do it 'resets password if url changed' do
teamcity_integration.teamcity_url = 'http://gitlab1.com' teamcity_integration.teamcity_url = 'http://gitlab1.com'
teamcity_integration.save! teamcity_integration.valid?
expect(teamcity_integration.password).to be_nil expect(teamcity_integration.password).to be_nil
end end
it 'does not reset password if username changed' do it 'does not reset password if username changed' do
teamcity_integration.username = 'some_name' teamcity_integration.username = 'some_name'
teamcity_integration.save! teamcity_integration.valid?
expect(teamcity_integration.password).to eq('password') expect(teamcity_integration.password).to eq('password')
end end
...@@ -95,7 +95,7 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do ...@@ -95,7 +95,7 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do
it "does not reset password if new url is set together with password, even if it's the same password" do it "does not reset password if new url is set together with password, even if it's the same password" do
teamcity_integration.teamcity_url = 'http://gitlab_edited.com' teamcity_integration.teamcity_url = 'http://gitlab_edited.com'
teamcity_integration.password = 'password' teamcity_integration.password = 'password'
teamcity_integration.save! teamcity_integration.valid?
expect(teamcity_integration.password).to eq('password') expect(teamcity_integration.password).to eq('password')
expect(teamcity_integration.teamcity_url).to eq('http://gitlab_edited.com') expect(teamcity_integration.teamcity_url).to eq('http://gitlab_edited.com')
...@@ -109,8 +109,10 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do ...@@ -109,8 +109,10 @@ RSpec.describe Integrations::Teamcity, :use_clean_rails_memory_store_caching do
teamcity_integration.password = 'password' teamcity_integration.password = 'password'
teamcity_integration.save! teamcity_integration.save!
expect(teamcity_integration.password).to eq('password') expect(teamcity_integration.reload).to have_attributes(
expect(teamcity_integration.teamcity_url).to eq('http://gitlab_edited.com') teamcity_url: 'http://gitlab_edited.com',
password: 'password'
)
end end
end end
end end
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment