|
91 | 91 | end |
92 | 92 | end |
93 | 93 |
|
| 94 | + # The formatter's methods and keywords differ between release lines. Calls go |
| 95 | + # through call_formatter, which passes only the keywords this version |
| 96 | + # accepts, so an unsupported keyword never looks like a rejected input. |
| 97 | + keyword_types = %i[key keyreq].freeze |
| 98 | + |
| 99 | + define_method(:keywords_for) do |name| |
| 100 | + formatter.method(name).parameters.filter_map { |type, param| param if keyword_types.include?(type) } |
| 101 | + end |
| 102 | + |
| 103 | + define_method(:call_formatter) do |name, *positional, **keywords| |
| 104 | + formatter.public_send(name, *positional, **keywords.slice(*keywords_for(name))) |
| 105 | + end |
| 106 | + |
| 107 | + # Routing tokens only count when this version's method accepts them |
| 108 | + define_method(:tokens_for) do |name, tokens| |
| 109 | + keywords_for(name).include?(:p_token) ? tokens : {} |
| 110 | + end |
| 111 | + |
| 112 | + define_method(:available) do |names| |
| 113 | + names.select { |name| formatter.respond_to?(name) } |
| 114 | + end |
| 115 | + |
94 | 116 | # Runs one formatter call; returns nil when the input was rejected |
95 | 117 | define_method(:attempt) do |&blk| |
96 | 118 | blk.call |
|
104 | 126 | p_token = random_token |
105 | 127 | l_token = random_token |
106 | 128 | tokens = { 'P' => p_token, 'L' => l_token } |
107 | | - case_name = %i[meta_get meta_set meta_delete meta_arithmetic plain_meta_get plain_meta_set |
108 | | - plain_meta_delete].sample(random: rng) |
| 129 | + case_name = available(%i[meta_get meta_set meta_delete meta_arithmetic plain_meta_get plain_meta_set |
| 130 | + plain_meta_delete]).sample(random: rng) |
109 | 131 | args = nil |
110 | 132 |
|
111 | 133 | out = attempt do |
|
115 | 137 | recache_ttl: maybe(lambda { |
116 | 138 | random_numeric |
117 | 139 | }), quiet: rng.rand < 0.5, p_token: p_token, l_token: l_token } |
118 | | - formatter.meta_get(**args) |
| 140 | + call_formatter(:meta_get, **args) |
119 | 141 | when :meta_set |
120 | 142 | args = { key: key, value: random_string(key_chars, 30), bitflags: rng.rand(0..5), cas: maybe(lambda { |
121 | 143 | random_numeric |
122 | 144 | }), |
123 | 145 | ttl: maybe(-> { random_numeric }), quiet: rng.rand < 0.5, p_token: p_token, l_token: l_token } |
124 | | - formatter.meta_set(**args) |
| 146 | + call_formatter(:meta_set, **args) |
125 | 147 | when :meta_delete |
126 | 148 | args = { key: key, cas: maybe(-> { random_numeric }), stale: true, ttl: maybe(-> { random_numeric }), |
127 | 149 | p_token: p_token, l_token: l_token } |
128 | | - formatter.meta_delete(**args) |
| 150 | + call_formatter(:meta_delete, **args) |
129 | 151 | when :meta_arithmetic |
130 | 152 | args = { key: key, delta: maybe(-> { random_numeric }), initial: maybe(-> { random_numeric }), |
131 | 153 | ttl: maybe(-> { random_numeric }), p_token: p_token, l_token: l_token } |
132 | | - formatter.meta_arithmetic(**args) |
| 154 | + call_formatter(:meta_arithmetic, **args) |
133 | 155 | when :plain_meta_get |
134 | 156 | tokens = {} |
135 | 157 | args = [key, rng.rand < 0.5] |
136 | | - formatter.plain_meta_get(*args) |
| 158 | + call_formatter(:plain_meta_get, *args) |
137 | 159 | when :plain_meta_set |
138 | 160 | tokens = {} |
139 | 161 | args = [key, rng.rand(0..1000), rng.rand(0..5), maybe(-> { random_numeric })] |
140 | | - formatter.plain_meta_set(*args) |
| 162 | + call_formatter(:plain_meta_set, *args) |
141 | 163 | when :plain_meta_delete |
142 | 164 | tokens = {} |
143 | 165 | args = [key] |
144 | | - formatter.plain_meta_delete(*args) |
| 166 | + call_formatter(:plain_meta_delete, *args) |
145 | 167 | end |
146 | 168 | end |
147 | 169 | next if out.nil? |
|
152 | 174 | commands = frame(bytes) |
153 | 175 |
|
154 | 176 | assert_equal 1, commands.size, "#{context} produced #{commands.size} commands: #{out.inspect}" |
155 | | - assert_command_line(commands[0][0], key, tokens) |
| 177 | + assert_command_line(commands[0][0], key, tokens_for(case_name, tokens)) |
156 | 178 | rescue Minitest::Assertion => e |
157 | 179 | raise e.class, "#{e.message}\n#{context || "seed=#{seed} iteration=#{i}"}" |
158 | 180 | end |
|
164 | 186 | p_token = random_token |
165 | 187 | l_token = random_token |
166 | 188 | tokens = { 'P' => p_token, 'L' => l_token } |
167 | | - case_name = %i[multi_meta_get multi_meta_delete multi_meta_set].sample(random: rng) |
| 189 | + case_name = available(%i[multi_meta_get multi_meta_delete multi_meta_set]).sample(random: rng) |
168 | 190 | args = nil |
169 | 191 |
|
170 | 192 | out = attempt do |
171 | 193 | case case_name |
172 | 194 | when :multi_meta_get |
173 | 195 | args = [keys, { return_cas: rng.rand < 0.5, p_token: p_token, l_token: l_token }] |
174 | | - formatter.multi_meta_get(keys, **args[1]) |
| 196 | + call_formatter(:multi_meta_get, keys, **args[1]) |
175 | 197 | when :multi_meta_delete |
176 | 198 | args = [keys, { stale: true, ttl: maybe(-> { random_numeric }), p_token: p_token, l_token: l_token }] |
177 | | - formatter.multi_meta_delete(keys, **args[1]) |
| 199 | + call_formatter(:multi_meta_delete, keys, **args[1]) |
178 | 200 | when :multi_meta_set |
179 | 201 | entries = keys.to_h { |k| [k, [random_string(key_chars, 30), rng.rand(0..5)]] } |
180 | 202 | args = [entries, { ttl: maybe(-> { random_numeric }), p_token: p_token, l_token: l_token }] |
181 | | - formatter.multi_meta_set(entries, **args[1]) |
| 203 | + call_formatter(:multi_meta_set, entries, **args[1]) |
182 | 204 | end |
183 | 205 | end |
184 | 206 | next if out.nil? |
|
189 | 211 | assert_equal keys.size + 1, commands.size, "#{context} produced #{commands.size} commands" |
190 | 212 | assert_equal 'mn', commands.last[0], context |
191 | 213 | commands[0...-1].each_with_index do |(header, _), idx| |
192 | | - assert_command_line(header, keys[idx], tokens) |
| 214 | + assert_command_line(header, keys[idx], tokens_for(case_name, tokens)) |
193 | 215 | end |
194 | 216 | rescue Minitest::Assertion => e |
195 | 217 | raise e.class, "#{e.message}\n#{context || "seed=#{seed} iteration=#{i}"}" |
|
0 commit comments