engines/scc_proxy/spec/requests/api/connect/v3/systems/products_controller_spec.rb

Summary

Maintainability
B
4 hrs
Test Coverage
require 'rails_helper'

# rubocop:disable RSpec/NestedGroups

describe Api::Connect::V3::Systems::ProductsController, type: :request do
  include_context 'auth header', :system, :login, :password
  include_context 'version header', 3

  let(:url) { connect_systems_products_url }
  let(:headers) { auth_header.merge(version_header) }
  let(:product) { FactoryBot.create(:product, :product_sles, :with_mirrored_repositories, :with_mirrored_extensions) }
  let(:product_sap) { FactoryBot.create(:product, :product_sles_sap, :with_mirrored_repositories, :with_mirrored_extensions) }

  let(:payload) do
    {
      identifier: product.identifier,
      version: product.version,
      arch: product.arch
    }
  end
  let(:payload_byos) do
    {
      identifier: product.identifier,
      version: product.version,
      arch: product.arch,
      email: 'foo',
      token: 'bar'
    }
  end

  describe '#activate' do
    let(:plugin_double) { instance_double('InstanceVerification::Providers::Example') }


    context 'when system has hw_info' do
      let(:instance_data) { '<document>{"instanceId": "dummy_instance_data"}</document>' }
      let(:new_system_token) { 'BBBBBBBB-BBBB-4BBB-9BBB-BBBBBBBBBBBB' }
      let(:system) { FactoryBot.create(:system, :with_system_information, instance_data: instance_data) }
      let(:serialized_service_json) do
        V3::ServiceSerializer.new(
          product.service,
          base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s
        ).to_json
      end

      let(:serialized_service_sap_json) do
        V3::ServiceSerializer.new(
          product_sap.service,
          base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s
        ).to_json
      end

      context 'when system is connected to SCC' do
        let(:system) do
          FactoryBot.create(:system, :byos, :with_system_information, instance_data: instance_data,
            system_token: new_system_token)
        end
        let(:scc_activate_url) { 'https://scc.suse.com/connect/systems/products' }
        let(:subscription_response) do
          {
            id: 4206714,
            regcode: 'bar',
            name: 'SUSE Employee subscription for SUSE Linux Enterprise Server for SAP Applications',
            type: 'internal',
            status: 'ACTIVE',
            starts_at: '2019-03-20T09:48:52.658Z',
            expires_at: '2024-03-20T09:48:52.658Z',
            system_limit: '100',
            systems_count: '156',
            virtual_count: nil,
            product_classes: [
              'AiO',
              '7261',
              'SLE-HAE-X86',
              '7261-BETA',
              'SLE-HAE-X86-BETA',
              'AiO-BETA',
              '7261-ALPHA',
              'SLE-HAE-X86-ALPHA',
              'AiO-ALPHA'
            ],
            product_ids: [
              1959,
              1421
            ],
            skus: [],
            systems: [
              {
                id: 3021957,
                login: 'SCC_foo',
                password: '5ee7273ac6ac4d7f',
                last_seen_at: '2019-03-20T14:01:05.424Z'
              }
            ]
          }
        end

        before do
          allow(plugin_double).to(
            receive(:instance_valid?)
              .and_raise(InstanceVerification::Exception, 'Custom plugin error')
          )
        end

        context 'with a valid registration code' do
          before do
            stub_request(:post, scc_activate_url)
              .to_return(
                status: 201,
                body: '{"id": "bar"}',
                headers: {}
              )
          end

          it 'renders service JSON' do
            expect(Rails.cache).to receive(:write).twice.with(
              ['127.0.0.1', system.login, product.id].join('-'), true, expires_in: 24.hours
              )
            post url, params: payload_byos, headers: headers
            expect(response.body).to eq(serialized_service_json)
          end
        end

        context 'with a not valid registration code' do
          before do
            stub_request(:post, scc_activate_url)
              .to_return(
                status: 401,
                body: '{"error": "No product found on SCC for: foo bar x86_64 json api"}',
                headers: {}
              )
            post url, params: payload_byos, headers: headers
          end

          it 'renders an error with exception details' do
            data = JSON.parse(response.body)
            expect(data['error']).to include('No product found on SCC')
            expect(data['error']).not_to include('json api')
          end
        end

        context 'with different system_tokens' do
          let(:system2) do
            FactoryBot.create(:system, :byos, :with_system_information, instance_data: instance_data,
              system_token: 'foo')
          end

          before do
            allow(System).to receive(:get_by_credentials).and_return([system, system2])
            allow(plugin_double).to(
              receive(:instance_valid?)
                .and_raise(InstanceVerification::Exception, 'Custom plugin error')
            )
            stub_request(:post, scc_activate_url)
              .to_return(
                status: 201,
                body: '{"id": "bar"}',
                headers: {}
              )
            post url, params: payload_byos, headers: headers
          end

          it 'renders service JSON' do
            expect(response.body).to eq(serialized_service_json)
          end
        end

        context 'with duplicated system_tokens' do
          let(:system3) do
            FactoryBot.create(:system, :byos, :with_system_information, instance_data: instance_data,
              system_token: 'foo')
          end

          before do
            system3 = system
            system3.save!
            allow(System).to receive(:get_by_credentials).and_return([system, system3])
            allow(plugin_double).to(
              receive(:instance_valid?)
                .and_raise(InstanceVerification::Exception, 'Custom plugin error')
            )
            headers['System-Token'] = 'foo'
            stub_request(:post, scc_activate_url)
              .to_return(
                status: 201,
                body: '{"id": "bar"}',
                headers: {}
              )
            post url, params: payload_byos, headers: headers
          end

          it 'renders service JSON' do
            expect(response.body).to eq(serialized_service_json)
          end
        end
      end
    end
  end

  context 'when activating extensions' do
    let(:instance_data) { 'dummy_instance_data' }
    let(:system) do
      FactoryBot.create(
        :system, :with_system_information, :with_activated_product, product: base_product, instance_data: instance_data
      )
    end
    let(:serialized_service_json) do
      V3::ServiceSerializer.new(
        product.service,
        base_url: URI::HTTP.build({ scheme: response.request.scheme, host: response.request.host }).to_s
      ).to_json
    end
    let(:scc_activate_url) { 'https://scc.suse.com/connect/systems/products' }

    before do
      FactoryBot.create(:subscription, product_classes: product_classes)
      stub_request(:post, scc_activate_url)
        .to_return(
          status: 401,
          body: 'bar',
          headers: {}
        )

      post url, params: payload, headers: headers
    end

    context 'when the extension is not free' do
      let(:base_product) { FactoryBot.create(:product, :with_mirrored_repositories) }

      context 'when a suitable subscription is not found' do
        let(:product) do
          FactoryBot.create(
            :product, :with_mirrored_repositories, :extension, free: false, base_products: [base_product]
          )
        end
        let(:product_classes) { [base_product.product_class] }

        it 'reports an error' do
          data = JSON.parse(response.body)
          expect(data['error']).to eq('Instance verification failed: The product is not available for this instance')
          expect(InstanceVerification::Providers::Example).not_to receive(:new)
        end
      end

      context 'when a suitable subscription is found' do
        let(:product) do
          FactoryBot.create(
            :product, :with_mirrored_repositories, :extension, free: false, base_products: [base_product]
          )
        end
        let(:product_classes) { [base_product.product_class, product.product_class] }

        it 'returns service JSON' do
          expect(response.body).to eq(serialized_service_json)
        end
      end
    end

    context 'when the extension is free' do
      let(:base_product) { FactoryBot.create(:product, :with_mirrored_repositories) }
      let(:product) do
        FactoryBot.create(
          :product, :with_mirrored_repositories, :extension, free: true, base_products: [base_product]
        )
      end
      let(:product_classes) { [base_product.product_class] }

      it 'returns service JSON' do
        expect(response.body).to eq(serialized_service_json)
      end
    end


    context 'when the base product subscription is missing' do
      let(:base_product) { FactoryBot.create(:product, :with_mirrored_repositories) }
      let(:product) do
        FactoryBot.create(
          :product, :with_mirrored_repositories, :extension, free: false, base_products: [base_product]
        )
      end
      let(:product_classes) { [] }

      it 'reports an error' do
        data = JSON.parse(response.body)
        expect(data['error']).to eq('Unexpected instance verification error has occurred')
      end
    end
  end
end
# rubocop:enable RSpec/NestedGroups