File: projects_spec.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (167 lines) | stat: -rw-r--r-- 5,499 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe 'getting a collection of projects', feature_category: :source_code_management do
  include GraphqlHelpers

  let_it_be(:current_user) { create(:user) }
  let_it_be(:group) { create(:group, name: 'public-group', developers: current_user) }
  let_it_be(:projects) { create_list(:project, 5, :public, group: group) }
  let_it_be(:other_project) { create(:project, :public, group: group) }
  let_it_be(:archived_project) { create(:project, :archived, group: group) }

  let(:filters) { {} }

  let(:query) do
    graphql_query_for(
      :projects,
      filters,
      "nodes {#{all_graphql_fields_for('Project', max_depth: 1, excluded: ['productAnalyticsState'])} }"
    )
  end

  context 'when archived argument is ONLY' do
    let(:filters) { { archived: :ONLY } }

    it 'returns only archived projects' do
      post_graphql(query, current_user: current_user)

      expect(graphql_data_at(:projects, :nodes))
        .to contain_exactly(a_graphql_entity_for(archived_project))
    end
  end

  context 'when archived argument is INCLUDE' do
    let(:filters) { { archived: :INCLUDE } }

    it 'returns archived and non-archived projects' do
      post_graphql(query, current_user: current_user)

      expect(graphql_data_at(:projects, :nodes))
      .to contain_exactly(
        *projects.map { |project| a_graphql_entity_for(project) },
        a_graphql_entity_for(other_project),
        a_graphql_entity_for(archived_project)
      )
    end
  end

  context 'when archived argument is EXCLUDE' do
    let(:filters) { { archived: :EXCLUDE } }

    it 'returns only non-archived projects' do
      post_graphql(query, current_user: current_user)

      expect(graphql_data_at(:projects, :nodes))
      .to contain_exactly(
        *projects.map { |project| a_graphql_entity_for(project) },
        a_graphql_entity_for(other_project)
      )
    end
  end

  describe 'min_access_level' do
    let_it_be(:project_with_owner_access) { create(:project, :private) }

    before_all do
      project_with_owner_access.add_owner(current_user)
    end

    context 'when min_access_level is OWNER' do
      let(:filters) { { min_access_level: :OWNER } }

      it 'returns only projects user has owner access to' do
        post_graphql(query, current_user: current_user)

        expect(graphql_data_at(:projects, :nodes))
          .to contain_exactly(a_graphql_entity_for(project_with_owner_access))
      end
    end

    context 'when min_access_level is DEVELOPER' do
      let(:filters) { { min_access_level: :DEVELOPER } }

      it 'returns only projects user has developer or higher access to' do
        post_graphql(query, current_user: current_user)

        expect(graphql_data_at(:projects, :nodes))
        .to contain_exactly(
          *projects.map { |project| a_graphql_entity_for(project) },
          a_graphql_entity_for(other_project),
          a_graphql_entity_for(project_with_owner_access)
        )
      end
    end
  end

  context 'when providing full_paths filter' do
    let(:project_full_paths) { projects.map(&:full_path) }
    let(:filters) { { full_paths: project_full_paths } }

    let(:single_project_query) do
      graphql_query_for(
        :projects,
        { full_paths: [project_full_paths.first] },
        "nodes {#{all_graphql_fields_for('Project', max_depth: 1, excluded: ['productAnalyticsState'])} }"
      )
    end

    it_behaves_like 'a working graphql query that returns data' do
      before do
        post_graphql(query, current_user: current_user)
      end
    end

    it 'avoids N+1 queries', :use_sql_query_cache, :clean_gitlab_redis_cache do
      post_graphql(single_project_query, current_user: current_user)

      control = ActiveRecord::QueryRecorder.new do
        post_graphql(single_project_query, current_user: current_user)
      end

      # There is an N+1 query for max_member_access_for_user_ids
      # There is an N+1 query for duo_features_enabled cascading setting
      # https://gitlab.com/gitlab-org/gitlab/-/issues/442164
      expect do
        post_graphql(query, current_user: current_user)
      end.not_to exceed_all_query_limit(control).with_threshold(17)
    end

    it 'returns the expected projects' do
      post_graphql(query, current_user: current_user)
      returned_full_paths = graphql_data_at(:projects, :nodes).pluck('fullPath')

      expect(returned_full_paths).to match_array(project_full_paths)
    end

    context 'when users provides more than 50 full_paths' do
      let(:filters) { { full_paths: Array.new(51) { other_project.full_path } } }

      it 'returns an error' do
        post_graphql(query, current_user: current_user)

        expect(graphql_errors).to contain_exactly(
          hash_including('message' => _('You cannot provide more than 50 full_paths'))
        )
      end
    end
  end

  context 'when providing the programming_language_name argument' do
    let_it_be(:project) { projects.first }
    let_it_be(:ruby) { create(:programming_language, name: 'Ruby') }
    let_it_be(:repository_language) do
      create(:repository_language, project: project, programming_language: ruby, share: 1)
    end

    let(:filters) { { programming_language_name: 'ruby' } }

    it 'returns the expected projects' do
      post_graphql(query, current_user: current_user)

      expect(graphql_data_at(:projects, :nodes))
        .to contain_exactly(a_graphql_entity_for(project))
    end
  end
end