Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module WorkItems
  module Widgets
    module CurrentUserTodosService
      class UpdateService < WorkItems::Widgets::BaseService
        def before_update_in_transaction(params:)
          return unless params.present? && params.key?(:action)

          case params[:action]
          when "add"
            add_todo
          when "mark_as_done"
            mark_as_done(params[:todo_id])
          end
        end

        private

        def add_todo
          return unless has_permission?(:create_todo)

          TodoService.new.mark_todo(work_item, current_user)&.first
        end

        def mark_as_done(todo_id)
          todos = TodosFinder.new(current_user, state: :pending, target_id: work_item.id).execute
          todos = todo_id ? todos.id_in(todo_id) : todos

          return if todos.empty?

          TodoService.new.resolve_todos(todos, current_user, resolved_by_action: :api_done)
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe WorkItems::Widgets::CurrentUserTodosService::UpdateService, feature_category: :team_planning do
  let_it_be(:reporter) { create(:user) }
  let_it_be(:project) { create(:project, :private) }
  let_it_be(:current_user) { reporter }
  let_it_be(:work_item) { create(:work_item, project: project) }

  let_it_be(:pending_todo1) do
    create(:todo, state: :pending, target: work_item, target_type: work_item.class.name, user: current_user)
  end

  let_it_be(:pending_todo2) do
    create(:todo, state: :pending, target: work_item, target_type: work_item.class.name, user: current_user)
  end

  let_it_be(:done_todo) do
    create(:todo, state: :done, target: work_item, target_type: work_item.class.name, user: current_user)
  end

  let_it_be(:other_work_item_todo) { create(:todo, state: :pending, target: create(:work_item), user: current_user) }
  let_it_be(:other_user_todo) do
    create(:todo, state: :pending, target: work_item, target_type: work_item.class.name, user: create(:user))
  end

  let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::CurrentUserTodos) } }

  before_all do
    project.add_reporter(reporter)
  end

  describe '#before_update_in_transaction' do
    subject do
      described_class.new(widget: widget, current_user: current_user)
        .before_update_in_transaction(params: params)
    end

    context 'when adding a todo' do
      let(:params) { { action: "add" } }

      context 'when user has no access' do
        let(:current_user) { create(:user) }

        it 'does add a todo' do
          expect { subject }.not_to change { Todo.count }
        end
      end

      context 'when user has access' do
        let(:params) { { action: "add" } }

        it 'creates a new todo for the user and the work item' do
          expect { subject }.to change { current_user.todos.count }.by(1)

          todo = current_user.todos.last

          expect(todo.target.id).to eq(work_item.id)
          expect(todo).to be_pending
        end
      end
    end

    context 'when marking as done' do
      let(:params) { { action: "mark_as_done" } }

      context 'when user has no access' do
        let(:current_user) { create(:user) }

        it 'does not change todo status' do
          subject

          expect(pending_todo1.reload).to be_pending
          expect(pending_todo2.reload).to be_pending
          expect(other_work_item_todo.reload).to be_pending
          expect(other_user_todo.reload).to be_pending
        end
      end

      context 'when resolving all todos of the work item', :aggregate_failures do
        it 'resolves todos of the user for the work item' do
          subject

          expect(pending_todo1.reload).to be_done
          expect(pending_todo2.reload).to be_done
          expect(other_work_item_todo.reload).to be_pending
          expect(other_user_todo.reload).to be_pending
        end
      end

      context 'when resolving a specific todo', :aggregate_failures do
        let(:params) { { action: "mark_as_done", todo_id: pending_todo1.id } }

        it 'resolves todos of the user for the work item' do
          subject

          expect(pending_todo1.reload).to be_done
          expect(pending_todo2.reload).to be_pending
          expect(other_work_item_todo.reload).to be_pending
          expect(other_user_todo.reload).to be_pending
        end
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module WorkItems
  module Widgets
    module HierarchyService
      class UpdateService < WorkItems::Widgets::HierarchyService::BaseService
        INVALID_RELATIVE_POSITION_ERROR = 'Relative position is not valid.'
        CHILDREN_REORDERING_ERROR = 'Relative position cannot be combined with childrenIds.'
        UNRELATED_ADJACENT_HIERARCHY_ERROR = 'The adjacent work item\'s parent must match the new parent work item.'
        INVALID_ADJACENT_PARENT_ERROR = 'The adjacent work item\'s parent must match the current parent work item.'

        def before_update_in_transaction(params:)
          return unless params.present?

          if positioning?(params)
            service_response!(handle_positioning(params))
          else
            service_response!(handle_hierarchy_changes(params))
          end
        end

        private

        def handle_positioning(params)
          validate_positioning!(params)

          arguments = {
            target_issuable: work_item,
            adjacent_work_item: params.delete(:adjacent_work_item),
            relative_position: params.delete(:relative_position)
          }
          work_item_parent = params.delete(:parent) || work_item.work_item_parent
          ::WorkItems::ParentLinks::ReorderService.new(work_item_parent, current_user, arguments).execute
        end

        def positioning?(params)
          params[:relative_position].present? || params[:adjacent_work_item].present?
        end

        def error!(message)
          service_response!(error(_(message)))
        end

        def validate_positioning!(params)
          error!(INVALID_RELATIVE_POSITION_ERROR) if incomplete_relative_position?(params)
          error!(CHILDREN_REORDERING_ERROR) if positioning_children?(params)
          error!(UNRELATED_ADJACENT_HIERARCHY_ERROR) if unrelated_adjacent_hierarchy?(params)
          error!(INVALID_ADJACENT_PARENT_ERROR) if invalid_adjacent_parent?(params)
        end

        def positioning_children?(params)
          params.key?(:children)
        end

        def incomplete_relative_position?(params)
          params[:adjacent_work_item].blank? || params[:relative_position].blank?
        end

        def unrelated_adjacent_hierarchy?(params)
          return false if params[:parent].blank?

          params[:parent] != params[:adjacent_work_item].work_item_parent
        end

        def invalid_adjacent_parent?(params)
          return false if params[:parent].present?

          work_item.work_item_parent != params[:adjacent_work_item].work_item_parent
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe WorkItems::Widgets::HierarchyService::UpdateService, feature_category: :portfolio_management do
  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project) }

  let_it_be(:work_item) { create(:work_item, project: project) }
  let_it_be(:parent_work_item) { create(:work_item, project: project) }
  let_it_be(:child_work_item) { create(:work_item, :task, project: project) }
  let_it_be(:existing_link) { create(:parent_link, work_item: child_work_item, work_item_parent: work_item) }

  let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Hierarchy) } }
  let(:not_found_error) { 'No matching work item found. Make sure that you are adding a valid work item ID.' }

  shared_examples 'raises a WidgetError' do |message|
    it { expect { subject }.to raise_error(described_class::WidgetError, message) }
  end

  shared_examples 'raises a WidgetError with message' do
    let(:message) { not_found_error }

    it { expect { subject }.to raise_error(described_class::WidgetError, message) }
  end

  describe '#update' do
    subject { described_class.new(widget: widget, current_user: user).before_update_in_transaction(params: params) }

    context 'when parent and children params are present' do
      let(:params) { { parent: parent_work_item, children: [child_work_item] } }

      it_behaves_like 'raises a WidgetError', 'A Work Item can be a parent or a child, but not both.'
    end

    context 'when invalid params are present' do
      let(:params) { { other_parent: parent_work_item } }

      it_behaves_like 'raises a WidgetError', 'One or more arguments are invalid: other_parent.'
    end

    context 'when relative position params are incomplete' do
      context 'when only adjacent_work_item is present' do
        let(:params) do
          { parent: parent_work_item, adjacent_work_item: child_work_item }
        end

        it_behaves_like 'raises a WidgetError', described_class::INVALID_RELATIVE_POSITION_ERROR
      end

      context 'when only relative_position is present' do
        let(:params) do
          { parent: parent_work_item, relative_position: 'AFTER' }
        end

        it_behaves_like 'raises a WidgetError', described_class::INVALID_RELATIVE_POSITION_ERROR
      end
    end

    context 'when updating children' do
      let_it_be(:child_work_item2) { create(:work_item, :task, project: project) }
      let_it_be(:child_work_item3) { create(:work_item, :task, project: project) }
      let_it_be(:child_work_item4) { create(:work_item, :task, project: project) }

      context 'when user has insufficient permissions to link work items' do
        let(:params) { { children: [child_work_item4] } }

        it_behaves_like 'raises a WidgetError with message' do
          let(:message) { not_found_error }
        end
      end

      context 'when user has sufficient permissions to link work item' do
        before do
          project.add_developer(user)
        end

        context 'with valid children params' do
          let(:params) { { children: [child_work_item2, child_work_item3] } }

          it 'correctly sets work item parent' do
            subject

            expect(work_item.reload.work_item_children)
              .to contain_exactly(child_work_item, child_work_item2, child_work_item3)
          end

          context 'when relative_position and adjacent_work_item are given' do
            context 'with BEFORE value' do
              let(:params) do
                { children: [child_work_item3], relative_position: 'BEFORE', adjacent_work_item: child_work_item }
              end

              it_behaves_like 'raises a WidgetError', described_class::CHILDREN_REORDERING_ERROR
            end

            context 'with AFTER value' do
              let(:params) do
                { children: [child_work_item2], relative_position: 'AFTER', adjacent_work_item: child_work_item }
              end

              it_behaves_like 'raises a WidgetError', described_class::CHILDREN_REORDERING_ERROR
            end
          end
        end

        context 'when child is already assigned' do
          let(:params) { { children: [child_work_item] } }

          it_behaves_like 'raises a WidgetError', 'Work item(s) already assigned'
        end

        context 'when child type is invalid' do
          let_it_be(:child_issue) { create(:work_item, project: project) }

          let(:params) { { children: [child_issue] } }

          it_behaves_like 'raises a WidgetError with message' do
            let(:message) { "#{child_issue.to_reference} cannot be added: is not allowed to add this type of parent" }
          end
        end
      end
    end

    context 'when updating parent' do
      let_it_be(:work_item) { create(:work_item, :task, project: project) }

      let(:params) { { parent: parent_work_item } }

      context 'when user has insufficient permissions to link work items' do
        it_behaves_like 'raises a WidgetError with message' do
          let(:message) { not_found_error }
        end
      end

      context 'when user has sufficient permissions to link work item' do
        before do
          project.add_developer(user)
        end

        it 'correctly sets new parent' do
          expect(subject[:status]).to eq(:success)
          expect(work_item.work_item_parent).to eq(parent_work_item)
        end

        context 'when parent is nil' do
          let(:params) { { parent: nil } }

          it 'removes the work item parent if present' do
            work_item.update!(work_item_parent: parent_work_item)

            expect do
              subject
              work_item.reload
            end.to change(work_item, :work_item_parent).from(parent_work_item).to(nil)
          end

          it 'returns success status if parent not present', :aggregate_failures do
            work_item.update!(work_item_parent: nil)

            expect(subject[:status]).to eq(:success)
            expect(work_item.reload.work_item_parent).to be_nil
          end
        end

        context 'when type is invalid' do
          let_it_be(:parent_task) { create(:work_item, :task, project: project) }

          let(:params) { { parent: parent_task } }

          it_behaves_like 'raises a WidgetError with message' do
            let(:message) { "#{work_item.to_reference} cannot be added: is not allowed to add this type of parent" }
          end
        end

        context 'with positioning arguments' do
          let_it_be_with_reload(:adjacent) { create(:work_item, :task, project: project) }

          let_it_be_with_reload(:adjacent_link) do
            create(:parent_link, work_item: adjacent, work_item_parent: parent_work_item)
          end

          let(:params) { { parent: parent_work_item, adjacent_work_item: adjacent, relative_position: 'AFTER' } }

          it 'correctly sets new parent and position' do
            expect(subject[:status]).to eq(:success)
            expect(work_item.work_item_parent).to eq(parent_work_item)
            expect(work_item.parent_link.relative_position).to be > adjacent_link.relative_position
          end

          context 'when other hierarchy adjacent is provided' do
            let_it_be(:other_hierarchy_adjacent) { create(:parent_link).work_item }

            let(:params) do
              { parent: parent_work_item, adjacent_work_item: other_hierarchy_adjacent, relative_position: 'AFTER' }
            end

            it_behaves_like 'raises a WidgetError', described_class::UNRELATED_ADJACENT_HIERARCHY_ERROR
          end
        end
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module WorkItems
  module Widgets
    module HierarchyService
      class CreateService < WorkItems::Widgets::HierarchyService::BaseService
        def after_create_in_transaction(params:)
          return unless params.present?

          service_response!(handle_hierarchy_changes(params))
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe WorkItems::Widgets::HierarchyService::CreateService, feature_category: :portfolio_management do
  let_it_be(:user) { create(:user) }
  let_it_be(:project) { create(:project) }
  let_it_be(:parent_item) { create(:work_item, project: project) }

  let(:widget) { parent_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Hierarchy) } }

  shared_examples 'raises a WidgetError' do
    it { expect { subject }.to raise_error(described_class::WidgetError, message) }
  end

  before_all do
    project.add_developer(user)
  end

  describe '#create' do
    subject { described_class.new(widget: widget, current_user: user).after_create_in_transaction(params: params) }

    context 'when invalid params are present' do
      let(:params) { { other_parent: 'parent_work_item' } }

      it_behaves_like 'raises a WidgetError' do
        let(:message) { 'One or more arguments are invalid: other_parent.' }
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module WorkItems
  module Widgets
    module NotificationsService
      class UpdateService < WorkItems::Widgets::BaseService
        def before_update_in_transaction(params:)
          return unless params.present? && params.key?(:subscribed)
          return unless has_permission?(:update_subscription)

          update_subscription(work_item, params)
        end

        private

        def update_subscription(work_item, subscription_params)
          work_item.set_subscription(
            current_user,
            subscription_params[:subscribed],
            work_item.project
          )
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe WorkItems::Widgets::NotificationsService::UpdateService, feature_category: :team_planning do
  let_it_be(:group) { create(:group) }
  let_it_be(:project) { create(:project, :private, group: group) }
  let_it_be(:guest) { create(:user).tap { |u| project.add_guest(u) } }
  let_it_be(:author) { create(:user).tap { |u| project.add_guest(u) } }
  let_it_be_with_reload(:work_item) { create(:work_item, project: project, author: author) }
  let_it_be(:current_user) { guest }

  let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Notifications) } }
  let(:service) { described_class.new(widget: widget, current_user: current_user) }

  describe '#before_update_in_transaction' do
    let(:expected) { params[:subscribed] }

    subject(:update_notifications) { service.before_update_in_transaction(params: params) }

    shared_examples 'failing to update subscription' do
      context 'when user is subscribed with a subscription record' do
        let_it_be(:subscription) { create_subscription(:subscribed) }

        it "does not update the work item's subscription" do
          expect do
            update_notifications
            subscription.reload
          end.to not_change { subscription.subscribed }
            .and(not_change { work_item.subscribed?(current_user, project) })
        end
      end

      context 'when user is subscribed by being a participant' do
        let_it_be(:current_user) { author }

        it 'does not create subscription record or change subscription state' do
          expect { update_notifications }
            .to not_change { Subscription.count }
            .and(not_change { work_item.subscribed?(current_user, project) })
        end
      end
    end

    shared_examples 'updating notifications subscription successfully' do
      it 'updates existing subscription record' do
        expect do
          update_notifications
          subscription.reload
        end.to change { subscription.subscribed }.to(expected)
          .and(change { work_item.subscribed?(current_user, project) }.to(expected))
      end
    end

    context 'when update fails' do
      context 'when user lack update_subscription permissions' do
        let_it_be(:params) { { subscribed: false } }

        before do
          allow(Ability).to receive(:allowed?).and_call_original
          allow(Ability).to receive(:allowed?)
            .with(current_user, :update_subscription, work_item)
            .and_return(false)
        end

        it_behaves_like 'failing to update subscription'
      end

      context 'when notifications params are not present' do
        let_it_be(:params) { {} }

        it_behaves_like 'failing to update subscription'
      end
    end

    context 'when update is successful' do
      context 'when subscribing' do
        let_it_be(:subscription) { create_subscription(:unsubscribed) }
        let(:params) { { subscribed: true } }

        it_behaves_like 'updating notifications subscription successfully'
      end

      context 'when unsubscribing' do
        let(:params) { { subscribed: false } }

        context 'when user is subscribed with a subscription record' do
          let_it_be(:subscription) { create_subscription(:subscribed) }

          it_behaves_like 'updating notifications subscription successfully'
        end

        context 'when user is subscribed by being a participant' do
          let_it_be(:current_user) { author }

          it 'creates a subscription with expected value' do
            expect { update_notifications }
              .to change { Subscription.count }.by(1)
              .and(change { work_item.subscribed?(current_user, project) }.to(expected))

            expect(Subscription.last.subscribed).to eq(expected)
          end
        end
      end
    end
  end

  def create_subscription(state)
    create(
      :subscription,
      project: project,
      user: current_user,
      subscribable: work_item,
      subscribed: (state == :subscribed)
    )
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module WorkItems
  module Widgets
    module DescriptionService
      class UpdateService < WorkItems::Widgets::BaseService
        def before_update_callback(params: {})
          params[:description] = nil if new_type_excludes_widget?

          return unless params.present? && params.key?(:description)
          return unless has_permission?(:update_work_item)

          work_item.description = params[:description]
          work_item.assign_attributes(last_edited_at: Time.current, last_edited_by: current_user)
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe WorkItems::Widgets::DescriptionService::UpdateService, feature_category: :portfolio_management do
  let_it_be(:random_user) { create(:user) }
  let_it_be(:author) { create(:user) }
  let_it_be(:guest) { create(:user) }
  let_it_be(:reporter) { create(:user) }
  let_it_be(:project) { create(:project, :public) }

  let(:params) { { description: 'updated description' } }
  let(:current_user) { author }
  let(:work_item) do
    create(
      :work_item,
      author: author,
      project: project,
      description: 'old description',
      last_edited_at: Date.yesterday,
      last_edited_by: random_user
    )
  end

  let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Description) } }

  describe '#update' do
    let(:service) { described_class.new(widget: widget, current_user: current_user) }

    subject(:before_update_callback) { service.before_update_callback(params: params) }

    shared_examples 'sets work item description' do
      it 'correctly sets work item description value' do
        subject

        expect(work_item.description).to eq(params[:description])
        expect(work_item.last_edited_by).to eq(current_user)
        expect(work_item.last_edited_at).to be_within(2.seconds).of(Time.current)
      end
    end

    shared_examples 'does not set work item description' do
      it 'does not change work item description value' do
        subject

        expect(work_item.description).to eq('old description')
        expect(work_item.last_edited_by).to eq(random_user)
        expect(work_item.last_edited_at).to eq(Date.yesterday)
      end
    end

    context 'when user has permission to update description' do
      context 'when user is work item author' do
        let(:current_user) { author }

        it_behaves_like 'sets work item description'
      end

      context 'when user is a project reporter' do
        let(:current_user) { reporter }

        before do
          project.add_reporter(reporter)
        end

        it_behaves_like 'sets work item description'
      end

      context 'when description is nil' do
        let(:current_user) { author }
        let(:params) { { description: nil } }

        it_behaves_like 'sets work item description'
      end

      context 'when description is empty' do
        let(:current_user) { author }
        let(:params) { { description: '' } }

        it_behaves_like 'sets work item description'
      end

      context 'when description param is not present' do
        let(:params) { {} }

        it_behaves_like 'does not set work item description'
      end

      context 'when widget does not exist in new type' do
        let(:current_user) { author }
        let(:params) { {} }

        before do
          allow(service).to receive(:new_type_excludes_widget?).and_return(true)
          work_item.update!(description: 'test')
        end

        it "resets the work item's description" do
          expect { before_update_callback }
            .to change { work_item.description }
            .from('test')
            .to(nil)
        end
      end
    end

    context 'when user does not have permission to update description' do
      context 'when user is a project guest' do
        let(:current_user) { guest }

        before do
          project.add_guest(guest)
        end

        it_behaves_like 'does not set work item description'
      end

      context 'with private project' do
        let_it_be(:project) { create(:project) }

        context 'when user is work item author' do
          let(:current_user) { author }

          it_behaves_like 'does not set work item description'
        end
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module WorkItems
  module Widgets
    module LabelsService
      class UpdateService < WorkItems::Widgets::BaseService
        def prepare_update_params(params: {})
          if new_type_excludes_widget?
            params[:remove_label_ids] = @work_item.labels.map(&:id)
            params[:add_label_ids] = []
          end

          return if params.blank?
          return unless has_permission?(:set_work_item_metadata)

          service_params.merge!(params.slice(:add_label_ids, :remove_label_ids))
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe WorkItems::Widgets::LabelsService::UpdateService, feature_category: :team_planning do
  let_it_be(:group) { create(:group) }
  let_it_be(:project) { create(:project, group: group) }
  let_it_be(:label1) { create(:label, project: project) }
  let_it_be(:label2) { create(:label, project: project) }
  let_it_be(:label3) { create(:label, project: project) }
  let_it_be(:current_user) { create(:user).tap { |user| project.add_reporter(user) } }

  let(:work_item) { create(:work_item, project: project, labels: [label1, label2]) }
  let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Labels) } }
  let(:service) { described_class.new(widget: widget, current_user: current_user) }

  describe '#prepare_update_params' do
    context 'when params are set' do
      let(:params) { { add_label_ids: [label1.id], remove_label_ids: [label2.id] } }

      it "sets params correctly" do
        expect(service.prepare_update_params(params: params)).to include(
          {
            add_label_ids: match_array([label1.id]),
            remove_label_ids: match_array([label2.id])
          }
        )
      end

      context "and user doesn't have permissions to update labels" do
        let_it_be(:current_user) { create(:user) }

        it 'removes label params' do
          expect(service.prepare_update_params(params: params)).to be_nil
        end
      end
    end

    context 'when widget does not exist in new type' do
      let(:params) { {} }

      before do
        allow(service).to receive(:new_type_excludes_widget?).and_return(true)
      end

      it "sets correct params to remove work item labels" do
        expect(service.prepare_update_params(params: params)).to include(
          {
            remove_label_ids: match_array([label1.id, label2.id]),
            add_label_ids: []
          }
        )
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module WorkItems
  module Widgets
    module StartAndDueDateService
      class UpdateService < WorkItems::Widgets::BaseService
        def before_update_callback(params: {})
          return widget.work_item.assign_attributes({ start_date: nil, due_date: nil }) if new_type_excludes_widget?

          return if params.blank?
          return unless has_permission?(:set_work_item_metadata)

          widget.work_item.assign_attributes(params.slice(:start_date, :due_date))
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe WorkItems::Widgets::StartAndDueDateService::UpdateService, feature_category: :portfolio_management do
  let_it_be(:project) { create(:project) }
  let_it_be(:user) { create(:user).tap { |user| project.add_reporter(user) } }
  let_it_be_with_reload(:work_item) { create(:work_item, project: project) }

  let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::StartAndDueDate) } }

  describe '#before_update_callback' do
    let(:start_date) { Date.today }
    let(:due_date) { 1.week.from_now.to_date }
    let(:service) { described_class.new(widget: widget, current_user: user) }

    subject(:update_params) { service.before_update_callback(params: params) }

    context 'when start and due date params are present' do
      let(:params) { { start_date: Date.today, due_date: 1.week.from_now.to_date } }

      it 'correctly sets date values' do
        expect do
          update_params
        end.to change(work_item, :start_date).from(nil).to(start_date).and(
          change(work_item, :due_date).from(nil).to(due_date)
        )
      end

      context "and user doesn't have permissions to update start and due date" do
        let_it_be(:user) { create(:user) }

        it 'removes start and due date params params' do
          expect(update_params).to be_nil
        end
      end
    end

    context 'when date params are not present' do
      let(:params) { {} }

      it 'does not change work item date values' do
        expect do
          update_params
        end.to not_change(work_item, :start_date).from(nil).and(
          not_change(work_item, :due_date).from(nil)
        )
      end
    end

    context 'when work item had both date values already set' do
      before do
        work_item.update!(start_date: start_date, due_date: due_date)
      end

      context 'when one of the two params is null' do
        let(:params) { { start_date: nil } }

        it 'sets only one date to null' do
          expect do
            update_params
          end.to change(work_item, :start_date).from(start_date).to(nil).and(
            not_change(work_item, :due_date).from(due_date)
          )
        end
      end
    end

    context 'when widget does not exist in new type' do
      let(:params) { {} }

      before do
        allow(service).to receive(:new_type_excludes_widget?).and_return(true)
        work_item.update!(start_date: start_date, due_date: due_date)
      end

      it 'sets both dates to null' do
        expect do
          update_params
        end.to change(work_item, :start_date).from(start_date).to(nil).and(
          change(work_item, :due_date).from(due_date).to(nil)
        )
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module WorkItems
  module Widgets
    module AssigneesService
      class UpdateService < WorkItems::Widgets::BaseService
        def before_update_in_transaction(params:)
          params[:assignee_ids] = [] if new_type_excludes_widget?

          return unless params.present? && params.has_key?(:assignee_ids)
          return unless has_permission?(:set_work_item_metadata)

          assignee_ids = filter_assignees_count(params[:assignee_ids])
          assignee_ids = filter_assignee_permissions(assignee_ids)

          return if assignee_ids.sort == work_item.assignee_ids.sort

          work_item.assignee_ids = assignee_ids
          work_item.touch
        end

        private

        def filter_assignees_count(assignee_ids)
          return assignee_ids if work_item.allows_multiple_assignees?

          assignee_ids.first(1)
        end

        def filter_assignee_permissions(assignee_ids)
          assignees = User.id_in(assignee_ids)

          assignees.select { |assignee| assignee.can?(:read_work_item, work_item) }.map(&:id)
        end
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe WorkItems::Widgets::AssigneesService::UpdateService, :freeze_time, feature_category: :portfolio_management do
  let_it_be(:reporter) { create(:user) }
  let_it_be(:project) { create(:project, :private) }
  let_it_be(:new_assignee) { create(:user) }

  let(:work_item) do
    create(:work_item, project: project, updated_at: 1.day.ago)
  end

  let(:widget) { work_item.widgets.find { |widget| widget.is_a?(WorkItems::Widgets::Assignees) } }
  let(:current_user) { reporter }
  let(:params) { { assignee_ids: [new_assignee.id] } }

  before_all do
    project.add_reporter(reporter)
    project.add_guest(new_assignee)
  end

  describe '#before_update_in_transaction' do
    let(:service) { described_class.new(widget: widget, current_user: current_user) }

    subject { service.before_update_in_transaction(params: params) }

    it 'updates the assignees and sets updated_at to the current time' do
      subject

      expect(work_item.assignee_ids).to contain_exactly(new_assignee.id)
      expect(work_item.updated_at).to be_like_time(Time.current)
    end

    context 'when passing an empty array' do
      let(:params) { { assignee_ids: [] } }

      before do
        work_item.assignee_ids = [reporter.id]
      end

      it 'removes existing assignees' do
        subject

        expect(work_item.assignee_ids).to be_empty
        expect(work_item.updated_at).to be_like_time(Time.current)
      end
    end

    context 'when user does not have access' do
      let(:current_user) { create(:user) }

      it 'does not update the assignees' do
        subject

        expect(work_item.assignee_ids).to be_empty
        expect(work_item.updated_at).to be_like_time(1.day.ago)
      end
    end

    context 'when multiple assignees are given' do
      let(:params) { { assignee_ids: [new_assignee.id, reporter.id] } }

      context 'when work item allows multiple assignees' do
        before do
          allow(work_item).to receive(:allows_multiple_assignees?).and_return(true)
        end

        it 'sets all the given assignees' do
          subject

          expect(work_item.assignee_ids).to contain_exactly(new_assignee.id, reporter.id)
          expect(work_item.updated_at).to be_like_time(Time.current)
        end
      end

      context 'when work item does not allow multiple assignees' do
        before do
          allow(work_item).to receive(:allows_multiple_assignees?).and_return(false)
        end

        it 'only sets the first assignee' do
          subject

          expect(work_item.assignee_ids).to contain_exactly(new_assignee.id)
          expect(work_item.updated_at).to be_like_time(Time.current)
        end
      end
    end

    context 'when assignee does not have access to the work item' do
      let(:params) { { assignee_ids: [create(:user).id] } }

      it 'does not set the assignee' do
        subject

        expect(work_item.assignee_ids).to be_empty
        expect(work_item.updated_at).to be_like_time(1.day.ago)
      end
    end

    context 'when assignee ids are the same as the existing ones' do
      before do
        work_item.assignee_ids = [new_assignee.id]
      end

      it 'does not touch updated_at' do
        subject

        expect(work_item.assignee_ids).to contain_exactly(new_assignee.id)
        expect(work_item.updated_at).to be_like_time(1.day.ago)
      end
    end

    context 'when widget does not exist in new type' do
      let(:params) { {} }

      before do
        allow(service).to receive(:new_type_excludes_widget?).and_return(true)
        work_item.assignee_ids = [new_assignee.id]
      end

      it "resets the work item's assignees" do
        subject

        expect(work_item.assignee_ids).to be_empty
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Webauthn
  class RegisterService < BaseService
    def initialize(user, params, challenge)
      @user = user
      @params = params
      @challenge = challenge
    end

    def execute
      registration = WebauthnRegistration.new

      begin
        webauthn_credential = WebAuthn::Credential.from_create(Gitlab::Json.parse(@params[:device_response]))
        webauthn_credential.verify(@challenge)

        registration.update(
          credential_xid: Base64.strict_encode64(webauthn_credential.raw_id),
          public_key: webauthn_credential.public_key,
          counter: webauthn_credential.sign_count,
          name: @params[:name],
          user: @user
        )
      rescue JSON::ParserError
        registration.errors.add(:base, _('Your WebAuthn device did not send a valid JSON response.'))
      rescue WebAuthn::Error => e
        registration.errors.add(:base, e.message)
      end

      registration
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'
require 'webauthn/fake_client'

