diff options
author | Kamil Trzcinski <ayufan@ayufan.eu> | 2016-12-20 20:07:59 +0100 |
---|---|---|
committer | Kamil Trzcinski <ayufan@ayufan.eu> | 2016-12-20 20:07:59 +0100 |
commit | 3c61b13efeb52c95d13fbb75fd3016555095276b (patch) | |
tree | bc4ac0b4c818e27a4bdea376f249c0950352b6b6 /spec/models | |
parent | dec1e90e505d9ab9e8b088b6a348f5bec293fed1 (diff) | |
parent | 2bc3084d68ac64fcc31276f4ec5e76f79d6fa296 (diff) | |
download | gitlab-ce-3c61b13efeb52c95d13fbb75fd3016555095276b.tar.gz |
Merge remote-tracking branch 'origin/master' into zj-mattermost-slash-config
Diffstat (limited to 'spec/models')
-rw-r--r-- | spec/models/concerns/reactive_caching_spec.rb | 145 | ||||
-rw-r--r-- | spec/models/environment_spec.rb | 60 | ||||
-rw-r--r-- | spec/models/project_authorization_spec.rb | 25 | ||||
-rw-r--r-- | spec/models/project_services/kubernetes_service_spec.rb | 109 | ||||
-rw-r--r-- | spec/models/project_spec.rb | 12 |
5 files changed, 321 insertions, 30 deletions
diff --git a/spec/models/concerns/reactive_caching_spec.rb b/spec/models/concerns/reactive_caching_spec.rb new file mode 100644 index 00000000000..a0765a264cf --- /dev/null +++ b/spec/models/concerns/reactive_caching_spec.rb @@ -0,0 +1,145 @@ +require 'spec_helper' + +describe ReactiveCaching, caching: true do + include ReactiveCachingHelpers + + class CacheTest + include ReactiveCaching + + self.reactive_cache_key = ->(thing) { ["foo", thing.id] } + + self.reactive_cache_lifetime = 5.minutes + self.reactive_cache_refresh_interval = 15.seconds + + attr_reader :id + + def initialize(id, &blk) + @id = id + @calculator = blk + end + + def calculate_reactive_cache + @calculator.call + end + + def result + with_reactive_cache do |data| + data / 2 + end + end + end + + let(:now) { Time.now.utc } + + around(:each) do |example| + Timecop.freeze(now) { example.run } + end + + let(:calculation) { -> { 2 + 2 } } + let(:cache_key) { "foo:666" } + let(:instance) { CacheTest.new(666, &calculation) } + + describe '#with_reactive_cache' do + before { stub_reactive_cache } + subject(:go!) { instance.result } + + context 'when cache is empty' do + it { is_expected.to be_nil } + + it 'queues a background worker' do + expect(ReactiveCachingWorker).to receive(:perform_async).with(CacheTest, 666) + + go! + end + + it 'updates the cache lifespan' do + go! + + expect(reactive_cache_alive?(instance)).to be_truthy + end + end + + context 'when the cache is full' do + before { stub_reactive_cache(instance, 4) } + + it { is_expected.to eq(2) } + + context 'and expired' do + before { invalidate_reactive_cache(instance) } + it { is_expected.to be_nil } + end + end + end + + describe '#clear_reactive_cache!' do + before do + stub_reactive_cache(instance, 4) + instance.clear_reactive_cache! + end + + it { expect(instance.result).to be_nil } + end + + describe '#exclusively_update_reactive_cache!' do + subject(:go!) { instance.exclusively_update_reactive_cache! } + + context 'when the lease is free and lifetime is not exceeded' do + before { stub_reactive_cache(instance, "preexisting") } + + it 'takes and releases the lease' do + expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return("000000") + expect(Gitlab::ExclusiveLease).to receive(:cancel).with(cache_key, "000000") + + go! + end + + it 'caches the result of #calculate_reactive_cache' do + go! + + expect(read_reactive_cache(instance)).to eq(calculation.call) + end + + it "enqueues a repeat worker" do + expect_reactive_cache_update_queued(instance) + + go! + end + + context 'and #calculate_reactive_cache raises an exception' do + before { stub_reactive_cache(instance, "preexisting") } + let(:calculation) { -> { raise "foo"} } + + it 'leaves the cache untouched' do + expect { go! }.to raise_error("foo") + expect(read_reactive_cache(instance)).to eq("preexisting") + end + + it 'enqueues a repeat worker' do + expect_reactive_cache_update_queued(instance) + + expect { go! }.to raise_error("foo") + end + end + end + + context 'when lifetime is exceeded' do + it 'skips the calculation' do + expect(instance).to receive(:calculate_reactive_cache).never + + go! + end + end + + context 'when the lease is already taken' do + before do + expect_any_instance_of(Gitlab::ExclusiveLease).to receive(:try_obtain).and_return(nil) + end + + it 'skips the calculation' do + expect(instance).to receive(:calculate_reactive_cache).never + + go! + end + end + end +end diff --git a/spec/models/environment_spec.rb b/spec/models/environment_spec.rb index 97cbb093ed2..93eb402e060 100644 --- a/spec/models/environment_spec.rb +++ b/spec/models/environment_spec.rb @@ -1,7 +1,8 @@ require 'spec_helper' describe Environment, models: true do - subject(:environment) { create(:environment) } + let(:project) { create(:empty_project) } + subject(:environment) { create(:environment, project: project) } it { is_expected.to belong_to(:project) } it { is_expected.to have_many(:deployments) } @@ -31,6 +32,8 @@ describe Environment, models: true do end describe '#includes_commit?' do + let(:project) { create(:project) } + context 'without a last deployment' do it "returns false" do expect(environment.includes_commit?('HEAD')).to be false @@ -38,9 +41,6 @@ describe Environment, models: true do end context 'with a last deployment' do - let(:project) { create(:project) } - let(:environment) { create(:environment, project: project) } - let!(:deployment) do create(:deployment, environment: environment, sha: project.commit('master').id) end @@ -65,7 +65,6 @@ describe Environment, models: true do describe '#first_deployment_for' do let(:project) { create(:project) } - let!(:environment) { create(:environment, project: project) } let!(:deployment) { create(:deployment, environment: environment, ref: commit.parent.id) } let!(:deployment1) { create(:deployment, environment: environment, ref: commit.id) } let(:head_commit) { project.commit } @@ -196,6 +195,57 @@ describe Environment, models: true do end end + describe '#has_terminals?' do + subject { environment.has_terminals? } + + context 'when the enviroment is available' do + context 'with a deployment service' do + let(:project) { create(:kubernetes_project) } + + context 'and a deployment' do + let!(:deployment) { create(:deployment, environment: environment) } + it { is_expected.to be_truthy } + end + + context 'but no deployments' do + it { is_expected.to be_falsy } + end + end + + context 'without a deployment service' do + it { is_expected.to be_falsy } + end + end + + context 'when the environment is unavailable' do + let(:project) { create(:kubernetes_project) } + before { environment.stop } + it { is_expected.to be_falsy } + end + end + + describe '#terminals' do + let(:project) { create(:kubernetes_project) } + subject { environment.terminals } + + context 'when the environment has terminals' do + before { allow(environment).to receive(:has_terminals?).and_return(true) } + + it 'returns the terminals from the deployment service' do + expect(project.deployment_service). + to receive(:terminals).with(environment). + and_return(:fake_terminals) + + is_expected.to eq(:fake_terminals) + end + end + + context 'when the environment does not have terminals' do + before { allow(environment).to receive(:has_terminals?).and_return(false) } + it { is_expected.to eq(nil) } + end + end + describe '#slug' do it "is automatically generated" do expect(environment.slug).not_to be_nil diff --git a/spec/models/project_authorization_spec.rb b/spec/models/project_authorization_spec.rb new file mode 100644 index 00000000000..33ef67f97a7 --- /dev/null +++ b/spec/models/project_authorization_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe ProjectAuthorization do + let(:user) { create(:user) } + let(:project1) { create(:empty_project) } + let(:project2) { create(:empty_project) } + + describe '.insert_authorizations' do + it 'inserts the authorizations' do + described_class. + insert_authorizations([[user.id, project1.id, Gitlab::Access::MASTER]]) + + expect(user.project_authorizations.count).to eq(1) + end + + it 'inserts rows in batches' do + described_class.insert_authorizations([ + [user.id, project1.id, Gitlab::Access::MASTER], + [user.id, project2.id, Gitlab::Access::MASTER], + ], 1) + + expect(user.project_authorizations.count).to eq(2) + end + end +end diff --git a/spec/models/project_services/kubernetes_service_spec.rb b/spec/models/project_services/kubernetes_service_spec.rb index 3603602e41d..4f3cd14e941 100644 --- a/spec/models/project_services/kubernetes_service_spec.rb +++ b/spec/models/project_services/kubernetes_service_spec.rb @@ -1,7 +1,29 @@ require 'spec_helper' -describe KubernetesService, models: true do - let(:project) { create(:empty_project) } +describe KubernetesService, models: true, caching: true do + include KubernetesHelpers + include ReactiveCachingHelpers + + let(:project) { create(:kubernetes_project) } + let(:service) { project.kubernetes_service } + + # We use Kubeclient to interactive with the Kubernetes API. It will + # GET /api/v1 for a list of resources the API supports. This must be stubbed + # in addition to any other HTTP requests we expect it to perform. + let(:discovery_url) { service.api_url + '/api/v1' } + let(:discovery_response) { { body: kube_discovery_body.to_json } } + + let(:pods_url) { service.api_url + "/api/v1/namespaces/#{service.namespace}/pods" } + let(:pods_response) { { body: kube_pods_body(kube_pod).to_json } } + + def stub_kubeclient_discover + WebMock.stub_request(:get, discovery_url).to_return(discovery_response) + end + + def stub_kubeclient_pods + stub_kubeclient_discover + WebMock.stub_request(:get, pods_url).to_return(pods_response) + end describe "Associations" do it { is_expected.to belong_to :project } @@ -65,22 +87,15 @@ describe KubernetesService, models: true do end describe '#test' do - let(:project) { create(:kubernetes_project) } - let(:service) { project.kubernetes_service } - let(:discovery_url) { service.api_url + '/api/v1' } - - # JSON response body from Kubernetes GET /api/v1 request - let(:discovery_response) { { "kind" => "APIResourceList", "groupVersion" => "v1", "resources" => [] }.to_json } + before do + stub_kubeclient_discover + end context 'with path prefix in api_url' do let(:discovery_url) { 'https://kubernetes.example.com/prefix/api/v1' } - before do - service.api_url = 'https://kubernetes.example.com/prefix/' - end - it 'tests with the prefix' do - WebMock.stub_request(:get, discovery_url).to_return(body: discovery_response) + service.api_url = 'https://kubernetes.example.com/prefix/' expect(service.test[:success]).to be_truthy expect(WebMock).to have_requested(:get, discovery_url).once @@ -88,17 +103,12 @@ describe KubernetesService, models: true do end context 'with custom CA certificate' do - let(:certificate) { "CA PEM DATA" } - before do - service.update_attributes!(ca_pem: certificate) - end - it 'is added to the certificate store' do - cert = double("certificate") + service.ca_pem = "CA PEM DATA" - expect(OpenSSL::X509::Certificate).to receive(:new).with(certificate).and_return(cert) + cert = double("certificate") + expect(OpenSSL::X509::Certificate).to receive(:new).with(service.ca_pem).and_return(cert) expect_any_instance_of(OpenSSL::X509::Store).to receive(:add_cert).with(cert) - WebMock.stub_request(:get, discovery_url).to_return(body: discovery_response) expect(service.test[:success]).to be_truthy expect(WebMock).to have_requested(:get, discovery_url).once @@ -107,17 +117,15 @@ describe KubernetesService, models: true do context 'success' do it 'reads the discovery endpoint' do - WebMock.stub_request(:get, discovery_url).to_return(body: discovery_response) - expect(service.test[:success]).to be_truthy expect(WebMock).to have_requested(:get, discovery_url).once end end context 'failure' do - it 'fails to read the discovery endpoint' do - WebMock.stub_request(:get, discovery_url).to_return(status: 404) + let(:discovery_response) { { status: 404 } } + it 'fails to read the discovery endpoint' do expect(service.test[:success]).to be_falsy expect(WebMock).to have_requested(:get, discovery_url).once end @@ -156,4 +164,55 @@ describe KubernetesService, models: true do ) end end + + describe '#terminals' do + let(:environment) { build(:environment, project: project, name: "env", slug: "env-000000") } + subject { service.terminals(environment) } + + context 'with invalid pods' do + it 'returns no terminals' do + stub_reactive_cache(service, pods: [ { "bad" => "pod" } ]) + + is_expected.to be_empty + end + end + + context 'with valid pods' do + let(:pod) { kube_pod(app: environment.slug) } + let(:terminals) { kube_terminals(service, pod) } + + it 'returns terminals' do + stub_reactive_cache(service, pods: [ pod, pod, kube_pod(app: "should-be-filtered-out") ]) + + is_expected.to eq(terminals + terminals) + end + end + end + + describe '#calculate_reactive_cache' do + before { stub_kubeclient_pods } + subject { service.calculate_reactive_cache } + + context 'when service is inactive' do + before { service.active = false } + + it { is_expected.to be_nil } + end + + context 'when kubernetes responds with valid pods' do + it { is_expected.to eq(pods: [kube_pod]) } + end + + context 'when kubernetes responds with 500' do + let(:pods_response) { { status: 500 } } + + it { expect { subject }.to raise_error(KubeException) } + end + + context 'when kubernetes responds with 404' do + let(:pods_response) { { status: 404 } } + + it { is_expected.to eq(pods: []) } + end + end end diff --git a/spec/models/project_spec.rb b/spec/models/project_spec.rb index 53b504fdfba..0455cd2fe49 100644 --- a/spec/models/project_spec.rb +++ b/spec/models/project_spec.rb @@ -1458,6 +1458,18 @@ describe Project, models: true do end end + describe '#gitlab_project_import?' do + subject(:project) { build(:project, import_type: 'gitlab_project') } + + it { expect(project.gitlab_project_import?).to be true } + end + + describe '#gitea_import?' do + subject(:project) { build(:project, import_type: 'gitea') } + + it { expect(project.gitea_import?).to be true } + end + describe '#lfs_enabled?' do let(:project) { create(:project) } |