diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-18 12:07:38 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2019-12-18 12:07:38 +0300 |
commit | 1a9d9cc14ec54036548824e3ce17da03960f5f81 (patch) | |
tree | 4b93fa74f393a1978ea9c2628516eb4a449b8704 /spec | |
parent | dad534d98a3f86bfa079b7ebd980448641cc9c7c (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec')
3 files changed, 305 insertions, 1 deletions
diff --git a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb index 0940fccb431..793c10f0b21 100644 --- a/spec/controllers/projects/environments/prometheus_api_controller_spec.rb +++ b/spec/controllers/projects/environments/prometheus_api_controller_spec.rb @@ -78,6 +78,40 @@ describe Projects::Environments::PrometheusApiController do end end end + + context 'with variables' do + let(:pod_name) { "pod1" } + + before do + expected_params[:query] = %{up{pod_name="#{pod_name}"}} + expected_params[:variables] = ['pod_name', pod_name] + end + + it 'replaces variables with values' do + get :proxy, params: environment_params.merge( + query: 'up{pod_name="{{pod_name}}"}', variables: ['pod_name', pod_name] + ) + + expect(response).to have_gitlab_http_status(:success) + expect(Prometheus::ProxyService).to have_received(:new) + .with(environment, 'GET', 'query', expected_params) + end + + context 'with invalid variables' do + let(:params_with_invalid_variables) do + environment_params.merge( + query: 'up{pod_name="{{pod_name}}"}', variables: ['a'] + ) + end + + it 'returns 400' do + get :proxy, params: params_with_invalid_variables + + expect(response).to have_gitlab_http_status(:bad_request) + expect(Prometheus::ProxyService).not_to receive(:new) + end + end + end end context 'with nil result' do diff --git a/spec/services/prometheus/proxy_variable_substitution_service_spec.rb b/spec/services/prometheus/proxy_variable_substitution_service_spec.rb index b1cdb8fd3ae..9978c631366 100644 --- a/spec/services/prometheus/proxy_variable_substitution_service_spec.rb +++ b/spec/services/prometheus/proxy_variable_substitution_service_spec.rb @@ -39,8 +39,12 @@ describe Prometheus::ProxyVariableSubstitutionService do end context 'with predefined variables' do + let(:params_keys) { { query: 'up{%{environment_filter}}' } } + it_behaves_like 'success' do - let(:expected_query) { %Q[up{environment="#{environment.slug}"}] } + let(:expected_query) do + %Q[up{container_name!="POD",environment="#{environment.slug}"}] + end end context 'with nil query' do @@ -50,6 +54,133 @@ describe Prometheus::ProxyVariableSubstitutionService do let(:expected_query) { nil } end end + + context 'with liquid format' do + let(:params_keys) do + { query: 'up{environment="{{ci_environment_slug}}"}' } + end + + it_behaves_like 'success' do + let(:expected_query) { %Q[up{environment="#{environment.slug}"}] } + end + end + + context 'with ruby and liquid formats' do + let(:params_keys) do + { query: 'up{%{environment_filter},env2="{{ci_environment_slug}}"}' } + end + + it_behaves_like 'success' do + let(:expected_query) do + %Q[up{container_name!="POD",environment="#{environment.slug}",env2="#{environment.slug}"}] + end + end + end + end + + context 'with custom variables' do + let(:pod_name) { "pod1" } + + let(:params_keys) do + { + query: 'up{pod_name="{{pod_name}}"}', + variables: ['pod_name', pod_name] + } + end + + it_behaves_like 'success' do + let(:expected_query) { %q[up{pod_name="pod1"}] } + end + + context 'with ruby variable interpolation format' do + let(:params_keys) do + { + query: 'up{pod_name="%{pod_name}"}', + variables: ['pod_name', pod_name] + } + end + + it_behaves_like 'success' do + # Custom variables cannot be used with the Ruby interpolation format. + let(:expected_query) { "up{pod_name=\"%{pod_name}\"}" } + end + end + + context 'with predefined variables in variables parameter' do + let(:params_keys) do + { + query: 'up{pod_name="{{pod_name}}",env="{{ci_environment_slug}}"}', + variables: ['pod_name', pod_name, 'ci_environment_slug', 'custom_value'] + } + end + + it_behaves_like 'success' do + # Predefined variable values should not be overwritten by custom variable + # values. + let(:expected_query) { "up{pod_name=\"#{pod_name}\",env=\"#{environment.slug}\"}" } + end + end + + context 'with invalid variables parameter' do + let(:params_keys) do + { + query: 'up{pod_name="{{pod_name}}"}', + variables: ['a'] + } + end + + it_behaves_like 'error', 'Optional parameter "variables" must be an ' \ + 'array of keys and values. Ex: [key1, value1, key2, value2]' + end + + context 'with nil variables' do + let(:params_keys) do + { + query: 'up{pod_name="{{pod_name}}"}', + variables: nil + } + end + + it_behaves_like 'success' do + let(:expected_query) { 'up{pod_name=""}' } + end + end + + context 'with ruby and liquid variables' do + let(:params_keys) do + { + query: 'up{env1="%{ruby_variable}",env2="{{ liquid_variable }}"}', + variables: %w(ruby_variable value liquid_variable env_slug) + } + end + + it_behaves_like 'success' do + # It should replace only liquid variables with their values + let(:expected_query) { %q[up{env1="%{ruby_variable}",env2="env_slug"}] } + end + end + end + + context 'with liquid tags and ruby format variables' do + let(:params_keys) do + { + query: 'up{ {% if true %}env1="%{ci_environment_slug}",' \ + 'env2="{{ci_environment_slug}}"{% endif %} }' + } + end + + # The following spec will fail and should be changed to a 'success' spec + # once we remove support for the Ruby interpolation format. + # https://gitlab.com/gitlab-org/gitlab/issues/37990 + # + # Liquid tags `{% %}` cannot be used currently because the Ruby `%` + # operator raises an error when it encounters a Liquid `{% %}` tag in the + # string. + # + # Once we remove support for the Ruby format, users can start using + # Liquid tags. + + it_behaves_like 'error', 'Malformed string' end context 'ruby template rendering' do @@ -139,5 +270,18 @@ describe Prometheus::ProxyVariableSubstitutionService do end end end + + context 'when liquid template rendering raises error' do + before do + liquid_service = instance_double(TemplateEngines::LiquidService) + + allow(TemplateEngines::LiquidService).to receive(:new).and_return(liquid_service) + allow(liquid_service).to receive(:render).and_raise( + TemplateEngines::LiquidService::RenderError, 'error message' + ) + end + + it_behaves_like 'error', 'error message' + end end end diff --git a/spec/services/template_engines/liquid_service_spec.rb b/spec/services/template_engines/liquid_service_spec.rb new file mode 100644 index 00000000000..7c5262bc264 --- /dev/null +++ b/spec/services/template_engines/liquid_service_spec.rb @@ -0,0 +1,126 @@ +# frozen_string_literal: true + +require 'spec_helper' + +describe TemplateEngines::LiquidService do + describe '#render' do + let(:template) { 'up{env={{ci_environment_slug}}}' } + let(:result) { subject } + + let_it_be(:slug) { 'env_slug' } + + let_it_be(:context) do + { + ci_environment_slug: slug, + environment_filter: "container_name!=\"POD\",environment=\"#{slug}\"" + } + end + + subject { described_class.new(template).render(context) } + + it 'with symbol keys in context it substitutes variables' do + expect(result).to include("up{env=#{slug}") + end + + context 'with multiple occurrences of variable in template' do + let(:template) do + 'up{env1={{ci_environment_slug}},env2={{ci_environment_slug}}}' + end + + it 'substitutes variables' do + expect(result).to eq("up{env1=#{slug},env2=#{slug}}") + end + end + + context 'with multiple variables in template' do + let(:template) do + 'up{env={{ci_environment_slug}},' \ + '{{environment_filter}}}' + end + + it 'substitutes all variables' do + expect(result).to eq( + "up{env=#{slug}," \ + "container_name!=\"POD\",environment=\"#{slug}\"}" + ) + end + end + + context 'with unknown variables in template' do + let(:template) { 'up{env={{env_slug}}}' } + + it 'does not substitute unknown variables' do + expect(result).to eq("up{env=}") + end + end + + context 'with extra variables in context' do + let(:template) { 'up{env={{ci_environment_slug}}}' } + + it 'substitutes variables' do + # If context has only 1 key, there is no need for this spec. + expect(context.count).to be > 1 + expect(result).to eq("up{env=#{slug}}") + end + end + + context 'with unknown and known variables in template' do + let(:template) { 'up{env={{ci_environment_slug}},other_env={{env_slug}}}' } + + it 'substitutes known variables' do + expect(result).to eq("up{env=#{slug},other_env=}") + end + end + + context 'Liquid errors' do + shared_examples 'raises RenderError' do |message| + it do + expect { result }.to raise_error(described_class::RenderError, message) + end + end + + context 'when liquid raises error' do + let(:template) { 'up{env={{ci_environment_slug}}' } + let(:liquid_template) { Liquid::Template.new } + + before do + allow(Liquid::Template).to receive(:parse).with(template).and_return(liquid_template) + allow(liquid_template).to receive(:render!).and_raise(exception, message) + end + + context 'raises Liquid::MemoryError' do + let(:exception) { Liquid::MemoryError } + let(:message) { 'Liquid error: Memory limits exceeded' } + + it_behaves_like 'raises RenderError', 'Memory limit exceeded while rendering template' + end + + context 'raises Liquid::Error' do + let(:exception) { Liquid::Error } + let(:message) { 'Liquid error: Generic error message' } + + it_behaves_like 'raises RenderError', 'Error rendering query' + end + end + + context 'with template that is expensive to render' do + let(:template) do + '{% assign loop_count = 1000 %}'\ + '{% assign padStr = "0" %}'\ + '{% assign number_to_pad = "1" %}'\ + '{% assign strLength = number_to_pad | size %}'\ + '{% assign padLength = loop_count | minus: strLength %}'\ + '{% if padLength > 0 %}'\ + ' {% assign padded = number_to_pad %}'\ + ' {% for position in (1..padLength) %}'\ + ' {% assign padded = padded | prepend: padStr %}'\ + ' {% endfor %}'\ + ' {{ padded }}'\ + '{% endif %}' + end + + it_behaves_like 'raises RenderError', 'Memory limit exceeded while rendering template' + end + end + end +end |