RSpec.describe Webauthn::RegisterService, feature_category: :system_access do
  let(:client) { WebAuthn::FakeClient.new(origin) }
  let(:user) { create(:user) }
  let(:challenge) { Base64.strict_encode64(SecureRandom.random_bytes(32)) }

  let(:origin) { 'http://localhost' }

  describe '#execute' do
    it 'returns a registration if challenge matches' do
      create_result = client.create(challenge: challenge) # rubocop:disable Rails/SaveBang
      webauthn_credential = WebAuthn::Credential.from_create(create_result)

      params = { device_response: create_result.to_json, name: 'abc' }
      service = described_class.new(user, params, challenge)

      registration = service.execute
      expect(registration.credential_xid).to eq(Base64.strict_encode64(webauthn_credential.raw_id))
      expect(registration.errors.size).to eq(0)
    end

    it 'returns an error if challenge does not match' do
      create_result = client.create(challenge: Base64.strict_encode64(SecureRandom.random_bytes(16))) # rubocop:disable Rails/SaveBang

      params = { device_response: create_result.to_json, name: 'abc' }
      service = described_class.new(user, params, challenge)

      registration = service.execute
      expect(registration.errors.size).to eq(1)
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Webauthn
  class AuthenticateService < BaseService
    def initialize(user, device_response, challenge)
      @user = user
      @device_response = device_response
      @challenge = challenge
    end

    def execute
      parsed_device_response = Gitlab::Json.parse(@device_response)

      webauthn_credential = WebAuthn::Credential.from_get(parsed_device_response)
      encoded_raw_id = Base64.strict_encode64(webauthn_credential.raw_id)
      stored_webauthn_credential = @user.webauthn_registrations.find_by_credential_xid(encoded_raw_id)

      encoder = WebAuthn.configuration.encoder

      if stored_webauthn_credential &&
          validate_webauthn_credential(webauthn_credential) &&
          verify_webauthn_credential(webauthn_credential, stored_webauthn_credential, @challenge, encoder)

        stored_webauthn_credential.update!(counter: webauthn_credential.sign_count)
        return true
      end

      false
    rescue JSON::ParserError, WebAuthn::SignCountVerificationError, WebAuthn::Error
      false
    end

    private

    ##
    # Validates that webauthn_credential is syntactically valid
    #
    # duplicated from WebAuthn::PublicKeyCredential#verify
    # which can't be used here as we need to call WebAuthn::AuthenticatorAssertionResponse#verify instead
    # (which is done in #verify_webauthn_credential)
    def validate_webauthn_credential(webauthn_credential)
      webauthn_credential.type == WebAuthn::TYPE_PUBLIC_KEY &&
        webauthn_credential.raw_id && webauthn_credential.id &&
        webauthn_credential.raw_id == WebAuthn.standard_encoder.decode(webauthn_credential.id)
    end

    ##
    # Verifies that webauthn_credential matches stored_credential with the given challenge
    #
    def verify_webauthn_credential(webauthn_credential, stored_credential, challenge, encoder)
      # We need to adjust the relaying party id (RP id) we verify against if the registration in question
      # is a migrated U2F registration. This is beacuse the appid of U2F and the rp id of WebAuthn differ.
      rp_id = webauthn_credential.client_extension_outputs['appid'] ? WebAuthn.configuration.origin : URI(WebAuthn.configuration.origin).host
      webauthn_credential.response.verify(
        encoder.decode(challenge),
        public_key: encoder.decode(stored_credential.public_key),
        sign_count: stored_credential.counter,
        rp_id: rp_id
      )
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'
require 'webauthn/fake_client'

