gitlab-experiment 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +54 -16
- data/lib/gitlab/experiment/rspec.rb +20 -7
- data/lib/gitlab/experiment/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ea78e416b0b830fe748b29e64d0871d4ece35d99bb6c4142fae1a6b1e2bbfb96
|
|
4
|
+
data.tar.gz: ec16e265a80b00380528ba3d2aee36f1da8ffb13b7941a838dcc73e20671aca4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a767ae547fae832e9053ba91779fc0c1ee85bd16bda1d2a1eb41239fe34a01921b2ef734bea5fbe4724c45f70bed2f3cfbec9c68624d4003c9f30493bf50e99b
|
|
7
|
+
data.tar.gz: cabbdd641f2ee46db0be4209e28866eb7f5437f46f60ba23c0fe82dfb16944620f360506a7ddad3f17d2fcbf149c374a876545473afc474b943518fbfb631a7f
|
data/README.md
CHANGED
|
@@ -669,20 +669,52 @@ end
|
|
|
669
669
|
|
|
670
670
|
### Stub helpers
|
|
671
671
|
|
|
672
|
-
You can stub experiment variant resolution using the `stub_experiments` helper.
|
|
672
|
+
You can stub experiment variant resolution using the `stub_experiments` helper. The helper supports multiple formats for
|
|
673
|
+
flexibility:
|
|
674
|
+
|
|
675
|
+
**Simple hash format:**
|
|
673
676
|
|
|
674
677
|
```ruby
|
|
675
|
-
it "stubs experiments
|
|
678
|
+
it "stubs experiments using hash format" do
|
|
676
679
|
stub_experiments(pill_color: :red)
|
|
677
680
|
|
|
678
681
|
experiment(:pill_color) do |e|
|
|
679
682
|
expect(e).to be_enabled
|
|
680
683
|
expect(e.assigned.name).to eq('red')
|
|
681
684
|
end
|
|
682
|
-
end
|
|
685
|
+
end
|
|
686
|
+
```
|
|
687
|
+
|
|
688
|
+
**Hash format with options:**
|
|
689
|
+
|
|
690
|
+
```ruby
|
|
691
|
+
it "stubs experiments with assigned option" do
|
|
692
|
+
stub_experiments(pill_color: { variant: :red, assigned: true })
|
|
693
|
+
|
|
694
|
+
experiment(:pill_color) do |e|
|
|
695
|
+
expect(e).to be_enabled
|
|
696
|
+
expect(e.assigned.name).to eq('red')
|
|
697
|
+
end
|
|
698
|
+
end
|
|
699
|
+
```
|
|
700
|
+
|
|
701
|
+
**Mixed formats (symbols and hashes together):**
|
|
702
|
+
|
|
703
|
+
```ruby
|
|
704
|
+
it "stubs multiple experiments with mixed formats" do
|
|
705
|
+
stub_experiments(
|
|
706
|
+
pill_color: :red,
|
|
707
|
+
hippy: { variant: :free_love, assigned: true },
|
|
708
|
+
yuppie: :financial_success
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
expect(experiment(:pill_color).assigned.name).to eq(:red)
|
|
712
|
+
expect(experiment(:hippy).assigned.name).to eq(:free_love)
|
|
713
|
+
expect(experiment(:yuppie).assigned.name).to eq(:financial_success)
|
|
714
|
+
end
|
|
683
715
|
```
|
|
684
716
|
|
|
685
|
-
|
|
717
|
+
**Boolean true (allows rollout strategy to assign):**
|
|
686
718
|
|
|
687
719
|
```ruby
|
|
688
720
|
it "stubs experiments while allowing the rollout strategy to assign the variant" do
|
|
@@ -695,30 +727,36 @@ it "stubs experiments while allowing the rollout strategy to assign the variant"
|
|
|
695
727
|
end
|
|
696
728
|
```
|
|
697
729
|
|
|
698
|
-
|
|
730
|
+
#### Testing `only_assigned` behavior
|
|
731
|
+
|
|
732
|
+
When you use the `assigned: true` option in `stub_experiments`, the `find_variant` method is automatically stubbed
|
|
733
|
+
to return the specified variant. This allows you to test the `only_assigned` behavior:
|
|
699
734
|
|
|
700
735
|
```ruby
|
|
701
|
-
it "tests only_assigned behavior with cached
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
736
|
+
it "tests only_assigned behavior with a cached variant" do
|
|
737
|
+
stub_experiments(pill_color: { variant: :red, assigned: true })
|
|
738
|
+
|
|
705
739
|
experiment_instance = experiment(:pill_color, actor: user, only_assigned: true)
|
|
706
|
-
|
|
740
|
+
|
|
707
741
|
expect(experiment_instance).not_to be_excluded
|
|
708
742
|
expect(experiment_instance.run).to eq('red')
|
|
709
743
|
end
|
|
710
744
|
|
|
711
|
-
it "tests only_assigned behavior without cached
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
745
|
+
it "tests only_assigned behavior without a cached variant" do
|
|
746
|
+
stub_experiments(pill_color: :red)
|
|
747
|
+
|
|
715
748
|
experiment_instance = experiment(:pill_color, actor: user, only_assigned: true)
|
|
716
|
-
|
|
749
|
+
|
|
717
750
|
expect(experiment_instance).to be_excluded
|
|
718
|
-
expect(experiment_instance.run).to eq('
|
|
751
|
+
expect(experiment_instance.run).to eq('red')
|
|
719
752
|
end
|
|
720
753
|
```
|
|
721
754
|
|
|
755
|
+
**Note:** The `assigned: true` option only works correctly when caching is disabled. When caching is enabled,
|
|
756
|
+
`find_variant` will attempt to read from the actual cache store rather than using the stub. In this case, you can
|
|
757
|
+
populate the cache naturally by running the experiment first to assign and cache a variant before testing with
|
|
758
|
+
`only_assigned: true`.
|
|
759
|
+
|
|
722
760
|
### Registered behaviors matcher
|
|
723
761
|
|
|
724
762
|
It's useful to test our registered behaviors, as well as their return values when we implement anything complex in them. The `register_behavior` matcher is useful for this.
|
|
@@ -6,7 +6,7 @@ module Gitlab
|
|
|
6
6
|
autoload :Trackable, 'gitlab/experiment/test_behaviors/trackable.rb'
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
WrappedExperiment = Struct.new(:klass, :experiment_name, :variant_name, :expectation_chain, :blocks)
|
|
9
|
+
WrappedExperiment = Struct.new(:klass, :experiment_name, :variant_name, :expectation_chain, :blocks, :assigned)
|
|
10
10
|
|
|
11
11
|
module RSpecMocks
|
|
12
12
|
@__gitlab_experiment_receivers = {}
|
|
@@ -44,6 +44,12 @@ module Gitlab
|
|
|
44
44
|
# Call the original method if we specified simply `true`.
|
|
45
45
|
wrapped.variant_name == true ? method.call : wrapped.variant_name
|
|
46
46
|
}
|
|
47
|
+
|
|
48
|
+
# Stub find_variant only if caching is not enabled
|
|
49
|
+
unless Configuration.cache
|
|
50
|
+
variant_return_value = wrapped.assigned ? wrapped.variant_name.to_s : nil
|
|
51
|
+
allow(instance).to receive(:find_variant).and_return(variant_return_value)
|
|
52
|
+
end
|
|
47
53
|
end
|
|
48
54
|
end
|
|
49
55
|
|
|
@@ -51,11 +57,11 @@ module Gitlab
|
|
|
51
57
|
end
|
|
52
58
|
|
|
53
59
|
def wrapped_experiment(experiment, remock: false, &block)
|
|
54
|
-
klass, experiment_name, variant_name = *extract_experiment_details(experiment)
|
|
60
|
+
klass, experiment_name, variant_name, assigned = *extract_experiment_details(experiment)
|
|
55
61
|
|
|
56
62
|
wrapped_experiment = wrapped_experiments[experiment_name] =
|
|
57
63
|
(!remock && wrapped_experiments[experiment_name]) ||
|
|
58
|
-
WrappedExperiment.new(klass, experiment_name, variant_name, wrapped_experiment_chain_for(klass), [])
|
|
64
|
+
WrappedExperiment.new(klass, experiment_name, variant_name, wrapped_experiment_chain_for(klass), [], assigned)
|
|
59
65
|
|
|
60
66
|
wrapped_experiment.blocks << block if block
|
|
61
67
|
wrapped_experiment
|
|
@@ -84,9 +90,16 @@ module Gitlab
|
|
|
84
90
|
def extract_experiment_details(experiment)
|
|
85
91
|
experiment_name = nil
|
|
86
92
|
variant_name = nil
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
93
|
+
assigned = nil
|
|
94
|
+
|
|
95
|
+
if experiment.is_a?(Array)
|
|
96
|
+
# From normalize_experiments: [experiment_name, variant_name_or_config]
|
|
97
|
+
experiment_name, variant_name = *experiment
|
|
98
|
+
assigned = variant_name.is_a?(Hash) ? variant_name.delete(:assigned) : nil
|
|
99
|
+
variant_name = variant_name[:variant] if variant_name.is_a?(Hash)
|
|
100
|
+
elsif experiment.is_a?(Symbol)
|
|
101
|
+
experiment_name = experiment
|
|
102
|
+
end
|
|
90
103
|
|
|
91
104
|
base_klass = Configuration.base_class.constantize
|
|
92
105
|
variant_name = experiment.assigned.name if experiment.is_a?(base_klass)
|
|
@@ -94,7 +107,7 @@ module Gitlab
|
|
|
94
107
|
resolved_klass = experiment_klass(experiment) { base_klass.constantize(experiment_name) }
|
|
95
108
|
experiment_name ||= experiment.instance_variable_get(:@_name)
|
|
96
109
|
|
|
97
|
-
[resolved_klass, experiment_name.to_s, variant_name]
|
|
110
|
+
[resolved_klass, experiment_name.to_s, variant_name, assigned]
|
|
98
111
|
end
|
|
99
112
|
|
|
100
113
|
def experiment_klass(experiment, &block)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: gitlab-experiment
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- GitLab
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-
|
|
11
|
+
date: 2025-12-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|