Commit da611499 authored by Mayra Cabrera's avatar Mayra Cabrera

Merge branch 'vij-add-subscription-term-service' into 'master'

Add a new service GitlabSubscriptions::CheckLastTermService [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!56235
parents acd5c23c 7dc271d5
# frozen_string_literal: true
# Service to determine if the given namespace has a future renewal
# created in the CustomersDot application
#
# If there is a problem querying CustomersDot, it assumes there is no
# future renewal
#
# returns true, false
module GitlabSubscriptions
class CheckFutureRenewalService
def initialize(namespace_id:)
@namespace_id = namespace_id
end
def execute
return false unless Feature.enabled?(:gitlab_subscription_future_renewal, default_enabled: :yaml)
future_renewal
end
private
attr_reader :namespace_id
def client
Gitlab::SubscriptionPortal::Client
end
def last_term_request
response = client.subscription_last_term(namespace_id)
if response[:success]
response[:last_term] == false
else
nil
end
end
def cache
Rails.cache
end
def cache_key
"subscription:future_renewal:namespace:#{namespace_id}"
end
def future_renewal
cache.fetch(cache_key, skip_nil: true, expires_in: 1.day) { last_term_request } || false
end
end
end
---
name: gitlab_subscription_future_renewal
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56235
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/324157
milestone: '13.11'
type: development
group: group::utilization
default_enabled: false
...@@ -119,10 +119,16 @@ module Gitlab ...@@ -119,10 +119,16 @@ module Gitlab
subscribable && ((is_admin && subscribable.notify_admins?) || subscribable.notify_users?) subscribable && ((is_admin && subscribable.notify_admins?) || subscribable.notify_users?)
end end
def subscription_future_renewal?
return if self_managed? || namespace.nil?
::GitlabSubscriptions::CheckFutureRenewalService.new(namespace_id: namespace.id).execute
end
def require_notification? def require_notification?
return false if expiring_auto_renew? || ::License.future_dated.present? return false if expiring_auto_renew? || ::License.future_dated.present?
auto_renew_choice_exists? && expired_subscribable_within_notification_window? auto_renew_choice_exists? && expired_subscribable_within_notification_window? && !subscription_future_renewal?
end end
def auto_renew_choice_exists? def auto_renew_choice_exists?
......
...@@ -34,7 +34,7 @@ module Gitlab ...@@ -34,7 +34,7 @@ module Gitlab
) )
if !response[:success] || response.dig(:data, 'errors').present? if !response[:success] || response.dig(:data, 'errors').present?
return { success: false, errors: response.dig(:data, 'errors') } return error(response.dig(:data, 'errors'))
end end
response = response.dig(:data, 'data', 'cloudActivationActivate') response = response.dig(:data, 'data', 'cloudActivationActivate')
...@@ -42,7 +42,7 @@ module Gitlab ...@@ -42,7 +42,7 @@ module Gitlab
if response['errors'].blank? if response['errors'].blank?
{ success: true, license_key: response['licenseKey'] } { success: true, license_key: response['licenseKey'] }
else else
{ success: false, errors: response['errors'] } error(response['errors'])
end end
end end
...@@ -71,7 +71,7 @@ module Gitlab ...@@ -71,7 +71,7 @@ module Gitlab
free_upgrade_plan_id: free_upgrade free_upgrade_plan_id: free_upgrade
} }
else else
{ success: false } error
end end
end end
...@@ -90,7 +90,8 @@ module Gitlab ...@@ -90,7 +90,8 @@ module Gitlab
if response['errors'].present? if response['errors'].present?
exception = SubscriptionPortal::Client::ResponseError.new("Received an error from CustomerDot") exception = SubscriptionPortal::Client::ResponseError.new("Received an error from CustomerDot")
Gitlab::ErrorTracking.track_and_raise_for_dev_exception(exception, query: query, response: response) Gitlab::ErrorTracking.track_and_raise_for_dev_exception(exception, query: query, response: response)
return { success: false }
return error
end end
{ {
...@@ -100,6 +101,26 @@ module Gitlab ...@@ -100,6 +101,26 @@ module Gitlab
} }
end end
def subscription_last_term(namespace_id)
return error('Must provide a namespace ID') unless namespace_id
query = <<~GQL
query($namespaceId: ID!) {
subscription(namespaceId: $namespaceId) {
lastTerm
}
}
GQL
response = execute_graphql_query({ query: query, variables: { namespaceId: namespace_id } })
if response[:success]
{ success: true, last_term: response.dig(:data, 'data', 'subscription', 'lastTerm') }
else
error(response.dig(:data, :errors))
end
end
private private
def execute_graphql_query(params) def execute_graphql_query(params)
...@@ -115,6 +136,13 @@ module Gitlab ...@@ -115,6 +136,13 @@ module Gitlab
def graphql_endpoint def graphql_endpoint
EE::SUBSCRIPTIONS_GRAPHQL_URL EE::SUBSCRIPTIONS_GRAPHQL_URL
end end
def error(errors = nil)
{
success: false,
errors: errors
}.compact
end
end end
end end
end end
......
...@@ -110,7 +110,15 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do ...@@ -110,7 +110,15 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do
end end
context 'with namespace' do context 'with namespace' do
let(:namespace) { double(:namespace, name: 'No Limit Records') } let(:has_future_renewal) { false }
let_it_be(:namespace) { create(:group, name: 'No Limit Records') }
before do
allow_next_instance_of(GitlabSubscriptions::CheckFutureRenewalService, namespace_id: namespace.id) do |service|
allow(service).to receive(:execute).and_return(has_future_renewal)
end
end
it 'has an expiration blocking message' do it 'has an expiration blocking message' do
expect(subject).to include("You didn't renew your subscription for No Limit Records so it was downgraded to the free plan") expect(subject).to include("You didn't renew your subscription for No Limit Records so it was downgraded to the free plan")
...@@ -127,6 +135,12 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do ...@@ -127,6 +135,12 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do
expect(subject).to include("We tried to automatically renew your subscription for No Limit Records on 2020-03-01 but something went wrong so your subscription was downgraded to the free plan. Don't worry, your data is safe. We suggest you check your payment method and get in touch with our support team (support@gitlab.com). They'll gladly help with your subscription renewal.") expect(subject).to include("We tried to automatically renew your subscription for No Limit Records on 2020-03-01 but something went wrong so your subscription was downgraded to the free plan. Don't worry, your data is safe. We suggest you check your payment method and get in touch with our support team (support@gitlab.com). They'll gladly help with your subscription renewal.")
end end
end end
context 'when there is a future renewal' do
let(:has_future_renewal) { true }
it { is_expected.to be_nil }
end
end end
end end
...@@ -184,7 +198,15 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do ...@@ -184,7 +198,15 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do
context 'with namespace' do context 'with namespace' do
using RSpec::Parameterized::TableSyntax using RSpec::Parameterized::TableSyntax
let(:namespace) { double(:namespace, name: 'No Limit Records') } let(:has_future_renewal) { false }
let_it_be(:namespace) { create(:group, name: 'No Limit Records') }
before do
allow_next_instance_of(GitlabSubscriptions::CheckFutureRenewalService, namespace_id: namespace.id) do |service|
allow(service).to receive(:execute).and_return(has_future_renewal)
end
end
where plan: %w(gold ultimate) where plan: %w(gold ultimate)
...@@ -227,6 +249,12 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do ...@@ -227,6 +249,12 @@ RSpec.describe Gitlab::ExpiringSubscriptionMessage do
expect(subject).to be nil expect(subject).to be nil
end end
end end
context 'when there is a future renewal' do
let(:has_future_renewal) { true }
it { is_expected.to be_nil }
end
end end
end end
......
...@@ -182,4 +182,66 @@ RSpec.describe Gitlab::SubscriptionPortal::Clients::Graphql do ...@@ -182,4 +182,66 @@ RSpec.describe Gitlab::SubscriptionPortal::Clients::Graphql do
end end
end end
end end
describe '#subscription_last_term' do
let(:query) do
<<~GQL
query($namespaceId: ID!) {
subscription(namespaceId: $namespaceId) {
lastTerm
}
}
GQL
end
it 'returns success' do
expected_args = {
query: query,
variables: {
namespaceId: 'namespace-id'
}
}
expected_response = {
success: true,
data: {
"data" => {
"subscription" => {
"lastTerm" => true
}
}
}
}
expect(client).to receive(:execute_graphql_query).with(expected_args).and_return(expected_response)
result = client.subscription_last_term('namespace-id')
expect(result).to eq({ success: true, last_term: true })
end
it 'returns failure' do
error = "some error"
expect(client).to receive(:execute_graphql_query).and_return(
{
success: false,
data: {
errors: error
}
}
)
result = client.subscription_last_term('failing-namespace-id')
expect(result).to eq({ success: false, errors: error })
end
context 'with no namespace_id' do
it 'returns failure' do
expect(client).not_to receive(:execute_graphql_query)
expect(client.subscription_last_term(nil)).to eq({ success: false, errors: 'Must provide a namespace ID' })
end
end
end
end end
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSubscriptions::CheckFutureRenewalService, :use_clean_rails_memory_store_caching do
using RSpec::Parameterized::TableSyntax
describe '#execute' do
let(:namespace) { create(:namespace) }
let(:namespace_id) { namespace.id }
let(:cache_key) { "subscription:future_renewal:namespace:#{namespace_id}" }
subject(:execute_service) { described_class.new(namespace_id: namespace_id).execute }
where(:in_last_term, :expected_response) do
true | false
false | true
end
with_them do
let(:response) { { success: true, last_term: in_last_term } }
before do
allow(Gitlab::SubscriptionPortal::Client).to receive(:subscription_last_term).and_return(response)
end
it 'returns the correct value' do
expect(execute_service).to eq expected_response
end
it 'caches the query response' do
expect(Rails.cache).to receive(:fetch).with(cache_key, skip_nil: true, expires_in: 1.day).and_call_original
execute_service
end
end
context 'with an unsuccessful CustomersDot query' do
it 'assumes no future renewal' do
allow(Gitlab::SubscriptionPortal::Client).to receive(:subscription_last_term).and_return({
success: false
})
expect(execute_service).to be false
end
end
context 'when the `gitlab_subscription_future_renewal` feature flag is disabled' do
before do
stub_feature_flags(gitlab_subscription_future_renewal: false)
end
it { is_expected.to be false }
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