RSpec.describe Webauthn::AuthenticateService, feature_category: :system_access do
  let(:client) { WebAuthn::FakeClient.new(origin) }
  let(:user) { create(:user) }
  let(:challenge) { Base64.strict_encode64(SecureRandom.random_bytes(32)) }

  let(:origin) { 'http://localhost' }

  before do
    create_result = client.create(challenge: challenge) # rubocop:disable Rails/SaveBang

    webauthn_credential = WebAuthn::Credential.from_create(create_result)

    registration = WebauthnRegistration.new(
      credential_xid: Base64.strict_encode64(webauthn_credential.raw_id),
      public_key: webauthn_credential.public_key,
      counter: 0,
      name: 'name',
      user_id: user.id
    )
    registration.save!
  end

  describe '#execute' do
    it 'returns true if the response is valid and a matching stored credential is present' do
      get_result = client.get(challenge: challenge)

      get_result['clientExtensionResults'] = {}
      service = described_class.new(user, get_result.to_json, challenge)

      expect(service.execute).to eq true
    end

    context 'when response is valid but no matching stored credential is present' do
      it 'returns false' do
        other_client = WebAuthn::FakeClient.new(origin)
        other_client.create(challenge: challenge) # rubocop:disable Rails/SaveBang

        get_result = other_client.get(challenge: challenge)

        get_result['clientExtensionResults'] = {}
        service = described_class.new(user, get_result.to_json, challenge)

        expect(service.execute).to eq false
      end
    end

    context 'when device response includes invalid json' do
      it 'returns false' do
        service = described_class.new(user, 'invalid JSON', '')
        expect(service.execute).to eq false
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Webauthn
  class DestroyService < BaseService
    attr_reader :webauthn_registration, :user, :current_user

    def initialize(current_user, user, webauthn_registrations_id)
      @current_user = current_user
      @user = user
      @webauthn_registration = user.webauthn_registrations.find(webauthn_registrations_id)
    end

    def execute
      return error(_('You are not authorized to perform this action')) unless authorized?

      webauthn_registration.destroy
      user.reset_backup_codes! if last_two_factor_registration?
    end

    private

    def last_two_factor_registration?
      user.webauthn_registrations.empty? && !user.otp_required_for_login?
    end

    def authorized?
      current_user.can?(:disable_two_factor, user)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Webauthn::DestroyService, feature_category: :system_access do
  let(:user) { create(:user, :two_factor_via_webauthn, registrations_count: 1) }
  let(:current_user) { user }

  describe '#execute' do
    let(:webauthn_id) { user.webauthn_registrations.first.id }

    subject { described_class.new(current_user, user, webauthn_id).execute }

    context 'with only one webauthn method enabled' do
      context 'when another user is calling the service' do
        context 'for a user without permissions' do
          let(:current_user) { create(:user) }

          it 'does not destry the webauthn registration' do
            expect { subject }.not_to change { user.webauthn_registrations.count }
          end

          it 'does not remove the user backup codes' do
            expect { subject }.not_to change { user.otp_backup_codes }
          end

          it 'returns error' do
            expect(subject[:status]).to eq(:error)
          end
        end

        context 'for an admin' do
          it 'destroys the webauthn registration' do
            expect { subject }.to change { user.webauthn_registrations.count }.by(-1)
          end

          it 'removes the user backup codes' do
            subject

            expect(user.otp_backup_codes).to be_nil
          end
        end
      end

      context 'when current user is calling the service' do
        context 'when there is also OTP enabled' do
          before do
            user.otp_required_for_login = true
            user.otp_secret = User.generate_otp_secret(32)
            user.otp_grace_period_started_at = Time.current
            user.generate_otp_backup_codes!
            user.save!
          end

          it 'removes the webauth registrations' do
            expect { subject }.to change { user.webauthn_registrations.count }.by(-1)
          end

          it 'does not remove the user backup codes' do
            expect { subject }.not_to change { user.otp_backup_codes }
          end
        end
      end
    end

    context 'with multiple webauthn methods enabled' do
      before do
        create(:webauthn_registration, user: user)
      end

      it 'destroys the webauthn registration' do
        expect { subject }.to change { user.webauthn_registrations.count }.by(-1)
      end

      it 'does not remove the user backup codes' do
        expect { subject }.not_to change { user.otp_backup_codes }
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  class CreateEventService < BaseService
    def execute
      ::Packages::Event.unique_counters_for(event_scope, event_name, originator_type).each do |event_name|
        ::Gitlab::UsageDataCounters::HLLRedisCounter.track_event(event_name, values: current_user.id)
      end

      ::Packages::Event.counters_for(event_scope, event_name, originator_type).each do |event_name|
        ::Gitlab::UsageDataCounters::PackageEventCounter.count(event_name)
      end
    end

    def originator_type
      case current_user
      when User
        :user
      when DeployToken
        :deploy_token
      else
        :guest
      end
    end

    private

    def event_scope
      @event_scope ||= scope.is_a?(::Packages::Package) ? scope.package_type : scope
    end

    def scope
      params[:scope]
    end

    def event_name
      params[:event_name]
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::CreateEventService, feature_category: :package_registry do
  let(:scope) { 'generic' }
  let(:event_name) { 'push_package' }

  let(:params) do
    {
      scope: scope,
      event_name: event_name
    }
  end

  subject { described_class.new(nil, user, params).execute }

  describe '#execute' do
    shared_examples 'redis package unique event creation' do |originator_type, expected_scope|
      it 'tracks the event' do
        expect(::Gitlab::UsageDataCounters::HLLRedisCounter).to receive(:track_event).with(/package/, values: user.id)

        subject
      end
    end

    shared_examples 'redis package count event creation' do |originator_type, expected_scope|
      it 'tracks the event' do
        expect(::Gitlab::UsageDataCounters::PackageEventCounter).to receive(:count).at_least(:once)

        subject
      end
    end

    context 'with a user' do
      let(:user) { create(:user) }

      it_behaves_like 'redis package unique event creation', 'user', 'generic'
      it_behaves_like 'redis package count event creation', 'user', 'generic'
    end

    context 'with a deploy token' do
      let(:user) { create(:deploy_token) }

      it_behaves_like 'redis package unique event creation', 'deploy_token', 'generic'
      it_behaves_like 'redis package count event creation', 'deploy_token', 'generic'
    end

    context 'with no user' do
      let(:user) { nil }

      it_behaves_like 'redis package count event creation', 'guest', 'generic'
    end

    context 'with a package as scope' do
      let(:scope) { create(:npm_package) }

      context 'as guest' do
        let(:user) { nil }

        it_behaves_like 'redis package count event creation', 'guest', 'npm'
      end

      context 'with user' do
        let(:user) { create(:user) }

        it_behaves_like 'redis package unique event creation', 'user', 'npm'
        it_behaves_like 'redis package count event creation', 'user', 'npm'
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  # WARNING: ensure that permissions are verified before using this service.
  class MarkPackageFilesForDestructionService
    BATCH_SIZE = 500

    def initialize(package_files)
      @package_files = package_files
    end

    def execute(batch_deadline: nil, batch_size: BATCH_SIZE)
      timeout = false
      updates_count = 0
      min_batch_size = [batch_size, BATCH_SIZE].min

      @package_files.each_batch(of: min_batch_size) do |batched_package_files|
        if batch_deadline && Time.zone.now > batch_deadline
          timeout = true
          break
        end

        updates_count += batched_package_files.update_all(status: :pending_destruction)
      end

      payload = { marked_package_files_count: updates_count }

      return response_error(payload) if timeout

      response_success(payload)
    end

    private

    def response_success(payload)
      ServiceResponse.success(
        message: 'Package files are now pending destruction',
        payload: payload
      )
    end

    def response_error(payload)
      ServiceResponse.error(
        message: 'Timeout while marking package files as pending destruction',
        payload: payload
      )
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::MarkPackageFilesForDestructionService, :aggregate_failures,
  feature_category: :package_registry do
  let(:service) { described_class.new(package_files) }

  describe '#execute', :aggregate_failures do
    let(:batch_deadline) { nil }

    subject { service.execute(batch_deadline: batch_deadline) }

    shared_examples 'executing successfully' do |marked_package_files_count: 0|
      it 'marks package files for destruction' do
        expect { subject }
          .to change { ::Packages::PackageFile.pending_destruction.count }.by(package_files.size)
      end

      it 'executes successfully' do
        expect(subject).to be_success
        expect(subject.message).to eq('Package files are now pending destruction')
        expect(subject.payload).to eq(marked_package_files_count: marked_package_files_count)
      end
    end

    context 'with no package files' do
      let_it_be(:package_files) { ::Packages::PackageFile.none }

      it_behaves_like 'executing successfully'
    end

    context 'with a single package file' do
      let_it_be(:package_file) { create(:package_file) }
      let_it_be(:package_files) { ::Packages::PackageFile.id_in(package_file.id) }

      it_behaves_like 'executing successfully', marked_package_files_count: 1
    end

    context 'with many package files' do
      let_it_be(:package_files) { ::Packages::PackageFile.id_in(create_list(:package_file, 3).map(&:id)) }

      it_behaves_like 'executing successfully', marked_package_files_count: 3

      context 'with a batch deadline' do
        let_it_be(:batch_deadline) { 250.seconds.from_now }

        context 'when the deadline is not hit' do
          before do
            expect(Time.zone).to receive(:now).and_return(batch_deadline - 10.seconds)
          end

          it_behaves_like 'executing successfully', marked_package_files_count: 3
        end

        context 'when the deadline is hit' do
          it 'does not execute the batch loop' do
            expect(Time.zone).to receive(:now).and_return(batch_deadline + 10.seconds)
            expect { subject }.to not_change { ::Packages::PackageFile.pending_destruction.count }
            expect(subject).to be_error
            expect(subject.message).to eq('Timeout while marking package files as pending destruction')
            expect(subject.payload).to eq(marked_package_files_count: 0)
          end
        end
      end

      context 'when a batch size is defined' do
        let_it_be(:batch_deadline) { 250.seconds.from_now }

        let(:batch_size) { 2 }

        subject { service.execute(batch_deadline: batch_deadline, batch_size: batch_size) }

        before do
          expect(Time.zone).to receive(:now).twice.and_call_original
        end

        it_behaves_like 'executing successfully', marked_package_files_count: 3
      end
    end

    context 'with an error during the update' do
      let_it_be(:package_files) { ::Packages::PackageFile.none }

      before do
        expect(package_files).to receive(:each_batch).and_raise('error!')
      end

      it 'raises the error' do
        expect { subject }
          .to raise_error('error!')
          .and not_change { ::Packages::PackageFile.pending_destruction.count }
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  class UpdatePackageFileService
    delegate :file, to: :@package_file

    def initialize(package_file, params)
      @package_file = package_file
      @params = params
    end

    def execute
      check_params

      return if same_as_params?

      # we need to access the file *before* updating the attributes linked to its path/key.
      file_storage_mode = file.file_storage?

      @package_file.package_id = package_id if package_id
      @package_file.file_name = file_name if file_name

      if file_storage_mode
        # package file is in mode LOCAL: we can pass the `file` to the update
        @package_file.file = file
      else
        # package file is in mode REMOTE: don't pass the `file` to the update
        # instead, pass the new file path. This will move the file
        # in object storage.
        @package_file.new_file_path = File.join(file.store_dir, @package_file.file_name)
      end

      @package_file.save!
    end

    private

    def check_params
      raise ArgumentError, 'package_file not persisted' unless @package_file.persisted?
      raise ArgumentError, 'package_id and file_name are blank' if package_id.blank? && file_name.blank?
    end

    def same_as_params?
      return false if package_id && package_id != @package_file.package_id
      return false if file_name && file_name != @package_file.file_name

      true
    end

    def package_id
      @params[:package_id]
    end

    def file_name
      @params[:file_name]
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::UpdatePackageFileService, feature_category: :package_registry do
  let_it_be(:another_package) { create(:package) }
  let_it_be(:old_file_name) { 'old_file_name.txt' }
  let_it_be(:new_file_name) { 'new_file_name.txt' }

  let(:package) { package_file.package }
  let(:params) { { package_id: another_package.id, file_name: new_file_name } }
  let(:service) { described_class.new(package_file, params) }

  describe '#execute' do
    subject { service.execute }

    shared_examples 'updating package file with valid parameters' do
      context 'with both parameters set' do
        it 'updates the package file accordingly' do
          expect { subject }
            .to change { package.package_files.count }.from(1).to(0)
            .and change { another_package.package_files.count }.from(0).to(1)
            .and change { package_file.package_id }.from(package.id).to(another_package.id)
            .and change { package_file.file_name }.from(old_file_name).to(new_file_name)
        end
      end

      context 'with only file_name set' do
        let(:params) { { file_name: new_file_name } }

        it 'updates the package file accordingly' do
          expect { subject }
            .to not_change { package.package_files.count }
            .and not_change { another_package.package_files.count }
            .and not_change { package_file.package_id }
            .and change { package_file.file_name }.from(old_file_name).to(new_file_name)
        end
      end

      context 'with only package_id set' do
        let(:params) { { package_id: another_package.id } }

        it 'updates the package file accordingly' do
          expect { subject }
            .to change { package.package_files.count }.from(1).to(0)
            .and change { another_package.package_files.count }.from(0).to(1)
            .and change { package_file.package_id }.from(package.id).to(another_package.id)
            .and not_change { package_file.file_name }
        end
      end
    end

    shared_examples 'not updating package with invalid parameters' do
      context 'with blank parameters' do
        let(:params) { {} }

        it 'raise an argument error' do
          expect { subject }.to raise_error(ArgumentError, 'package_id and file_name are blank')
        end
      end

      context 'with non persisted package file' do
        let(:package_file) { build(:package_file) }

        it 'raise an argument error' do
          expect { subject }.to raise_error(ArgumentError, 'package_file not persisted')
        end
      end
    end

    context 'with object storage disabled' do
      let(:package_file) { create(:package_file, file_name: old_file_name) }

      before do
        stub_package_file_object_storage(enabled: false)
      end

      it_behaves_like 'updating package file with valid parameters' do
        before do
          expect(package_file).to receive(:remove_previously_stored_file).and_call_original
          expect(package_file).not_to receive(:move_in_object_storage)
        end
      end

      it_behaves_like 'not updating package with invalid parameters'
    end

    context 'with object storage enabled' do
      let(:package_file) do
        create(
          :package_file,
          file_name: old_file_name,
          file: CarrierWaveStringFile.new_file(
            file_content: 'content',
            filename: old_file_name,
            content_type: 'text/plain'
          ),
          file_store: ::Packages::PackageFileUploader::Store::REMOTE
        )
      end

      before do
        stub_package_file_object_storage(enabled: true)
      end

      it_behaves_like 'updating package file with valid parameters' do
        before do
          expect(package_file).not_to receive(:remove_previously_stored_file)
          expect(package_file).to receive(:move_in_object_storage).and_call_original
        end
      end

      it_behaves_like 'not updating package with invalid parameters' do
        before do
          expect(package_file.file.file).not_to receive(:copy_to)
        end
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  class CreatePackageFileService
    attr_reader :package, :params

    def initialize(package, params)
      @package = package
      @params = params
    end

    def execute
      package_file = package.package_files.build(
        file: params[:file],
        size: params[:size],
        file_name: params[:file_name],
        file_sha1: params[:file_sha1],
        file_sha256: params[:file_sha256],
        file_md5: params[:file_md5]
      )

      if params[:build].present?
        package_file.package_file_build_infos << package_file.package_file_build_infos.build(pipeline: params[:build].pipeline)
      end

      package_file.save!
      package_file
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::CreatePackageFileService, feature_category: :package_registry do
  let_it_be(:package) { create(:maven_package) }
  let_it_be(:user) { create(:user) }

  let(:service) { described_class.new(package, params) }

  describe '#execute' do
    subject { service.execute }

    context 'with valid params' do
      let(:params) do
        {
          file: Tempfile.new,
          file_name: 'foo.jar'
        }
      end

      it 'creates a new package file' do
        package_file = subject

        expect(package_file).to be_valid
        expect(package_file.file_name).to eq('foo.jar')
      end

      it_behaves_like 'assigns build to package file'
    end

    context 'file is missing' do
      let(:params) do
        {
          file_name: 'foo.jar'
        }
      end

      it 'raises an error' do
        expect { subject }.to raise_error(ActiveRecord::RecordInvalid)
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  class UpdateTagsService
    include Gitlab::Utils::StrongMemoize

    def initialize(package, tags = [])
      @package = package
      @tags = tags
    end

    def execute
      return if @tags.empty?

      tags_to_destroy = existing_tags - @tags
      tags_to_create = @tags - existing_tags

      @package.tags.with_name(tags_to_destroy).delete_all if tags_to_destroy.any?
      ::ApplicationRecord.legacy_bulk_insert(Packages::Tag.table_name, rows(tags_to_create)) if tags_to_create.any? # rubocop:disable Gitlab/BulkInsert
    end

    private

    def existing_tags
      @package.tag_names
    end
    strong_memoize_attr :existing_tags

    def rows(tags)
      now = Time.zone.now
      tags.map do |tag|
        {
          package_id: @package.id,
          name: tag,
          created_at: now,
          updated_at: now,
          project_id: @package.project_id
        }
      end
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::UpdateTagsService, feature_category: :package_registry do
  let_it_be(:package, reload: true) { create(:nuget_package) }

  let(:tags) { %w[test-tag tag1 tag2 tag3] }
  let(:service) { described_class.new(package, tags) }

  describe '#execute' do
    subject { service.execute }

    RSpec.shared_examples 'updating tags' do |tags_count|
      it 'updates a tag' do
        expect { subject }.to change { Packages::Tag.count }.by(tags_count)
        expect(package.reload.tags.map(&:name)).to contain_exactly(*tags)
      end
    end

    it_behaves_like 'updating tags', 4

    context 'with an existing tag' do
      before do
        create(:packages_tag, package: package2, name: 'test-tag')
      end

      context 'on the same package' do
        let_it_be(:package2) { package }

        it_behaves_like 'updating tags', 3

        context 'with different name' do
          before do
            create(:packages_tag, package: package2, name: 'to_be_destroyed')
          end

          it_behaves_like 'updating tags', 2
        end
      end

      context 'on a different package' do
        let_it_be(:package2) { create(:nuget_package) }

        it_behaves_like 'updating tags', 4
      end
    end

    context 'with empty tags' do
      let(:tags) { [] }

      it 'is a no op' do
        expect(package).not_to receive(:tags)
        expect(::ApplicationRecord).not_to receive(:legacy_bulk_insert)

        subject
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  class RemoveTagService < BaseService
    attr_reader :package_tag

    def initialize(package_tag)
      raise ArgumentError, "Package tag must be set" if package_tag.blank?

      @package_tag = package_tag
    end

    def execute
      package_tag.delete
    end
  end
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::RemoveTagService, feature_category: :package_registry do
  let!(:package_tag) { create(:packages_tag) }

  describe '#execute' do
    subject { described_class.new(package_tag).execute }

    context 'with existing tag' do
      it { expect { subject }.to change { Packages::Tag.count }.by(-1) }
    end

    context 'with nil' do
      subject { described_class.new(nil) }

      it { expect { subject }.to raise_error(ArgumentError) }
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  class MarkPackageForDestructionService < BaseContainerService
    alias_method :package, :container

    def execute
      return service_response_error("You don't have access to this package", 403) unless user_can_delete_package?

      package.pending_destruction!

      package.mark_package_files_for_destruction
      package.sync_maven_metadata(current_user)

      service_response_success('Package was successfully marked as pending destruction')
    rescue StandardError => e
      track_exception(e)
      service_response_error('Failed to mark the package as pending destruction', 400)
    end

    private

    def service_response_error(message, http_status)
      ServiceResponse.error(message: message, http_status: http_status)
    end

    def service_response_success(message)
      ServiceResponse.success(message: message)
    end

    def user_can_delete_package?
      can?(current_user, :destroy_package, package.project)
    end

    def track_exception(error)
      Gitlab::ErrorTracking.track_exception(
        error,
        project_id: package.project_id,
        package_id: package.id
      )
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::MarkPackageForDestructionService, feature_category: :package_registry do
  let_it_be(:user) { create(:user) }
  let_it_be_with_reload(:package) { create(:npm_package) }

  describe '#execute' do
    subject(:service) { described_class.new(container: package, current_user: user) }

    context 'when the user is authorized' do
      before do
        package.project.add_maintainer(user)
      end

      context 'when it is successful' do
        it 'marks the package and package files as pending destruction' do
          expect(package).to receive(:sync_maven_metadata).and_call_original
          expect(package).to receive(:mark_package_files_for_destruction).and_call_original
          expect { service.execute }.to change { package.status }.from('default').to('pending_destruction')
        end

        it 'returns a success ServiceResponse' do
          response = service.execute

          expect(response).to be_a(ServiceResponse)
          expect(response).to be_success
          expect(response.message).to eq("Package was successfully marked as pending destruction")
        end
      end

      context 'when it is not successful' do
        before do
          allow(package).to receive(:pending_destruction!).and_raise(StandardError, "test")
        end

        it 'returns an error ServiceResponse' do
          expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
            instance_of(StandardError),
            project_id: package.project_id,
            package_id: package.id
          )

          response = service.execute

          expect(package).not_to receive(:sync_maven_metadata)
          expect(response).to be_a(ServiceResponse)
          expect(response).to be_error
          expect(response.message).to eq("Failed to mark the package as pending destruction")
          expect(response.status).to eq(:error)
        end
      end
    end

    context 'when the user is not authorized' do
      it 'returns an error ServiceResponse' do
        response = service.execute

        expect(response).to be_a(ServiceResponse)
        expect(response).to be_error
        expect(response.message).to eq("You don't have access to this package")
        expect(response.status).to eq(:error)
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  class CreateTemporaryPackageService < ::Packages::CreatePackageService
    PACKAGE_VERSION = '0.0.0'

    def execute(package_type, name: 'Temporary.Package')
      create_package!(package_type,
        name: name,
        version: "#{PACKAGE_VERSION}-#{uuid}",
        status: 'processing'
      )
    end

    private

    def uuid
      SecureRandom.uuid
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::CreateTemporaryPackageService, feature_category: :package_registry do
  let_it_be(:project) { create(:project) }
  let_it_be(:user) { create(:user) }
  let_it_be(:params) { {} }
  let_it_be(:package_name) { 'my-package' }
  let_it_be(:package_type) { 'rubygems' }

  describe '#execute' do
    subject { described_class.new(project, user, params).execute(package_type, name: package_name) }

    let(:package) { Packages::Package.last }

    it 'creates the package', :aggregate_failures do
      expect { subject }.to change { Packages::Package.count }.by(1)

      expect(package).to be_valid
      expect(package).to be_processing
      expect(package.name).to eq(package_name)
      expect(package.version).to start_with(described_class::PACKAGE_VERSION)
      expect(package.package_type).to eq(package_type)
    end

    it 'can create two packages in a row', :aggregate_failures do
      expect { subject }.to change { Packages::Package.count }.by(1)

      expect do
        described_class.new(project, user, params).execute(package_type, name: package_name)
      end.to change { Packages::Package.count }.by(1)

      expect(package).to be_valid
      expect(package).to be_processing
      expect(package.name).to eq(package_name)
      expect(package.version).to start_with(described_class::PACKAGE_VERSION)
      expect(package.package_type).to eq(package_type)
    end

    it_behaves_like 'assigns the package creator'
    it_behaves_like 'assigns build to package'
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  class MarkPackagesForDestructionService
    include BaseServiceUtility

    BATCH_SIZE = 20

    UNAUTHORIZED_RESPONSE = ServiceResponse.error(
      message: "You don't have the permission to perform this action",
      reason: :unauthorized
    ).freeze

    ERROR_RESPONSE = ServiceResponse.error(
      message: 'Failed to mark the packages as pending destruction'
    ).freeze

    SUCCESS_RESPONSE = ServiceResponse.success(
      message: 'Packages were successfully marked as pending destruction'
    ).freeze

    # Initialize this service with the given packages and user.
    #
    # * `packages`: must be an ActiveRecord relationship.
    # * `current_user`: an User object. Could be nil.
    def initialize(packages:, current_user: nil)
      @packages = packages
      @current_user = current_user
    end

    def execute(batch_size: BATCH_SIZE)
      no_access = false
      min_batch_size = [batch_size, BATCH_SIZE].min
      package_ids = []

      @packages.each_batch(of: min_batch_size) do |batched_packages|
        loaded_packages = batched_packages.including_project_route.to_a
        package_ids = loaded_packages.map(&:id)

        break no_access = true unless can_destroy_packages?(loaded_packages)

        ::Packages::Package.id_in(package_ids)
                           .update_all(status: :pending_destruction)

        sync_maven_metadata(loaded_packages)
        mark_package_files_for_destruction(loaded_packages)
      end

      return UNAUTHORIZED_RESPONSE if no_access

      SUCCESS_RESPONSE
    rescue StandardError => e
      track_exception(e, package_ids)
      ERROR_RESPONSE
    end

    private

    def mark_package_files_for_destruction(packages)
      ::Packages::MarkPackageFilesForDestructionWorker.bulk_perform_async_with_contexts(
        packages,
        arguments_proc: -> (package) { package.id },
        context_proc: -> (package) { { project: package.project, user: @current_user } }
      )
    end

    def sync_maven_metadata(packages)
      maven_packages_with_version = packages.select { |pkg| pkg.maven? && pkg.version? }
      ::Packages::Maven::Metadata::SyncWorker.bulk_perform_async_with_contexts(
        maven_packages_with_version,
        arguments_proc: -> (package) { [@current_user.id, package.project_id, package.name] },
        context_proc: -> (package) { { project: package.project, user: @current_user } }
      )
    end

    def can_destroy_packages?(packages)
      packages.all? do |package|
        can?(@current_user, :destroy_package, package)
      end
    end

    def track_exception(error, package_ids)
      Gitlab::ErrorTracking.track_exception(error, package_ids: package_ids)
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::MarkPackagesForDestructionService, :sidekiq_inline, feature_category: :package_registry do
  let_it_be(:project) { create(:project) }
  let_it_be_with_reload(:packages) { create_list(:npm_package, 3, project: project) }

  let(:user) { project.owner }

  # The service only accepts ActiveRecord relationships and not arrays.
  let(:service) { described_class.new(packages: ::Packages::Package.id_in(package_ids), current_user: user) }
  let(:package_ids) { packages.map(&:id) }

  describe '#execute' do
    subject { service.execute }

    context 'when the user is authorized' do
      before do
        project.add_maintainer(user)
      end

      context 'when it is successful' do
        it 'marks the packages as pending destruction' do
          expect(::Packages::Maven::Metadata::SyncService).not_to receive(:new)

          expect { subject }.to change { ::Packages::Package.pending_destruction.count }.from(0).to(3)
                                  .and change { Packages::PackageFile.pending_destruction.count }.from(0).to(3)
          packages.each { |pkg| expect(pkg.reload).to be_pending_destruction }

          expect(subject).to be_a(ServiceResponse)
          expect(subject).to be_success
          expect(subject.message).to eq('Packages were successfully marked as pending destruction')
        end

        context 'with maven packages' do
          let_it_be_with_reload(:packages) { create_list(:maven_package, 3, project: project) }

          it 'marks the packages as pending destruction' do
            expect(::Packages::Maven::Metadata::SyncService).to receive(:new).once.and_call_original

            expect { subject }.to change { ::Packages::Package.pending_destruction.count }.from(0).to(3)
                                    .and change { Packages::PackageFile.pending_destruction.count }.from(0).to(9)
            packages.each { |pkg| expect(pkg.reload).to be_pending_destruction }

            expect(subject).to be_a(ServiceResponse)
            expect(subject).to be_success
            expect(subject.message).to eq('Packages were successfully marked as pending destruction')
          end

          context 'without version' do
            before do
              ::Packages::Package.id_in(package_ids).update_all(version: nil)
            end

            it 'marks the packages as pending destruction' do
              expect(::Packages::Maven::Metadata::SyncService).not_to receive(:new)

              expect { subject }.to change { ::Packages::Package.pending_destruction.count }.from(0).to(3)
                                      .and change { Packages::PackageFile.pending_destruction.count }.from(0).to(9)
              packages.each { |pkg| expect(pkg.reload).to be_pending_destruction }

              expect(subject).to be_a(ServiceResponse)
              expect(subject).to be_success
              expect(subject.message).to eq('Packages were successfully marked as pending destruction')
            end
          end
        end
      end

      context 'when it is not successful' do
        before do
          allow(service).to receive(:can_destroy_packages?).and_raise(StandardError, 'test')
        end

        it 'returns an error ServiceResponse' do
          expect(::Packages::Maven::Metadata::SyncService).not_to receive(:new)

          expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
            instance_of(StandardError),
            package_ids: package_ids
          )

          expect { subject }.to not_change { ::Packages::Package.pending_destruction.count }
                                  .and not_change { ::Packages::PackageFile.pending_destruction.count }

          expect(subject).to be_a(ServiceResponse)
          expect(subject).to be_error
          expect(subject.message).to eq("Failed to mark the packages as pending destruction")
          expect(subject.status).to eq(:error)
        end
      end
    end

    context 'when the user is not authorized' do
      let(:user) { nil }

      it 'returns an error ServiceResponse' do
        expect(::Packages::Maven::Metadata::SyncService).not_to receive(:new)

        expect { subject }.to not_change { ::Packages::Package.pending_destruction.count }
                                .and not_change { ::Packages::PackageFile.pending_destruction.count }

        expect(subject).to be_a(ServiceResponse)
        expect(subject).to be_error
        expect(subject.message).to eq("You don't have the permission to perform this action")
        expect(subject.status).to eq(:error)
        expect(subject.reason).to eq(:unauthorized)
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true
module Packages
  # rubocop: disable Gitlab/BulkInsert
  class CreateDependencyService < BaseService
    attr_reader :package, :dependencies

    def initialize(package, dependencies)
      @package = package
      @dependencies = dependencies
    end

    def execute
      Packages::DependencyLink.dependency_types.each_key do |type|
        create_dependency(type)
      end
    end

    private

    def create_dependency(type)
      return unless dependencies[type].is_a?(Hash)

      names_and_version_patterns = dependencies[type]
      existing_ids, existing_names = find_existing_ids_and_names(names_and_version_patterns)
      dependencies_to_insert = names_and_version_patterns

      if existing_names.any?
        dependencies_to_insert = names_and_version_patterns.reject { |k, _| k.in?(existing_names) }
      end

      ApplicationRecord.transaction do
        inserted_ids = bulk_insert_package_dependencies(dependencies_to_insert)
        bulk_insert_package_dependency_links(type, (existing_ids + inserted_ids))
      end
    end

    def find_existing_ids_and_names(names_and_version_patterns)
      ids_and_names = Packages::Dependency.for_package_names_and_version_patterns(names_and_version_patterns)
                                          .pluck_ids_and_names
      ids = ids_and_names.map(&:first) || []
      names = ids_and_names.map(&:second) || []
      [ids, names]
    end

    def bulk_insert_package_dependencies(names_and_version_patterns)
      return [] if names_and_version_patterns.empty?

      rows = names_and_version_patterns.map do |name, version_pattern|
        {
          name: name,
          version_pattern: version_pattern
        }
      end

      ids = ApplicationRecord.legacy_bulk_insert(Packages::Dependency.table_name, rows, return_ids: true, on_conflict: :do_nothing)
      return ids if ids.size == names_and_version_patterns.size

      Packages::Dependency.uncached do
        # The bulk_insert statement above do not dirty the query cache. To make
        # sure that the results are fresh from the database and not from a stalled
        # and potentially wrong cache, this query has to be done with the query
        # cache disabled.
        Packages::Dependency.ids_for_package_names_and_version_patterns(names_and_version_patterns)
      end
    end

    def bulk_insert_package_dependency_links(type, dependency_ids)
      rows = dependency_ids.map do |dependency_id|
        {
          package_id: package.id,
          dependency_id: dependency_id,
          dependency_type: Packages::DependencyLink.dependency_types[type.to_s]
        }
      end

      ApplicationRecord.legacy_bulk_insert(Packages::DependencyLink.table_name, rows)
    end
  end
  # rubocop: enable Gitlab/BulkInsert
