summaryrefslogtreecommitdiff
path: root/lib/quality/test_level.rb
blob: 45cfa9b373db249ceeabfbe0162db63d18e90af7 (plain)
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
# frozen_string_literal: true

module Quality
  class TestLevel
    UnknownTestLevelError = Class.new(StandardError)

    TEST_LEVEL_FOLDERS = {
      migration: %w[
        migrations
      ],
      background_migration: %w[
        lib/gitlab/background_migration
        lib/ee/gitlab/background_migration
      ],
      frontend_fixture: %w[
        frontend/fixtures
      ],
      unit: %w[
        bin
        channels
        config
        db
        dependencies
        elastic
        elastic_integration
        experiments
        factories
        finders
        frontend
        graphql
        haml_lint
        helpers
        initializers
        javascripts
        lib
        models
        policies
        presenters
        rack_servers
        replicators
        routing
        rubocop
        serializers
        services
        sidekiq
        support_specs
        tasks
        uploaders
        validators
        views
        workers
        tooling
      ],
      integration: %w[
        controllers
        mailers
        requests
      ],
      system: ['features']
    }.freeze

    attr_reader :prefix

    def initialize(prefix = nil)
      @prefix = prefix
      @patterns = {}
      @regexps = {}
    end

    def pattern(level)
      @patterns[level] ||= "#{prefix}spec/#{folders_pattern(level)}{,/**/}*#{suffix(level)}"
    end

    def regexp(level)
      @regexps[level] ||= Regexp.new("#{prefix}spec/#{folders_regex(level)}").freeze
    end

    def level_for(file_path)
      case file_path
      # Detect migration first since some background migration tests are under
      # spec/lib/gitlab/background_migration and tests under spec/lib are unit by default
      when regexp(:migration), regexp(:background_migration)
        :migration
      # Detect frontend fixture before matching other unit tests
      when regexp(:frontend_fixture)
        :frontend_fixture
      when regexp(:unit)
        :unit
      when regexp(:integration)
        :integration
      when regexp(:system)
        :system
      else
        raise UnknownTestLevelError, "Test level for #{file_path} couldn't be set. Please rename the file properly or change the test level detection regexes in #{__FILE__}."
      end
    end

    def background_migration?(file_path)
      !!(file_path =~ regexp(:background_migration))
    end

    private

    def suffix(level)
      case level
      when :frontend_fixture
        ".rb"
      else
        "_spec.rb"
      end
    end

    def migration_and_background_migration_folders
      TEST_LEVEL_FOLDERS.fetch(:migration) + TEST_LEVEL_FOLDERS.fetch(:background_migration)
    end

    def folders_pattern(level)
      case level
      when :migration
        "{#{migration_and_background_migration_folders.join(',')}}"
      # Geo specs aren't in a specific folder, but they all have the :geo tag, so we must search for them globally
      when :all, :geo
        '**'
      else
        "{#{TEST_LEVEL_FOLDERS.fetch(level).join(',')}}"
      end
    end

    def folders_regex(level)
      case level
      when :migration
        "(#{migration_and_background_migration_folders.join('|')})"
      # Geo specs aren't in a specific folder, but they all have the :geo tag, so we must search for them globally
      when :all, :geo
        ''
      else
        "(#{TEST_LEVEL_FOLDERS.fetch(level).join('|')})"
      end
    end
  end
end