Welcome to mirror list, hosted at ThFree Co, Russian Federation.

application_experiment_spec.rb « experiments « spec - gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: ece52d37351e6f63daf3cc6681bbb48e57e351b3 (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
# frozen_string_literal: true

require 'spec_helper'

RSpec.describe ApplicationExperiment do
  subject { described_class.new(:stub) }

  describe "publishing results" do
    it "tracks the assignment" do
      expect(subject).to receive(:track).with(:assignment)

      subject.publish(nil)
    end

    it "pushes the experiment knowledge into the client using Gon.global" do
      expect(Gon.global).to receive(:push).with(
        {
          experiment: {
            'stub' => { # string key because it can be namespaced
              experiment: 'stub',
              key: 'e8f65fd8d973f9985dc7ea3cf1614ae1',
              variant: 'control'
            }
          }
        },
        true
      )

      subject.publish(nil)
    end
  end

  describe "tracking events", :snowplow do
    it "doesn't track if excluded" do
      subject.exclude { true }

      subject.track(:action)

      expect_no_snowplow_event
    end

    it "tracks the event with the expected arguments and merged contexts" do
      subject.track(:action, property: '_property_', context: [
        SnowplowTracker::SelfDescribingJson.new('iglu:com.gitlab/fake/jsonschema/0-0-0', { data: '_data_' })
      ])

      expect_snowplow_event(
        category: 'stub',
        action: 'action',
        property: '_property_',
        context: [
          {
            schema: 'iglu:com.gitlab/fake/jsonschema/0-0-0',
            data: { data: '_data_' }
          },
          {
            schema: 'iglu:com.gitlab/gitlab_experiment/jsonschema/0-3-0',
            data: { experiment: 'stub', key: 'e8f65fd8d973f9985dc7ea3cf1614ae1', variant: 'control' }
          }
        ]
      )
    end
  end

  describe "variant resolution" do
    it "returns nil when not rolled out" do
      stub_feature_flags(stub: false)

      expect(subject.variant.name).to eq('control')
    end

    context "when rolled out to 100%" do
      it "returns the first variant name" do
        subject.try(:variant1) {}
        subject.try(:variant2) {}

        expect(subject.variant.name).to eq('variant1')
      end
    end
  end

  context "when caching" do
    let(:cache) { ApplicationExperiment::Cache.new }

    before do
      cache.clear(key: subject.name)

      subject.use { } # setup the control
      subject.try { } # setup the candidate

      allow(Gitlab::Experiment::Configuration).to receive(:cache).and_return(cache)
    end

    it "caches the variant determined by the variant resolver" do
      expect(subject.variant.name).to eq('candidate') # we should be in the experiment

      subject.run

      expect(cache.read(subject.cache_key)).to eq('candidate')
    end

    it "doesn't cache a variant if we don't explicitly provide one" do
      # by not caching "empty" variants, we effectively create a mostly
      # optimal combination of caching and rollout flexibility. If we cached
      # every control variant assigned, we'd inflate the cache size and
      # wouldn't be able to roll out to subjects that we'd already assigned to
      # the control.
      stub_feature_flags(stub: false) # simulate being not rolled out

      expect(subject.variant.name).to eq('control') # if we ask, it should be control

      subject.run

      expect(cache.read(subject.cache_key)).to be_nil
    end

    it "caches a control variant if we assign it specifically" do
      # by specifically assigning the control variant here, we're guaranteeing
      # that this context will always get the control variant unless we delete
      # the field from the cache (or clear the entire experiment cache) -- or
      # write code that would specify a different variant.
      subject.run(:control)

      expect(cache.read(subject.cache_key)).to eq('control')
    end
  end
end