end

```

Response:
# frozen_string_literal: true
require 'spec_helper'

RSpec.describe Packages::CreateDependencyService, feature_category: :package_registry do
  describe '#execute' do
    let_it_be(:namespace) { create(:namespace) }
    let_it_be(:version) { '1.0.1' }
    let_it_be(:package_name) { "@#{namespace.path}/my-app" }

    context 'when packages are published' do
      let(:json_file) { 'packages/npm/payload.json' }
      let(:params) do
        Gitlab::Json.parse(fixture_file(json_file)
                .gsub('@root/npm-test', package_name)
                .gsub('1.0.1', version))
                .with_indifferent_access
      end

      let(:package_version) { params[:versions].each_key.first }
      let(:dependencies) { params[:versions][package_version] }
      let(:package) { create(:npm_package) }
      let(:dependency_names) { package.dependency_links.flat_map(&:dependency).map(&:name).sort }
      let(:dependency_link_types) { package.dependency_links.map(&:dependency_type).sort }

      subject { described_class.new(package, dependencies).execute }

      it 'creates dependencies and links' do
        expect(Packages::Dependency)
            .to receive(:ids_for_package_names_and_version_patterns)
            .once
            .and_call_original

        expect { subject }
          .to change { Packages::Dependency.count }.by(1)
          .and change { Packages::DependencyLink.count }.by(1)
        expect(dependency_names).to match_array(%w[express])
        expect(dependency_link_types).to match_array(%w[dependencies])
      end

      context 'with repeated packages' do
        let(:json_file) { 'packages/npm/payload_with_duplicated_packages.json' }

        it 'creates dependencies and links' do
          expect(Packages::Dependency)
            .to receive(:ids_for_package_names_and_version_patterns)
            .exactly(4).times
            .and_call_original

          expect { subject }
            .to change { Packages::Dependency.count }.by(4)
            .and change { Packages::DependencyLink.count }.by(6)
          expect(dependency_names).to match_array(%w[d3 d3 d3 dagre-d3 dagre-d3 express])
          expect(dependency_link_types).to match_array(%w[bundleDependencies dependencies dependencies devDependencies devDependencies peerDependencies])
        end
      end

      context 'with dependencies bulk insert conflicts' do
        let_it_be(:rows) { [{ name: 'express', version_pattern: '^4.16.4' }] }

        it 'creates dependences and links' do
          original_bulk_insert = ::ApplicationRecord.method(:legacy_bulk_insert)
          expect(::ApplicationRecord)
            .to receive(:legacy_bulk_insert) do |table, rows, return_ids: false, disable_quote: [], on_conflict: nil|
              call_count = table == Packages::Dependency.table_name ? 2 : 1
              call_count.times { original_bulk_insert.call(table, rows, return_ids: return_ids, disable_quote: disable_quote, on_conflict: on_conflict) }
            end.twice
          expect(Packages::Dependency)
            .to receive(:ids_for_package_names_and_version_patterns)
            .twice
            .and_call_original

          expect { subject }
            .to change { Packages::Dependency.count }.by(1)
            .and change { Packages::DependencyLink.count }.by(1)
          expect(dependency_names).to match_array(%w[express])
          expect(dependency_link_types).to match_array(%w[dependencies])
        end
      end

      context 'with existing dependencies' do
        let(:other_package) { create(:npm_package) }

        before do
          described_class.new(other_package, dependencies).execute
        end

        it 'reuses them' do
          expect { subject }
            .to not_change { Packages::Dependency.count }
            .and change { Packages::DependencyLink.count }.by(1)
        end
      end

      context 'with a dependency not described with a hash' do
        let(:invalid_dependencies) { dependencies.tap { |d| d['bundleDependencies'] = false } }

        subject { described_class.new(package, invalid_dependencies).execute }

        it 'creates dependencies and links' do
          expect(Packages::Dependency)
              .to receive(:ids_for_package_names_and_version_patterns)
              .once
              .and_call_original

          expect { subject }
            .to change { Packages::Dependency.count }.by(1)
            .and change { Packages::DependencyLink.count }.by(1)
          expect(dependency_names).to match_array(%w[express])
          expect(dependency_link_types).to match_array(%w[dependencies])
        end
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module MlModel
    class CreatePackageFileService < BaseService
      def execute
        ::Packages::Package.transaction do
          package = find_or_create_package
          find_or_create_model_version(package)

          create_package_file(package)
        end
      end

      private

      def find_or_create_package
        package_params = {
          name: params[:package_name],
          version: params[:package_version],
          build: params[:build],
          status: params[:status]
        }

        package = ::Packages::MlModel::FindOrCreatePackageService
                    .new(project, current_user, package_params)
                    .execute

        package.update_column(:status, params[:status]) if params[:status] && params[:status] != package.status

        package.create_build_infos!(params[:build])

        package
      end

      def find_or_create_model_version(package)
        model_version_params = {
          model_name: package.name,
          version: package.version,
          package: package,
          user: current_user
        }

        Ml::FindOrCreateModelVersionService.new(project, model_version_params).execute
      end

      def create_package_file(package)
        file_params = {
          file: params[:file],
          size: params[:file].size,
          file_sha256: params[:file].sha256,
          file_name: params[:file_name],
          build: params[:build]
        }

        ::Packages::CreatePackageFileService.new(package, file_params).execute
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::MlModel::CreatePackageFileService, feature_category: :mlops do
  describe '#execute' do
    let_it_be(:project) { create(:project) }
    let_it_be(:user) { create(:user) }
    let_it_be(:pipeline) { create(:ci_pipeline, user: user, project: project) }
    let_it_be(:file_name) { 'myfile.tar.gz.1' }

    let(:build) { instance_double(Ci::Build, pipeline: pipeline) }

    let(:sha256) { '440e5e148a25331bbd7991575f7d54933c0ebf6cc735a18ee5066ac1381bb590' }
    let(:temp_file) { Tempfile.new("test") }
    let(:file) { UploadedFile.new(temp_file.path, sha256: sha256) }
    let(:package_service) { double }

    subject(:execute_service) { described_class.new(project, user, params).execute }

    before do
      FileUtils.touch(temp_file)
    end

    after do
      FileUtils.rm_f(temp_file)
    end

    context 'without existing package' do
      let(:params) do
        {
          package_name: 'new_model',
          package_version: '1.0.0',
          file: file,
          file_name: file_name
        }
      end

      it 'creates package file', :aggregate_failures do
        expect { execute_service }
          .to change { Packages::MlModel::Package.count }.by(1)
          .and change { Packages::PackageFile.count }.by(1)
          .and change { Packages::PackageFileBuildInfo.count }.by(0)
          .and change { Ml::ModelVersion.count }.by(1)

        new_model = Packages::MlModel::Package.last
        package_file = new_model.package_files.last
        new_model_version = Ml::ModelVersion.last

        expect(new_model.name).to eq('new_model')
        expect(new_model.version).to eq('1.0.0')
        expect(new_model.status).to eq('default')
        expect(package_file.package).to eq(new_model)
        expect(package_file.file_name).to eq(file_name)
        expect(package_file.size).to eq(file.size)
        expect(package_file.file_sha256).to eq(sha256)
        expect(new_model_version.name).to eq('new_model')
        expect(new_model_version.version).to eq('1.0.0')
        expect(new_model_version.package).to eq(new_model)
      end
    end

    context 'with existing package' do
      let_it_be(:model) { create(:ml_model_package, creator: user, project: project, version: '0.1.0') }

      let(:params) do
        {
          package_name: model.name,
          package_version: model.version,
          file: file,
          file_name: file_name,
          status: :hidden,
          build: build
        }
      end

      it 'adds the package file and updates status and ci_build', :aggregate_failures do
        expect { execute_service }
          .to change { project.packages.ml_model.count }.by(0)
          .and change { model.package_files.count }.by(1)
          .and change { Packages::PackageFileBuildInfo.count }.by(1)

        model.reload

        package_file = model.package_files.last

        expect(model.build_infos.first.pipeline).to eq(build.pipeline)
        expect(model.status).to eq('hidden')

        expect(package_file.package).to eq(model)
        expect(package_file.file_name).to eq(file_name)
        expect(package_file.size).to eq(file.size)
        expect(package_file.file_sha256).to eq(sha256)
      end
    end
  end
end


Instruction:
Write RSpec test file for following ruby class
```ruby
# frozen_string_literal: true

