Class: MightyTest::Sharder

Inherits:
Object
  • Object
show all
Defined in:
lib/mighty_test/sharder.rb

Constant Summary collapse

DEFAULT_SEED =
123_456_789

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(index:, total:, seed: nil, file_system: FileSystem.new) ⇒ Sharder

Returns a new instance of Sharder.

Raises:

  • (ArgumentError)


17
18
19
20
21
22
23
24
25
26
27
# File 'lib/mighty_test/sharder.rb', line 17

def initialize(index:, total:, seed: nil, file_system: FileSystem.new)
  raise ArgumentError, "shard: total shards must be a number greater than 0" unless total > 0

  valid_group = index > 0 && index <= total
  raise ArgumentError, "shard: shard index must be > 0 and <= #{total}" unless valid_group

  @index = index
  @total = total
  @seed = seed || DEFAULT_SEED
  @file_system = file_system
end

Instance Attribute Details

#indexObject (readonly)

Returns the value of attribute index.



15
16
17
# File 'lib/mighty_test/sharder.rb', line 15

def index
  @index
end

#seedObject (readonly)

Returns the value of attribute seed.



15
16
17
# File 'lib/mighty_test/sharder.rb', line 15

def seed
  @seed
end

#totalObject (readonly)

Returns the value of attribute total.



15
16
17
# File 'lib/mighty_test/sharder.rb', line 15

def total
  @total
end

Class Method Details

.from_argv(value, env: ENV, file_system: FileSystem.new) ⇒ Object

Raises:

  • (ArgumentError)


5
6
7
8
9
10
11
12
13
# File 'lib/mighty_test/sharder.rb', line 5

def self.from_argv(value, env: ENV, file_system: FileSystem.new)
  index, total = value.to_s.match(%r{\A(\d+)/(\d+)\z})&.captures&.map(&:to_i)
  raise ArgumentError, "shard: value must be in the form INDEX/TOTAL (e.g. 2/8)" if total.nil?

  git_sha = env.values_at("GITHUB_SHA", "CIRCLE_SHA1").find { |sha| !sha.to_s.strip.empty? }
  seed = git_sha&.unpack1("l_")

  new(index:, total:, seed:, file_system:)
end

Instance Method Details

#shard(*test_paths) ⇒ Object



29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/mighty_test/sharder.rb', line 29

def shard(*test_paths)
  random = Random.new(seed)

  # Shuffle slow and normal paths separately so that slow ones get evenly distributed
  shuffled_paths = test_paths
    .flatten
    .partition { |path| !file_system.slow_test_path?(path) }
    .flat_map { |paths| paths.shuffle(random:) }

  slices = shuffled_paths.each_slice(total)
  slices.filter_map { |slice| slice[index - 1] }
end