...@@ -18,7 +18,7 @@ module Gitlab ...@@ -18,7 +18,7 @@ module Gitlab
authenticator = authenticator =
case provider case provider
when /^ldap/ when /^ldap/
Gitlab::Auth::LDAP::Authentication Gitlab::Auth::Ldap::Authentication
when 'database' when 'database'
Gitlab::Auth::Database::Authentication Gitlab::Auth::Database::Authentication
end end
...@@ -60,8 +60,8 @@ module Gitlab ...@@ -60,8 +60,8 @@ module Gitlab
def self.config_for(name) def self.config_for(name)
name = name.to_s name = name.to_s
if ldap_provider?(name) if ldap_provider?(name)
if Gitlab::Auth::LDAP::Config.valid_provider?(name) if Gitlab::Auth::Ldap::Config.valid_provider?(name)
Gitlab::Auth::LDAP::Config.new(name).options Gitlab::Auth::Ldap::Config.new(name).options
else else
nil nil
end end
... ...
......
...@@ -111,7 +111,7 @@ module Gitlab ...@@ -111,7 +111,7 @@ module Gitlab
def find_or_build_ldap_user def find_or_build_ldap_user
return unless ldap_person return unless ldap_person
user = Gitlab::Auth::LDAP::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider) user = Gitlab::Auth::Ldap::User.find_by_uid_and_provider(ldap_person.dn, ldap_person.provider)
if user if user
log.info "LDAP account found for user #{user.username}. Building new #{auth_hash.provider} identity." log.info "LDAP account found for user #{user.username}. Building new #{auth_hash.provider} identity."
return user return user
...@@ -141,8 +141,8 @@ module Gitlab ...@@ -141,8 +141,8 @@ module Gitlab
return @ldap_person if defined?(@ldap_person) return @ldap_person if defined?(@ldap_person)
# Look for a corresponding person with same uid in any of the configured LDAP providers # Look for a corresponding person with same uid in any of the configured LDAP providers
Gitlab::Auth::LDAP::Config.providers.each do |provider| Gitlab::Auth::Ldap::Config.providers.each do |provider|
adapter = Gitlab::Auth::LDAP::Adapter.new(provider) adapter = Gitlab::Auth::Ldap::Adapter.new(provider)
@ldap_person = find_ldap_person(auth_hash, adapter) @ldap_person = find_ldap_person(auth_hash, adapter)
break if @ldap_person break if @ldap_person
end end
...@@ -150,15 +150,15 @@ module Gitlab ...@@ -150,15 +150,15 @@ module Gitlab
end end
def find_ldap_person(auth_hash, adapter) def find_ldap_person(auth_hash, adapter)
Gitlab::Auth::LDAP::Person.find_by_uid(auth_hash.uid, adapter) || Gitlab::Auth::Ldap::Person.find_by_uid(auth_hash.uid, adapter) ||
Gitlab::Auth::LDAP::Person.find_by_email(auth_hash.uid, adapter) || Gitlab::Auth::Ldap::Person.find_by_email(auth_hash.uid, adapter) ||
Gitlab::Auth::LDAP::Person.find_by_dn(auth_hash.uid, adapter) Gitlab::Auth::Ldap::Person.find_by_dn(auth_hash.uid, adapter)
rescue Gitlab::Auth::LDAP::LDAPConnectionError rescue Gitlab::Auth::Ldap::LdapConnectionError
nil nil
end end
def ldap_config def ldap_config
Gitlab::Auth::LDAP::Config.new(ldap_person.provider) if ldap_person Gitlab::Auth::Ldap::Config.new(ldap_person.provider) if ldap_person
end end
def needs_blocking? def needs_blocking?
... ...
......
...@@ -33,7 +33,7 @@ module Gitlab ...@@ -33,7 +33,7 @@ module Gitlab
return false unless can_access_git? return false unless can_access_git?
if user.requires_ldap_check? && user.try_obtain_ldap_lease if user.requires_ldap_check? && user.try_obtain_ldap_lease
return false unless Gitlab::Auth::LDAP::Access.allowed?(user) return false unless Gitlab::Auth::Ldap::Access.allowed?(user)
end end
true true
... ...
......
...@@ -6,7 +6,7 @@ module SystemCheck ...@@ -6,7 +6,7 @@ module SystemCheck
set_name 'LDAP:' set_name 'LDAP:'
def multi_check def multi_check
if Gitlab::Auth::LDAP::Config.enabled? if Gitlab::Auth::Ldap::Config.enabled?
# Only show up to 100 results because LDAP directories can be very big. # Only show up to 100 results because LDAP directories can be very big.
# This setting only affects the `rake gitlab:check` script. # This setting only affects the `rake gitlab:check` script.
limit = ENV['LDAP_CHECK_LIMIT'] limit = ENV['LDAP_CHECK_LIMIT']
...@@ -21,13 +21,13 @@ module SystemCheck ...@@ -21,13 +21,13 @@ module SystemCheck
private private
def check_ldap(limit) def check_ldap(limit)
servers = Gitlab::Auth::LDAP::Config.providers servers = Gitlab::Auth::Ldap::Config.providers
servers.each do |server| servers.each do |server|
$stdout.puts "Server: #{server}" $stdout.puts "Server: #{server}"
begin begin
Gitlab::Auth::LDAP::Adapter.open(server) do |adapter| Gitlab::Auth::Ldap::Adapter.open(server) do |adapter|
check_ldap_auth(adapter) check_ldap_auth(adapter)
$stdout.puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)" $stdout.puts "LDAP users with access to your GitLab server (only showing the first #{limit} results)"
... ...
......
...@@ -13,7 +13,7 @@ namespace :gitlab do ...@@ -13,7 +13,7 @@ namespace :gitlab do
print "#{user.name} (#{user.ldap_identity.extern_uid}) ..." print "#{user.name} (#{user.ldap_identity.extern_uid}) ..."
if Gitlab::Auth::LDAP::Access.allowed?(user) if Gitlab::Auth::Ldap::Access.allowed?(user)
puts " [OK]".color(:green) puts " [OK]".color(:green)
else else
if block_flag if block_flag
... ...
......
...@@ -1550,13 +1550,13 @@ msgstr "" ...@@ -1550,13 +1550,13 @@ msgstr ""
msgid "Advanced" msgid "Advanced"
msgstr "" msgstr ""
   
msgid "Advanced permissions, Large File Storage and Two-Factor authentication settings." msgid "Advanced Settings"
msgstr "" msgstr ""
   
msgid "Advanced search functionality" msgid "Advanced permissions, Large File Storage and Two-Factor authentication settings."
msgstr "" msgstr ""
   
msgid "Advanced settings" msgid "Advanced search functionality"
msgstr "" msgstr ""
   
msgid "After a successful password update you will be redirected to login screen." msgid "After a successful password update you will be redirected to login screen."
...@@ -3991,6 +3991,9 @@ msgstr "" ...@@ -3991,6 +3991,9 @@ msgstr ""
msgid "Closed this %{quick_action_target}." msgid "Closed this %{quick_action_target}."
msgstr "" msgstr ""
   
msgid "Closed: %{closedIssuesCount}"
msgstr ""
msgid "Closes this %{quick_action_target}." msgid "Closes this %{quick_action_target}."
msgstr "" msgstr ""
   
...@@ -4021,6 +4024,9 @@ msgstr "" ...@@ -4021,6 +4024,9 @@ msgstr ""
msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster" msgid "ClusterIntegration|%{appList} was successfully installed on your Kubernetes cluster"
msgstr "" msgstr ""
   
msgid "ClusterIntegration|%{external_ip}.nip.io"
msgstr ""
msgid "ClusterIntegration|%{title} uninstalled successfully." msgid "ClusterIntegration|%{title} uninstalled successfully."
msgstr "" msgstr ""
   
...@@ -4057,7 +4063,7 @@ msgstr "" ...@@ -4057,7 +4063,7 @@ msgstr ""
msgid "ClusterIntegration|Adding an integration will share the cluster across all projects." msgid "ClusterIntegration|Adding an integration will share the cluster across all projects."
msgstr "" msgstr ""
   
msgid "ClusterIntegration|Advanced options on this Kubernetes cluster's integration" msgid "ClusterIntegration|Advanced options on this Kubernetes cluster’s integration"
msgstr "" msgstr ""
   
msgid "ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored." msgid "ClusterIntegration|All data not committed to GitLab will be deleted and cannot be restored."
...@@ -4093,9 +4099,6 @@ msgstr "" ...@@ -4093,9 +4099,6 @@ msgstr ""
msgid "ClusterIntegration|Any running pipelines will be canceled." msgid "ClusterIntegration|Any running pipelines will be canceled."
msgstr "" msgstr ""
   
msgid "ClusterIntegration|Applications"
msgstr ""
msgid "ClusterIntegration|Apply for credit" msgid "ClusterIntegration|Apply for credit"
msgstr "" msgstr ""
   
...@@ -4147,9 +4150,6 @@ msgstr "" ...@@ -4147,9 +4150,6 @@ msgstr ""
msgid "ClusterIntegration|Cluster being created" msgid "ClusterIntegration|Cluster being created"
msgstr "" msgstr ""
   
msgid "ClusterIntegration|Cluster health"
msgstr ""
msgid "ClusterIntegration|Cluster management project (alpha)" msgid "ClusterIntegration|Cluster management project (alpha)"
msgstr "" msgstr ""
   
...@@ -4342,7 +4342,7 @@ msgstr "" ...@@ -4342,7 +4342,7 @@ msgstr ""
msgid "ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration." msgid "ClusterIntegration|If you do not wish to delete all associated GitLab resources, you can simply remove the integration."
msgstr "" msgstr ""
   
msgid "ClusterIntegration|In order to view the health of your cluster, you must first install Prometheus below." msgid "ClusterIntegration|In order to view the health of your cluster, you must first install Prometheus in the Applications tab."
msgstr "" msgstr ""
   
msgid "ClusterIntegration|Ingress" msgid "ClusterIntegration|Ingress"
...@@ -4366,9 +4366,6 @@ msgstr "" ...@@ -4366,9 +4366,6 @@ msgstr ""
msgid "ClusterIntegration|Integrate Kubernetes cluster automation" msgid "ClusterIntegration|Integrate Kubernetes cluster automation"
msgstr "" msgstr ""
   
msgid "ClusterIntegration|Integration status"
msgstr ""
msgid "ClusterIntegration|Issuer Email" msgid "ClusterIntegration|Issuer Email"
msgstr "" msgstr ""
   
...@@ -4405,9 +4402,6 @@ msgstr "" ...@@ -4405,9 +4402,6 @@ msgstr ""
msgid "ClusterIntegration|Kubernetes cluster" msgid "ClusterIntegration|Kubernetes cluster"
msgstr "" msgstr ""
   
msgid "ClusterIntegration|Kubernetes cluster details"
msgstr ""
msgid "ClusterIntegration|Kubernetes cluster is being created..." msgid "ClusterIntegration|Kubernetes cluster is being created..."
msgstr "" msgstr ""
   
...@@ -4558,6 +4552,9 @@ msgstr "" ...@@ -4558,6 +4552,9 @@ msgstr ""
msgid "ClusterIntegration|Prometheus is an open-source monitoring system with %{gitlabIntegrationLink} to monitor deployed applications." msgid "ClusterIntegration|Prometheus is an open-source monitoring system with %{gitlabIntegrationLink} to monitor deployed applications."
msgstr "" msgstr ""
   
msgid "ClusterIntegration|Provider details"
msgstr ""
msgid "ClusterIntegration|Provision Role ARN" msgid "ClusterIntegration|Provision Role ARN"
msgstr "" msgstr ""
   
...@@ -5570,6 +5567,9 @@ msgstr "" ...@@ -5570,6 +5567,9 @@ msgstr ""
msgid "Copy commit SHA" msgid "Copy commit SHA"
msgstr "" msgstr ""
   
msgid "Copy evidence SHA"
msgstr ""
msgid "Copy file contents" msgid "Copy file contents"
msgstr "" msgstr ""
   
...@@ -5630,9 +5630,6 @@ msgstr "" ...@@ -5630,9 +5630,6 @@ msgstr ""
msgid "Could not create group" msgid "Could not create group"
msgstr "" msgstr ""
   
msgid "Could not create issue"
msgstr ""
msgid "Could not create project" msgid "Could not create project"
msgstr "" msgstr ""
   
...@@ -5642,9 +5639,6 @@ msgstr "" ...@@ -5642,9 +5639,6 @@ msgstr ""
msgid "Could not delete chat nickname %{chat_name}." msgid "Could not delete chat nickname %{chat_name}."
msgstr "" msgstr ""
   
msgid "Could not fetch projects"
msgstr ""
msgid "Could not find design" msgid "Could not find design"
msgstr "" msgstr ""
   
...@@ -7840,6 +7834,9 @@ msgstr "" ...@@ -7840,6 +7834,9 @@ msgstr ""
msgid "Epics|Something went wrong while creating child epics." msgid "Epics|Something went wrong while creating child epics."
msgstr "" msgstr ""
   
msgid "Epics|Something went wrong while creating issue."
msgstr ""
msgid "Epics|Something went wrong while fetching child epics." msgid "Epics|Something went wrong while fetching child epics."
msgstr "" msgstr ""
   
...@@ -10288,6 +10285,9 @@ msgstr "" ...@@ -10288,6 +10285,9 @@ msgstr ""
msgid "Header message" msgid "Header message"
msgstr "" msgstr ""
   
msgid "Health"
msgstr ""
msgid "Health Check" msgid "Health Check"
msgstr "" msgstr ""
   
...@@ -13178,6 +13178,9 @@ msgstr "" ...@@ -13178,6 +13178,9 @@ msgstr ""
msgid "No licenses found." msgid "No licenses found."
msgstr "" msgstr ""
   
msgid "No matches found"
msgstr ""
msgid "No matching labels" msgid "No matching labels"
msgstr "" msgstr ""
   
...@@ -13636,6 +13639,9 @@ msgstr "" ...@@ -13636,6 +13639,9 @@ msgstr ""
msgid "Open source software to collaborate on code" msgid "Open source software to collaborate on code"
msgstr "" msgstr ""
   
msgid "Open: %{openIssuesCount}"
msgstr ""
msgid "Open: %{open} • Closed: %{closed}" msgid "Open: %{open} • Closed: %{closed}"
msgstr "" msgstr ""
   
...@@ -18320,6 +18326,9 @@ msgstr "" ...@@ -18320,6 +18326,9 @@ msgstr ""
msgid "Something went wrong while fetching projects" msgid "Something went wrong while fetching projects"
msgstr "" msgstr ""
   
msgid "Something went wrong while fetching projects."
msgstr ""
msgid "Something went wrong while fetching related merge requests." msgid "Something went wrong while fetching related merge requests."
msgstr "" msgstr ""
   
... ...
......
...@@ -10,17 +10,35 @@ module QA ...@@ -10,17 +10,35 @@ module QA
element :ingress_ip_address, 'id="ingress-endpoint"' # rubocop:disable QA/ElementWithPattern element :ingress_ip_address, 'id="ingress-endpoint"' # rubocop:disable QA/ElementWithPattern
end end
view 'app/views/clusters/clusters/_form.html.haml' do view 'app/views/clusters/clusters/_gitlab_integration_form.html.haml' do
element :integration_status_toggle, required: true element :integration_status_toggle, required: true
element :base_domain_field, required: true element :base_domain_field, required: true
element :save_changes_button, required: true element :save_changes_button, required: true
end end
view 'app/views/clusters/clusters/_details_tab.html.haml' do
element :details, required: true
end
view 'app/views/clusters/clusters/_applications_tab.html.haml' do
element :applications, required: true
end
view 'app/assets/javascripts/clusters/components/application_row.vue' do view 'app/assets/javascripts/clusters/components/application_row.vue' do
element :install_button element :install_button
element :uninstall_button element :uninstall_button
end end
def open_details
has_element?(:details, wait: 30)
click_element :details
end
def open_applications
has_element?(:applications, wait: 30)
click_element :applications
end
def install!(application_name) def install!(application_name)
within_element(application_name) do within_element(application_name) do
has_element?(:install_button, application: application_name, wait: 30) has_element?(:install_button, application: application_name, wait: 30)
... ...
......
...@@ -38,6 +38,9 @@ module QA ...@@ -38,6 +38,9 @@ module QA
# We must wait a few seconds for permissions to be set up correctly for new cluster # We must wait a few seconds for permissions to be set up correctly for new cluster
sleep 10 sleep 10
# Open applications tab
show.open_applications
# Helm must be installed before everything else # Helm must be installed before everything else
show.install!(:helm) show.install!(:helm)
show.await_installed(:helm) show.await_installed(:helm)
...@@ -52,6 +55,8 @@ module QA ...@@ -52,6 +55,8 @@ module QA
if @install_ingress if @install_ingress
populate(:ingress_ip) populate(:ingress_ip)
show.open_details
show.set_domain("#{ingress_ip}.nip.io") show.set_domain("#{ingress_ip}.nip.io")
show.save_domain show.save_domain
end end
... ...
......
...@@ -57,97 +57,3 @@ function echoinfo() { ...@@ -57,97 +57,3 @@ function echoinfo() {
printf "\033[0;33m%s\n\033[0m" "${1}" >&2; printf "\033[0;33m%s\n\033[0m" "${1}" >&2;
fi fi
} }
function get_job_id() {
local job_name="${1}"
local query_string="${2:+&${2}}"
local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}"
if [ -z "${api_token}" ]; then
echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN."
return
fi
local max_page=3
local page=1
while true; do
local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/pipelines/${CI_PIPELINE_ID}/jobs?per_page=100&page=${page}${query_string}"
echoinfo "GET ${url}"
local job_id
job_id=$(curl --silent --show-error --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq "map(select(.name == \"${job_name}\")) | map(.id) | last")
[[ "${job_id}" == "null" && "${page}" -lt "$max_page" ]] || break
let "page++"
done
if [[ "${job_id}" == "" ]]; then
echoerr "The '${job_name}' job ID couldn't be retrieved!"
else
echoinfo "The '${job_name}' job ID is ${job_id}"
echo "${job_id}"
fi
}
function play_job() {
local job_name="${1}"
local job_id
job_id=$(get_job_id "${job_name}" "scope=manual");
if [ -z "${job_id}" ]; then return; fi
local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}"
if [ -z "${api_token}" ]; then
echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN."
return
fi
local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/jobs/${job_id}/play"
echoinfo "POST ${url}"
local job_url
job_url=$(curl --silent --show-error --request POST --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq ".web_url")
echoinfo "Manual job '${job_name}' started at: ${job_url}"
}
function wait_for_job_to_be_done() {
local job_name="${1}"
local query_string="${2}"
local job_id
job_id=$(get_job_id "${job_name}" "${query_string}")
if [ -z "${job_id}" ]; then return; fi
local api_token="${API_TOKEN-${GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN}}"
if [ -z "${api_token}" ]; then
echoerr "Please provide an API token with \$API_TOKEN or \$GITLAB_BOT_MULTI_PROJECT_PIPELINE_POLLING_TOKEN."
return
fi
echoinfo "Waiting for the '${job_name}' job to finish..."
local url="https://gitlab.com/api/v4/projects/${CI_PROJECT_ID}/jobs/${job_id}"
echoinfo "GET ${url}"
# In case the job hasn't finished yet. Keep trying until the job times out.
local interval=30
local elapsed_seconds=0
while true; do
local job_status
job_status=$(curl --silent --show-error --header "PRIVATE-TOKEN: ${api_token}" "${url}" | jq ".status" | sed -e s/\"//g)
[[ "${job_status}" == "pending" || "${job_status}" == "running" ]] || break
printf "."
let "elapsed_seconds+=interval"
sleep ${interval}
done
local elapsed_minutes=$((elapsed_seconds / 60))
echoinfo "Waited '${job_name}' for ${elapsed_minutes} minutes."
if [[ "${job_status}" == "failed" ]]; then
echoerr "The '${job_name}' failed."
elif [[ "${job_status}" == "manual" ]]; then
echoinfo "The '${job_name}' is manual."
else
echoinfo "The '${job_name}' passed."
fi
}
...@@ -198,6 +198,46 @@ describe Projects::ReleasesController do ...@@ -198,6 +198,46 @@ describe Projects::ReleasesController do
end end
end end
context 'GET #downloads' do
subject do
get :downloads, params: { namespace_id: project.namespace, project_id: project, tag: tag, filepath: filepath }
end
before do
sign_in(user)
end
let(:release) { create(:release, project: project, tag: tag ) }
let!(:link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: 'https://downloads.example.com/bin/gitlab-linux-amd64') }
let(:tag) { 'v11.9.0-rc2' }
context 'valid filepath' do
let(:filepath) { CGI.escape('/binaries/linux-amd64') }
it 'redirects to the asset direct link' do
subject
expect(response).to redirect_to('https://downloads.example.com/bin/gitlab-linux-amd64')
end
it 'redirects with a status of 302' do
subject
expect(response).to have_gitlab_http_status(:redirect)
end
end
context 'invalid filepath' do
let(:filepath) { CGI.escape('/binaries/win32') }
it 'is not found' do
subject
expect(response).to have_gitlab_http_status(:not_found)
end
end
end
context 'GET #downloads' do context 'GET #downloads' do
subject do subject do
get :downloads, params: { get :downloads, params: {
... ...
......
...@@ -17,7 +17,7 @@ describe 'Clusterable > Show page' do ...@@ -17,7 +17,7 @@ describe 'Clusterable > Show page' do
it 'allow the user to set domain' do it 'allow the user to set domain' do
visit cluster_path visit cluster_path
within '#cluster-integration' do within '.js-cluster-integration-form' do
fill_in('cluster_base_domain', with: 'test.com') fill_in('cluster_base_domain', with: 'test.com')
click_on 'Save changes' click_on 'Save changes'
end end
...@@ -34,7 +34,7 @@ describe 'Clusterable > Show page' do ...@@ -34,7 +34,7 @@ describe 'Clusterable > Show page' do
end end
it 'shows help text with the domain as an alternative to custom domain' do it 'shows help text with the domain as an alternative to custom domain' do
within '#cluster-integration' do within '.js-cluster-integration-form' do
expect(find(cluster_ingress_help_text_selector)).not_to match_css(hide_modifier_selector) expect(find(cluster_ingress_help_text_selector)).not_to match_css(hide_modifier_selector)
end end
end end
...@@ -44,7 +44,7 @@ describe 'Clusterable > Show page' do ...@@ -44,7 +44,7 @@ describe 'Clusterable > Show page' do
it 'alternative to custom domain is not shown' do it 'alternative to custom domain is not shown' do
visit cluster_path visit cluster_path
within '#cluster-integration' do within '.js-cluster-integration-form' do
expect(find(cluster_ingress_help_text_selector)).to match_css(hide_modifier_selector) expect(find(cluster_ingress_help_text_selector)).to match_css(hide_modifier_selector)
end end
end end
...@@ -63,7 +63,7 @@ describe 'Clusterable > Show page' do ...@@ -63,7 +63,7 @@ describe 'Clusterable > Show page' do
end end
it 'is not able to edit the name, API url, CA certificate nor token' do it 'is not able to edit the name, API url, CA certificate nor token' do
within('#js-cluster-details') do within('.js-provider-details') do
cluster_name_field = find('.cluster-name') cluster_name_field = find('.cluster-name')
api_url_field = find('#cluster_platform_kubernetes_attributes_api_url') api_url_field = find('#cluster_platform_kubernetes_attributes_api_url')
ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert') ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert')
...@@ -77,6 +77,8 @@ describe 'Clusterable > Show page' do ...@@ -77,6 +77,8 @@ describe 'Clusterable > Show page' do
end end
it 'displays GKE information' do it 'displays GKE information' do
click_link 'Advanced Settings'
within('#advanced-settings-section') do within('#advanced-settings-section') do
expect(page).to have_content('Google Kubernetes Engine') expect(page).to have_content('Google Kubernetes Engine')
expect(page).to have_content('Manage your Kubernetes cluster by visiting') expect(page).to have_content('Manage your Kubernetes cluster by visiting')
...@@ -91,7 +93,7 @@ describe 'Clusterable > Show page' do ...@@ -91,7 +93,7 @@ describe 'Clusterable > Show page' do
end end
it 'is able to edit the name, API url, CA certificate and token' do it 'is able to edit the name, API url, CA certificate and token' do
within('#js-cluster-details') do within('.js-provider-details') do
cluster_name_field = find('#cluster_name') cluster_name_field = find('#cluster_name')
api_url_field = find('#cluster_platform_kubernetes_attributes_api_url') api_url_field = find('#cluster_platform_kubernetes_attributes_api_url')
ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert') ca_certificate_field = find('#cluster_platform_kubernetes_attributes_ca_cert')
...@@ -105,6 +107,8 @@ describe 'Clusterable > Show page' do ...@@ -105,6 +107,8 @@ describe 'Clusterable > Show page' do
end end
it 'does not display GKE information' do it 'does not display GKE information' do
click_link 'Advanced Settings'
within('#advanced-settings-section') do within('#advanced-settings-section') do
expect(page).not_to have_content('Google Kubernetes Engine') expect(page).not_to have_content('Google Kubernetes Engine')
expect(page).not_to have_content('Manage your Kubernetes cluster by visiting') expect(page).not_to have_content('Manage your Kubernetes cluster by visiting')
... ...
......
...@@ -17,6 +17,12 @@ shared_examples "installing applications on a cluster" do ...@@ -17,6 +17,12 @@ shared_examples "installing applications on a cluster" do
context 'when cluster is created' do context 'when cluster is created' do
let(:cluster) { create(:cluster, :provided_by_gcp, *cluster_factory_args) } let(:cluster) { create(:cluster, :provided_by_gcp, *cluster_factory_args) }
before do
page.within('.js-edit-cluster-form') do
click_link 'Applications'
end
end
it 'user can install applications' do it 'user can install applications' do
wait_for_requests wait_for_requests
...@@ -29,6 +35,7 @@ shared_examples "installing applications on a cluster" do ...@@ -29,6 +35,7 @@ shared_examples "installing applications on a cluster" do
context 'when user installs Helm' do context 'when user installs Helm' do
before do before do
allow(ClusterInstallAppWorker).to receive(:perform_async) allow(ClusterInstallAppWorker).to receive(:perform_async)
wait_for_requests
page.within('.js-cluster-application-row-helm') do page.within('.js-cluster-application-row-helm') do
page.find(:css, '.js-cluster-application-install-button').click page.find(:css, '.js-cluster-application-install-button').click
... ...
......
...@@ -34,7 +34,7 @@ describe 'User Cluster', :js do ...@@ -34,7 +34,7 @@ describe 'User Cluster', :js do
it 'user sees a cluster details page' do it 'user sees a cluster details page' do
subject subject
expect(page).to have_content('Kubernetes cluster integration') expect(page).to have_content('GitLab Integration')
expect(page.find_field('cluster[name]').value).to eq('dev-cluster') expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value) expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com') .to have_content('http://example.com')
...@@ -93,7 +93,7 @@ describe 'User Cluster', :js do ...@@ -93,7 +93,7 @@ describe 'User Cluster', :js do
context 'when user disables the cluster' do context 'when user disables the cluster' do
before do before do
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
page.within('#cluster-integration') { click_button 'Save changes' } page.within('.js-cluster-integration-form') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -105,7 +105,7 @@ describe 'User Cluster', :js do ...@@ -105,7 +105,7 @@ describe 'User Cluster', :js do
before do before do
fill_in 'cluster_name', with: 'my-dev-cluster' fill_in 'cluster_name', with: 'my-dev-cluster'
fill_in 'cluster_platform_kubernetes_attributes_token', with: 'new-token' fill_in 'cluster_platform_kubernetes_attributes_token', with: 'new-token'
page.within('#js-cluster-details') { click_button 'Save changes' } page.within('.js-provider-details') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -117,6 +117,7 @@ describe 'User Cluster', :js do ...@@ -117,6 +117,7 @@ describe 'User Cluster', :js do
context 'when user destroys the cluster' do context 'when user destroys the cluster' do
before do before do
click_link 'Advanced Settings'
click_button 'Remove integration and resources' click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration' click_button 'Remove integration'
... ...
......
...@@ -119,7 +119,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -119,7 +119,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
context 'when user disables the cluster' do context 'when user disables the cluster' do
before do before do
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
page.within('#cluster-integration') { click_button 'Save changes' } page.within('.js-cluster-integration-form') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -130,7 +130,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -130,7 +130,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
context 'when user changes cluster parameters' do context 'when user changes cluster parameters' do
before do before do
fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace'
page.within('#js-cluster-details') { click_button 'Save changes' } page.within('.js-provider-details') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -141,6 +141,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do ...@@ -141,6 +141,7 @@ describe 'Gcp Cluster', :js, :do_not_mock_admin_mode do
context 'when user destroys the cluster' do context 'when user destroys the cluster' do
before do before do
click_link 'Advanced Settings'
click_button 'Remove integration and resources' click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration' click_button 'Remove integration'
... ...
......
...@@ -41,7 +41,7 @@ describe 'User Cluster', :js do ...@@ -41,7 +41,7 @@ describe 'User Cluster', :js do
it 'user sees a cluster details page' do it 'user sees a cluster details page' do
subject subject
expect(page).to have_content('Kubernetes cluster integration') expect(page).to have_content('GitLab Integration')
expect(page.find_field('cluster[name]').value).to eq('dev-cluster') expect(page.find_field('cluster[name]').value).to eq('dev-cluster')
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value) expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com') .to have_content('http://example.com')
...@@ -79,7 +79,7 @@ describe 'User Cluster', :js do ...@@ -79,7 +79,7 @@ describe 'User Cluster', :js do
context 'when user disables the cluster' do context 'when user disables the cluster' do
before do before do
page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click page.find(:css, '.js-cluster-enable-toggle-area .js-project-feature-toggle').click
page.within('#cluster-integration') { click_button 'Save changes' } page.within('.js-cluster-integration-form') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -91,7 +91,7 @@ describe 'User Cluster', :js do ...@@ -91,7 +91,7 @@ describe 'User Cluster', :js do
before do before do
fill_in 'cluster_name', with: 'my-dev-cluster' fill_in 'cluster_name', with: 'my-dev-cluster'
fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace' fill_in 'cluster_platform_kubernetes_attributes_namespace', with: 'my-namespace'
page.within('#js-cluster-details') { click_button 'Save changes' } page.within('.js-provider-details') { click_button 'Save changes' }
end end
it 'user sees the successful message' do it 'user sees the successful message' do
...@@ -103,6 +103,7 @@ describe 'User Cluster', :js do ...@@ -103,6 +103,7 @@ describe 'User Cluster', :js do
context 'when user destroys the cluster' do context 'when user destroys the cluster' do
before do before do
click_link 'Advanced Settings'
click_button 'Remove integration and resources' click_button 'Remove integration and resources'
fill_in 'confirm_cluster_name_input', with: cluster.name fill_in 'confirm_cluster_name_input', with: cluster.name
click_button 'Remove integration' click_button 'Remove integration'
... ...
......
...@@ -24,16 +24,31 @@ describe 'User views releases', :js do ...@@ -24,16 +24,31 @@ describe 'User views releases', :js do
context 'when there is a link as an asset' do context 'when there is a link as an asset' do
let!(:release_link) { create(:release_link, release: release, url: url ) } let!(:release_link) { create(:release_link, release: release, url: url ) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" } let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
let(:direct_asset_link) { Gitlab::Routing.url_helpers.project_release_url(project, release) << release_link.filepath }
it 'sees the link' do it 'sees the link' do
visit project_releases_path(project) visit project_releases_path(project)
page.within('.js-assets-list') do page.within('.js-assets-list') do
expect(page).to have_link release_link.name, href: release_link.url expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_content('(external source)') expect(page).not_to have_content('(external source)')
end end
end end
context 'when there is a link redirect' do
let!(:release_link) { create(:release_link, release: release, name: 'linux-amd64 binaries', filepath: '/binaries/linux-amd64', url: url) }
let(:url) { "#{project.web_url}/-/jobs/1/artifacts/download" }
it 'sees the link' do
visit project_releases_path(project)
page.within('.js-assets-list') do
expect(page).to have_link release_link.name, href: direct_asset_link
expect(page).not_to have_content('(external source)')
end
end
end
context 'when url points to external resource' do context 'when url points to external resource' do
let(:url) { 'http://google.com/download' } let(:url) { 'http://google.com/download' }
... ...
......
...@@ -38,7 +38,7 @@ describe 'Projects > Snippets > User updates a snippet' do ...@@ -38,7 +38,7 @@ describe 'Projects > Snippets > User updates a snippet' do
end end
it 'renders edit page and displays the error' do it 'renders edit page and displays the error' do
expect(page).to have_content('Error updating the snippet') expect(page.find('.flash-container span').text).to eq('Error updating the snippet')
expect(page).to have_content('Edit Snippet') expect(page).to have_content('Edit Snippet')
end end
end end
... ...
......
...@@ -71,7 +71,7 @@ describe 'User edits snippet', :js do ...@@ -71,7 +71,7 @@ describe 'User edits snippet', :js do
end end
it 'renders edit page and displays the error' do it 'renders edit page and displays the error' do
expect(page).to have_content('Error updating the snippet') expect(page.find('.flash-container span').text).to eq('Error updating the snippet')
expect(page).to have_content('Edit Snippet') expect(page).to have_content('Edit Snippet')
end end
end end
... ...
......
...@@ -67,7 +67,7 @@ describe('Evidence Block', () => { ...@@ -67,7 +67,7 @@ describe('Evidence Block', () => {
}); });
it('renders the correct hover text', () => { it('renders the correct hover text', () => {
expect(wrapper.find(ClipboardButton).attributes('title')).toBe('Copy commit SHA'); expect(wrapper.find(ClipboardButton).attributes('title')).toBe('Copy evidence SHA');
}); });
it('copies the sha', () => { it('copies the sha', () => {
... ...
......
...@@ -10,11 +10,9 @@ describe('Release block milestone info', () => { ...@@ -10,11 +10,9 @@ describe('Release block milestone info', () => {
let wrapper; let wrapper;
let milestones; let milestones;
const factory = milestonesProp => { const factory = props => {
wrapper = mount(ReleaseBlockMilestoneInfo, { wrapper = mount(ReleaseBlockMilestoneInfo, {
propsData: { propsData: props,
milestones: milestonesProp,
},
}); });
return wrapper.vm.$nextTick(); return wrapper.vm.$nextTick();
...@@ -26,6 +24,7 @@ describe('Release block milestone info', () => { ...@@ -26,6 +24,7 @@ describe('Release block milestone info', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
wrapper = null;
}); });
const milestoneProgressBarContainer = () => wrapper.find('.js-milestone-progress-bar-container'); const milestoneProgressBarContainer = () => wrapper.find('.js-milestone-progress-bar-container');
...@@ -33,7 +32,7 @@ describe('Release block milestone info', () => { ...@@ -33,7 +32,7 @@ describe('Release block milestone info', () => {
const issuesContainer = () => wrapper.find('.js-issues-container'); const issuesContainer = () => wrapper.find('.js-issues-container');
describe('with default props', () => { describe('with default props', () => {
beforeEach(() => factory(milestones)); beforeEach(() => factory({ milestones }));
it('renders the correct percentage', () => { it('renders the correct percentage', () => {
expect(milestoneProgressBarContainer().text()).toContain('41% complete'); expect(milestoneProgressBarContainer().text()).toContain('41% complete');
...@@ -102,7 +101,7 @@ describe('Release block milestone info', () => { ...@@ -102,7 +101,7 @@ describe('Release block milestone info', () => {
.map(m => m.title) .map(m => m.title)
.join(' • '); .join(' • ');
return factory(lotsOfMilestones); return factory({ milestones: lotsOfMilestones });
}); });
const clickShowMoreFewerButton = () => { const clickShowMoreFewerButton = () => {
...@@ -153,12 +152,12 @@ describe('Release block milestone info', () => { ...@@ -153,12 +152,12 @@ describe('Release block milestone info', () => {
...m, ...m,
issueStats: { issueStats: {
...m.issueStats, ...m.issueStats,
opened: 0, total: 0,
closed: 0, closed: 0,
}, },
})); }));
return factory(milestones); return factory({ milestones });
}); });
expectAllZeros(); expectAllZeros();
...@@ -171,9 +170,72 @@ describe('Release block milestone info', () => { ...@@ -171,9 +170,72 @@ describe('Release block milestone info', () => {
issueStats: undefined, issueStats: undefined,
})); }));
return factory(milestones); return factory({ milestones });
}); });
expectAllZeros(); expectAllZeros();
}); });
describe('Issue links', () => {
const findOpenIssuesLink = () => wrapper.find({ ref: 'openIssuesLink' });
const findOpenIssuesText = () => wrapper.find({ ref: 'openIssuesText' });
const findClosedIssuesLink = () => wrapper.find({ ref: 'closedIssuesLink' });
const findClosedIssuesText = () => wrapper.find({ ref: 'closedIssuesText' });
describe('when openIssuePath is provided', () => {
const openIssuesPath = '/path/to/open/issues';
beforeEach(() => {
return factory({ milestones, openIssuesPath });
});
it('renders the open issues as a link', () => {
expect(findOpenIssuesLink().exists()).toBe(true);
expect(findOpenIssuesText().exists()).toBe(false);
});
it('renders the open issues link with the correct href', () => {
expect(findOpenIssuesLink().attributes().href).toBe(openIssuesPath);
});
});
describe('when openIssuePath is not provided', () => {
beforeEach(() => {
return factory({ milestones });
});
it('renders the open issues as plain text', () => {
expect(findOpenIssuesLink().exists()).toBe(false);
expect(findOpenIssuesText().exists()).toBe(true);
});
});
describe('when closedIssuePath is provided', () => {
const closedIssuesPath = '/path/to/closed/issues';
beforeEach(() => {
return factory({ milestones, closedIssuesPath });
});
it('renders the closed issues as a link', () => {
expect(findClosedIssuesLink().exists()).toBe(true);
expect(findClosedIssuesText().exists()).toBe(false);
});
it('renders the closed issues link with the correct href', () => {
expect(findClosedIssuesLink().attributes().href).toBe(closedIssuesPath);
});
});
describe('when closedIssuePath is not provided', () => {
beforeEach(() => {
return factory({ milestones });
});
it('renders the closed issues as plain text', () => {
expect(findClosedIssuesLink().exists()).toBe(false);
expect(findClosedIssuesText().exists()).toBe(true);
});
});
});
}); });