module Packages
  module MlModel
    class FindOrCreatePackageService < ::Packages::CreatePackageService
      def execute
        find_or_create_package!(::Packages::Package.package_types['ml_model'])
      end
    end
  end
end

```

Response:
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe Packages::MlModel::FindOrCreatePackageService, feature_category: :mlops do
  let_it_be(:project) { create(:project) }
  let_it_be(:user) { project.creator }
  let_it_be(:ci_build) { create(:ci_build, :running, user: user, project: project) }

  let(:base_params) do
    {
      name: 'mymodel',
      version: '0.0.1'
    }
  end

  let(:params) { base_params }

  describe '#execute' do
    subject(:execute_service) { described_class.new(project, user, params).execute }

    context 'when model does not exist' do
      it 'creates the model' do
        expect { subject }.to change { project.packages.ml_model.count }.by(1)

        package = project.packages.ml_model.last

        aggregate_failures do
          expect(package.creator).to eq(user)
          expect(package.package_type).to eq('ml_model')
          expect(package.name).to eq('mymodel')
          expect(package.version).to eq('0.0.1')
          expect(package.build_infos.count).to eq(0)
        end
      end

      context 'when build is provided' do
        let(:params) { base_params.merge(build: ci_build) }

        it 'creates package and package build info' do
          expect { subject }.to change { project.packages.ml_model.count }.by(1)

          package = project.packages.ml_model.last

          aggregate_failures do
            expect(package.creator).to eq(user)
            expect(package.package_type).to eq('ml_model')
            expect(package.name).to eq('mymodel')
            expect(package.version).to eq('0.0.1')
            expect(package.build_infos.first.pipeline).to eq(ci_build.pipeline)
          end
        end
      end
    end

    context 'when model already exists' do
      it 'does not create a new model', :aggregate_failures do
        model = project.packages.ml_model.create!(params)

        expect do
          new_model = subject
          expect(new_model).to eq(model)
        end.not_to change { project.packages.ml_model.count }
      end
    end
  end
end