elasticsearch-api 7.8.0 → 7.9.0.pre
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/lib/elasticsearch/api.rb +2 -1
- data/lib/elasticsearch/api/actions/bulk.rb +6 -5
- data/lib/elasticsearch/api/actions/cat/aliases.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/allocation.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/count.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/fielddata.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/health.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/help.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/indices.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/master.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/nodeattrs.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/nodes.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/pending_tasks.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/plugins.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/recovery.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/repositories.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/segments.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/shards.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/snapshots.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/tasks.rb +2 -2
- data/lib/elasticsearch/api/actions/cat/templates.rb +3 -3
- data/lib/elasticsearch/api/actions/cat/thread_pool.rb +3 -3
- data/lib/elasticsearch/api/actions/clear_scroll.rb +3 -3
- data/lib/elasticsearch/api/actions/cluster/allocation_explain.rb +9 -4
- data/lib/elasticsearch/api/actions/cluster/delete_component_template.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/delete_voting_config_exclusions.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/exists_component_template.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/get_component_template.rb +3 -3
- data/lib/elasticsearch/api/actions/cluster/get_settings.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/health.rb +3 -3
- data/lib/elasticsearch/api/actions/cluster/pending_tasks.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/post_voting_config_exclusions.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/put_component_template.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/put_settings.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/remote_info.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/reroute.rb +2 -2
- data/lib/elasticsearch/api/actions/cluster/state.rb +3 -3
- data/lib/elasticsearch/api/actions/cluster/stats.rb +3 -3
- data/lib/elasticsearch/api/actions/count.rb +9 -14
- data/lib/elasticsearch/api/actions/create.rb +2 -2
- data/lib/elasticsearch/api/actions/dangling_indices/delete_dangling_index.rb +60 -0
- data/lib/elasticsearch/api/actions/dangling_indices/import_dangling_index.rb +60 -0
- data/lib/elasticsearch/api/actions/dangling_indices/list_dangling_indices.rb +43 -0
- data/lib/elasticsearch/api/actions/dangling_indices/params_registry.rb +60 -0
- data/lib/elasticsearch/api/actions/delete.rb +3 -3
- data/lib/elasticsearch/api/actions/delete_by_query.rb +3 -3
- data/lib/elasticsearch/api/actions/delete_by_query_rethrottle.rb +2 -2
- data/lib/elasticsearch/api/actions/delete_script.rb +2 -2
- data/lib/elasticsearch/api/actions/exists.rb +3 -3
- data/lib/elasticsearch/api/actions/exists_source.rb +3 -3
- data/lib/elasticsearch/api/actions/explain.rb +12 -7
- data/lib/elasticsearch/api/actions/field_caps.rb +14 -8
- data/lib/elasticsearch/api/actions/get.rb +3 -3
- data/lib/elasticsearch/api/actions/get_script.rb +2 -2
- data/lib/elasticsearch/api/actions/get_script_context.rb +2 -2
- data/lib/elasticsearch/api/actions/get_script_languages.rb +2 -2
- data/lib/elasticsearch/api/actions/get_source.rb +3 -3
- data/lib/elasticsearch/api/actions/index.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/add_block.rb +70 -0
- data/lib/elasticsearch/api/actions/indices/analyze.rb +12 -7
- data/lib/elasticsearch/api/actions/indices/clear_cache.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/clone.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/close.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/create.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/create_data_stream.rb +3 -4
- data/lib/elasticsearch/api/actions/indices/data_streams_stats.rb +62 -0
- data/lib/elasticsearch/api/actions/indices/delete.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/delete_alias.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/delete_data_stream.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/delete_index_template.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/delete_template.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/exists.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/exists_alias.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/exists_index_template.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/exists_template.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/exists_type.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/flush.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/flush_synced.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/forcemerge.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/get.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/get_alias.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/{get_data_streams.rb → get_data_stream.rb} +7 -7
- data/lib/elasticsearch/api/actions/indices/get_field_mapping.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/get_index_template.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/get_mapping.rb +4 -4
- data/lib/elasticsearch/api/actions/indices/get_settings.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/get_template.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/get_upgrade.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/open.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/put_alias.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/put_index_template.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/put_mapping.rb +6 -4
- data/lib/elasticsearch/api/actions/indices/put_settings.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/put_template.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/recovery.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/refresh.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/resolve_index.rb +58 -0
- data/lib/elasticsearch/api/actions/indices/rollover.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/segments.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/shard_stores.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/shrink.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/simulate_index_template.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/simulate_template.rb +63 -0
- data/lib/elasticsearch/api/actions/indices/split.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/stats.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/update_aliases.rb +2 -2
- data/lib/elasticsearch/api/actions/indices/upgrade.rb +3 -3
- data/lib/elasticsearch/api/actions/indices/validate_query.rb +14 -9
- data/lib/elasticsearch/api/actions/info.rb +2 -2
- data/lib/elasticsearch/api/actions/ingest/delete_pipeline.rb +2 -2
- data/lib/elasticsearch/api/actions/ingest/get_pipeline.rb +3 -3
- data/lib/elasticsearch/api/actions/ingest/processor_grok.rb +2 -2
- data/lib/elasticsearch/api/actions/ingest/put_pipeline.rb +2 -2
- data/lib/elasticsearch/api/actions/ingest/simulate.rb +4 -4
- data/lib/elasticsearch/api/actions/mget.rb +4 -4
- data/lib/elasticsearch/api/actions/msearch.rb +5 -5
- data/lib/elasticsearch/api/actions/msearch_template.rb +5 -5
- data/lib/elasticsearch/api/actions/mtermvectors.rb +15 -10
- data/lib/elasticsearch/api/actions/nodes/hot_threads.rb +3 -3
- data/lib/elasticsearch/api/actions/nodes/info.rb +3 -3
- data/lib/elasticsearch/api/actions/nodes/reload_secure_settings.rb +3 -3
- data/lib/elasticsearch/api/actions/nodes/stats.rb +4 -4
- data/lib/elasticsearch/api/actions/nodes/usage.rb +3 -3
- data/lib/elasticsearch/api/actions/ping.rb +2 -2
- data/lib/elasticsearch/api/actions/put_script.rb +3 -3
- data/lib/elasticsearch/api/actions/rank_eval.rb +4 -4
- data/lib/elasticsearch/api/actions/reindex.rb +2 -2
- data/lib/elasticsearch/api/actions/reindex_rethrottle.rb +2 -2
- data/lib/elasticsearch/api/actions/render_search_template.rb +12 -7
- data/lib/elasticsearch/api/actions/scripts_painless_execute.rb +9 -4
- data/lib/elasticsearch/api/actions/scroll.rb +12 -7
- data/lib/elasticsearch/api/actions/search.rb +14 -9
- data/lib/elasticsearch/api/actions/search_shards.rb +3 -3
- data/lib/elasticsearch/api/actions/search_template.rb +4 -4
- data/lib/elasticsearch/api/actions/snapshot/cleanup_repository.rb +2 -2
- data/lib/elasticsearch/api/actions/snapshot/create.rb +2 -2
- data/lib/elasticsearch/api/actions/snapshot/create_repository.rb +2 -2
- data/lib/elasticsearch/api/actions/snapshot/delete.rb +2 -2
- data/lib/elasticsearch/api/actions/snapshot/delete_repository.rb +2 -2
- data/lib/elasticsearch/api/actions/snapshot/get.rb +2 -2
- data/lib/elasticsearch/api/actions/snapshot/get_repository.rb +3 -3
- data/lib/elasticsearch/api/actions/snapshot/restore.rb +2 -2
- data/lib/elasticsearch/api/actions/snapshot/status.rb +3 -3
- data/lib/elasticsearch/api/actions/snapshot/verify_repository.rb +2 -2
- data/lib/elasticsearch/api/actions/tasks/cancel.rb +3 -3
- data/lib/elasticsearch/api/actions/tasks/get.rb +2 -2
- data/lib/elasticsearch/api/actions/tasks/list.rb +2 -2
- data/lib/elasticsearch/api/actions/termvectors.rb +8 -4
- data/lib/elasticsearch/api/actions/update.rb +3 -3
- data/lib/elasticsearch/api/actions/update_by_query.rb +3 -3
- data/lib/elasticsearch/api/actions/update_by_query_rethrottle.rb +2 -2
- data/lib/elasticsearch/api/namespace/cat.rb +0 -1
- data/lib/elasticsearch/api/namespace/dangling_indices.rb +35 -0
- data/lib/elasticsearch/api/version.rb +1 -1
- data/spec/elasticsearch/api/actions/count_spec.rb +2 -2
- data/spec/elasticsearch/api/actions/dangling_indices/delete_dangling_indices_spec.rb +48 -0
- data/spec/elasticsearch/api/actions/dangling_indices/import_dangling_indices_spec.rb +48 -0
- data/spec/elasticsearch/api/actions/dangling_indices/list_dangling_indices_spec.rb +36 -0
- data/spec/elasticsearch/api/actions/explain_document_spec.rb +8 -9
- data/spec/elasticsearch/api/actions/indices/add_block_spec.rb +63 -0
- data/spec/elasticsearch/api/actions/indices/analyze_spec.rb +7 -8
- data/spec/elasticsearch/api/actions/indices/data_streams_stats_spec.rb +72 -0
- data/spec/elasticsearch/api/actions/indices/validate_query_spec.rb +7 -13
- data/spec/elasticsearch/api/actions/ingest/simulate_spec.rb +6 -7
- data/spec/elasticsearch/api/actions/json_builders_spec.rb +10 -13
- data/spec/elasticsearch/api/actions/mget_spec.rb +5 -6
- data/spec/elasticsearch/api/actions/msearch_spec.rb +5 -6
- data/spec/elasticsearch/api/actions/msearch_template_spec.rb +5 -6
- data/spec/elasticsearch/api/actions/mtermvectors_spec.rb +7 -7
- data/spec/elasticsearch/api/actions/render_search_template_spec.rb +2 -2
- data/spec/elasticsearch/api/actions/scroll_spec.rb +1 -1
- data/spec/elasticsearch/api/actions/search_spec.rb +7 -7
- data/spec/elasticsearch/api/actions/search_template_spec.rb +5 -6
- data/spec/elasticsearch/api/actions/termvectors_spec.rb +5 -7
- data/spec/elasticsearch/api/rest_api_yaml_spec.rb +0 -1
- data/utils/thor/.rubocop.yml +2 -0
- data/utils/thor/generate_source.rb +22 -15
- data/utils/thor/generator/endpoint_specifics.rb +8 -1
- data/utils/thor/templates/_documentation_top.erb +11 -1
- metadata +26 -12
- data/spec/README.md +0 -61
- data/test/integration/yaml_test_runner.rb +0 -592
- data/test/test_helper.rb +0 -118
data/spec/README.md
DELETED
@@ -1,61 +0,0 @@
|
|
1
|
-
# Rest API YAML Spec Runner
|
2
|
-
|
3
|
-
The file that traverses the yaml files and loads a **TestFile** object per each of them:
|
4
|
-
`elasticsearch-api/spec/elasticsearch/api/rest_api_yaml_spec.rb`
|
5
|
-
|
6
|
-
You can use the SINGLE_TEST env variable to run just one test, or add code like this on the first line of the tests.each block:
|
7
|
-
```ruby
|
8
|
-
next unless file =~ /indices.put_mapping\/all_path_options_with_types.yml/
|
9
|
-
```
|
10
|
-
|
11
|
-
#### TestFile object
|
12
|
-
Class representing a single test file. Contains setup, teardown and tests.
|
13
|
-
`../api-spec-testing/test_file.rb`
|
14
|
-
|
15
|
-
#### Test object
|
16
|
-
Every single test in the test file is represented in the Test object.
|
17
|
-
`../api-spec-testing/test_file/test.rb`
|
18
|
-
|
19
|
-
#### TaskGroup objects
|
20
|
-
|
21
|
-
Tests are ordered in task groups, an array of TaskGroup objects.
|
22
|
-
`../api-spec-testing/test_file/task_group.rb`
|
23
|
-
|
24
|
-
Task Groups are a representation of a block of actions consisting of 'do' actions and their verifications. e.g.:
|
25
|
-
```yaml
|
26
|
-
- do:
|
27
|
-
index:
|
28
|
-
index: test-index
|
29
|
-
id: 1
|
30
|
-
body: { foo: bar }
|
31
|
-
|
32
|
-
- match: { _index: test-index }
|
33
|
-
- match: { _id: "1"}
|
34
|
-
- match: { _version: 1}
|
35
|
-
```
|
36
|
-
|
37
|
-
**Before** each test, the spec runner runs `clear_data` on the test_file. This clears indices, index templates, snapshots and repositories. For xpack it also clears roles, users, privileges, datafeeds, ml_jobs and more.
|
38
|
-
|
39
|
-
**After** each test, it runs the test file teardown and `clear_data` again.
|
40
|
-
|
41
|
-
For each TaskGroup, it sees what's in the task group definition and runs an expectation test.
|
42
|
-
|
43
|
-
# Rest YAML tests Helper
|
44
|
-
|
45
|
-
`elasticsearch-api/spec/rest_yaml_tests_helper.rb`
|
46
|
-
|
47
|
-
- `ADMIN_CLIENT` is defined here.
|
48
|
-
- `SINGLE_TEST` is defined here.
|
49
|
-
- Skipped tests are listed here
|
50
|
-
|
51
|
-
# Spec Helper
|
52
|
-
|
53
|
-
- `DEFAULT_CLIENT` is defined here
|
54
|
-
|
55
|
-
# RSpec Matchers
|
56
|
-
|
57
|
-
The tests use custom [RSpec Matchers](https://www.rubydoc.info/gems/rspec-expectations/RSpec/Matchers) defined in `api-spec-testing/rspec_matchers.rb`.
|
58
|
-
|
59
|
-
# Enable Logging
|
60
|
-
|
61
|
-
To enable logging, set the environment `QUIET` to false before running the tests. In CI, this is located in the [Dockerfile](https://github.com/elastic/elasticsearch-ruby/blob/master/.ci/Dockerfile). The environment variable is evaluated in the Rest YAML tests Helper file.
|
@@ -1,592 +0,0 @@
|
|
1
|
-
# Licensed to Elasticsearch B.V. under one or more contributor
|
2
|
-
# license agreements. See the NOTICE file distributed with
|
3
|
-
# this work for additional information regarding copyright
|
4
|
-
# ownership. Elasticsearch B.V. licenses this file to you under
|
5
|
-
# the Apache License, Version 2.0 (the "License"); you may
|
6
|
-
# not use this file except in compliance with the License.
|
7
|
-
# You may obtain a copy of the License at
|
8
|
-
#
|
9
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
-
#
|
11
|
-
# Unless required by applicable law or agreed to in writing,
|
12
|
-
# software distributed under the License is distributed on an
|
13
|
-
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
14
|
-
# KIND, either express or implied. See the License for the
|
15
|
-
# specific language governing permissions and limitations
|
16
|
-
# under the License.
|
17
|
-
|
18
|
-
RUBY_1_8 = defined?(RUBY_VERSION) && RUBY_VERSION < '1.9'
|
19
|
-
JRUBY = defined?(JRUBY_VERSION)
|
20
|
-
|
21
|
-
require 'pathname'
|
22
|
-
require 'logger'
|
23
|
-
require 'yaml'
|
24
|
-
require 'active_support/inflector'
|
25
|
-
require 'ansi'
|
26
|
-
|
27
|
-
require 'elasticsearch'
|
28
|
-
require 'elasticsearch/extensions/test/cluster'
|
29
|
-
require 'elasticsearch/extensions/test/startup_shutdown'
|
30
|
-
require 'elasticsearch/extensions/test/profiling' unless JRUBY
|
31
|
-
|
32
|
-
# Skip features
|
33
|
-
skip_features = 'stash_in_path,requires_replica,headers,warnings,default_shards'
|
34
|
-
SKIP_FEATURES = ENV.fetch('TEST_SKIP_FEATURES', skip_features)
|
35
|
-
SKIPPED_TESTS = [ '/nodes.stats/30_discovery.yml' ]
|
36
|
-
|
37
|
-
# Launch test cluster
|
38
|
-
#
|
39
|
-
if ENV['SERVER'] and not Elasticsearch::Extensions::Test::Cluster.running?
|
40
|
-
Elasticsearch::Extensions::Test::Cluster.start
|
41
|
-
end
|
42
|
-
|
43
|
-
# Register `at_exit` handler for server shutdown.
|
44
|
-
# MUST be called before requiring `test/unit`.
|
45
|
-
#
|
46
|
-
at_exit { Elasticsearch::Extensions::Test::Cluster.stop if ENV['SERVER'] and Elasticsearch::Extensions::Test::Cluster.running? }
|
47
|
-
|
48
|
-
class String
|
49
|
-
# Reset the `ansi` method on CI
|
50
|
-
def ansi(*args)
|
51
|
-
self
|
52
|
-
end
|
53
|
-
end if ENV['CI']
|
54
|
-
|
55
|
-
module CapturedLogger
|
56
|
-
def self.included base
|
57
|
-
base.class_eval do
|
58
|
-
%w[ info error warn fatal debug ].each do |m|
|
59
|
-
alias_method "#{m}_without_capture", m
|
60
|
-
|
61
|
-
define_method m do |*args|
|
62
|
-
@logdev.__send__ :puts, *(args.join("\n") + "\n")
|
63
|
-
self.__send__ "#{m}_without_capture", *args
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
Logger.__send__ :include, CapturedLogger if ENV['CI']
|
71
|
-
|
72
|
-
logger = Logger.new($stderr)
|
73
|
-
logger.progname = 'elasticsearch'
|
74
|
-
logger.formatter = proc do |severity, datetime, progname, msg|
|
75
|
-
color = case severity
|
76
|
-
when /INFO/ then :green
|
77
|
-
when /ERROR|WARN|FATAL/ then :red
|
78
|
-
when /DEBUG/ then :cyan
|
79
|
-
else :white
|
80
|
-
end
|
81
|
-
"#{severity[0]} ".ansi(color, :faint) + msg.ansi(:white, :faint) + "\n"
|
82
|
-
end
|
83
|
-
|
84
|
-
tracer = Logger.new($stdout)
|
85
|
-
tracer.progname = 'elasticsearch.tracer'
|
86
|
-
tracer.formatter = proc { |severity, datetime, progname, msg| "#{msg}\n" }
|
87
|
-
|
88
|
-
# Set up the client for the test
|
89
|
-
#
|
90
|
-
# To set up your own client, just set the `$client` variable in a file, and then require it:
|
91
|
-
#
|
92
|
-
# ruby -I lib:test -r ./tmp/my_special_client.rb test/integration/yaml_test_runner.rb
|
93
|
-
#
|
94
|
-
url = ENV['TEST_CLUSTER_URL'] || ENV['TEST_ES_SERVER']
|
95
|
-
url = "http://localhost:#{ENV['TEST_CLUSTER_PORT'] || 9250}" unless url
|
96
|
-
$client ||= Elasticsearch::Client.new url: url
|
97
|
-
$helper_client ||= Elasticsearch::Client.new url: url
|
98
|
-
|
99
|
-
$client.transport.logger = logger unless ENV['QUIET'] || ENV['CI']
|
100
|
-
$client.transport.tracer = tracer if ENV['TRACE']
|
101
|
-
|
102
|
-
# Store Elasticsearch version
|
103
|
-
#
|
104
|
-
es_version_info = $client.info['version']
|
105
|
-
$es_version = es_version_info['number']
|
106
|
-
|
107
|
-
puts '-'*80,
|
108
|
-
"Elasticsearch #{$es_version.ansi(:bold)} [#{es_version_info['build_hash'].to_s[0...7]}]".center(80),
|
109
|
-
'-'*80
|
110
|
-
|
111
|
-
require 'test_helper'
|
112
|
-
|
113
|
-
class Elasticsearch::Test::YAMLTestReporter < ::MiniTest::Reporters::SpecReporter
|
114
|
-
def before_suite(suite)
|
115
|
-
puts ">>>>> #{suite.to_s} #{''.ljust(73-suite.to_s.size, '>')}" unless ENV['QUIET']
|
116
|
-
end
|
117
|
-
|
118
|
-
def after_suite(suite)
|
119
|
-
super unless ENV['QUIET']
|
120
|
-
end
|
121
|
-
|
122
|
-
def after_suites(suites, type)
|
123
|
-
time = Time.now - runner.suites_start_time
|
124
|
-
|
125
|
-
color = ( runner.errors > 0 || runner.failures > 0 ) ? :red : :green
|
126
|
-
status_line = "Finished in %.6fs, %.4f tests/s, %.4f assertions/s.\n".ansi(color) %
|
127
|
-
[time, runner.test_count / time, runner.assertion_count / time]
|
128
|
-
status_line += "#{runner.test_count} tests: #{runner.skips} skipped, #{runner.errors} errored, #{runner.failures} failed.".ansi(:bold, color)
|
129
|
-
|
130
|
-
puts '=' * 80
|
131
|
-
puts status_line
|
132
|
-
puts '-' * 80, ''
|
133
|
-
|
134
|
-
runner.test_results.each do |suite, tests|
|
135
|
-
tests.each do |test, test_runner|
|
136
|
-
next unless test_runner.result.to_s =~ /error|failure/
|
137
|
-
|
138
|
-
test_name = test_runner.test.to_s
|
139
|
-
.gsub(/^test_: /, '')
|
140
|
-
.gsub(/ should /, ' ')
|
141
|
-
.gsub(/\| .*$/, '')
|
142
|
-
.gsub(/\.\s*$/, '')
|
143
|
-
yaml_filename = test_runner.test.to_s.gsub(/.*\| (.*)\.\s*$/, '\1')
|
144
|
-
|
145
|
-
status = case test_runner.result
|
146
|
-
when :failure
|
147
|
-
"FAILURE"
|
148
|
-
when :error
|
149
|
-
"ERROR"
|
150
|
-
end
|
151
|
-
|
152
|
-
puts status.ansi(:red) +
|
153
|
-
" [#{test_runner.suite.to_s}] ".ansi(:red, :bold) +
|
154
|
-
test_name,
|
155
|
-
"<https://github.com/elastic/elasticsearch/blob/master/rest-api-spec/src/main/resources/rest-api-spec/test/#{yaml_filename}>".ansi(:underscore),
|
156
|
-
test_runner.exception.message.ansi(:faint), ''
|
157
|
-
end
|
158
|
-
end
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
Minitest::Reporters.use! Elasticsearch::Test::YAMLTestReporter.new
|
163
|
-
|
164
|
-
module Elasticsearch
|
165
|
-
module YamlTestSuite
|
166
|
-
$last_response = ''
|
167
|
-
$results = {}
|
168
|
-
$stash = {}
|
169
|
-
|
170
|
-
module Utils
|
171
|
-
def titleize(word)
|
172
|
-
word.to_s.gsub(/[^\w]+/, ' ').gsub(/\b('?[a-z])/) { $1.capitalize }.tr('_', ' ')
|
173
|
-
end
|
174
|
-
|
175
|
-
def symbolize_keys(object)
|
176
|
-
if object.is_a? Hash
|
177
|
-
object.reduce({}) { |memo,(k,v)| memo[k.to_s.to_sym] = symbolize_keys(v); memo }
|
178
|
-
else
|
179
|
-
object
|
180
|
-
end
|
181
|
-
end
|
182
|
-
|
183
|
-
extend self
|
184
|
-
end
|
185
|
-
|
186
|
-
module Runner
|
187
|
-
def perform_api_call(test, api, arguments=nil)
|
188
|
-
namespace = api.split('.')
|
189
|
-
|
190
|
-
replacer = lambda do |value|
|
191
|
-
case value
|
192
|
-
when Array
|
193
|
-
value.map { |v| replacer.call(v) }
|
194
|
-
when Hash
|
195
|
-
Hash[ value.map { |v| replacer.call(v) } ]
|
196
|
-
else
|
197
|
-
fetch_or_return value
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
timefixer = lambda do |value|
|
202
|
-
if value.is_a?(Time)
|
203
|
-
value.iso8601
|
204
|
-
else
|
205
|
-
value
|
206
|
-
end
|
207
|
-
end
|
208
|
-
|
209
|
-
arguments = Hash[
|
210
|
-
arguments.map do |key, value|
|
211
|
-
replacement = replacer.call(value)
|
212
|
-
replacement = timefixer.call(replacement)
|
213
|
-
[key, replacement]
|
214
|
-
end
|
215
|
-
]
|
216
|
-
|
217
|
-
$stderr.puts "ARGUMENTS: #{arguments.inspect}" if ENV['DEBUG']
|
218
|
-
|
219
|
-
$last_response = namespace.reduce($client) do |memo, current|
|
220
|
-
unless current == namespace.last
|
221
|
-
memo = memo.send(current)
|
222
|
-
else
|
223
|
-
arguments ? memo = memo.send(current, arguments) : memo = memo.send(current)
|
224
|
-
end
|
225
|
-
memo
|
226
|
-
end
|
227
|
-
|
228
|
-
$results[test.hash] = $last_response
|
229
|
-
end
|
230
|
-
|
231
|
-
def evaluate(test, property, response=nil)
|
232
|
-
response ||= $results[test.hash]
|
233
|
-
property.gsub(/\\\./, '_____').split('.').reduce(response) do |memo, attr|
|
234
|
-
if memo
|
235
|
-
if attr
|
236
|
-
attr = attr.gsub(/_____/, '.')
|
237
|
-
attr = $stash[attr] if attr.start_with? '$'
|
238
|
-
end
|
239
|
-
memo = memo.is_a?(Hash) ? memo[attr] : memo[attr.to_i]
|
240
|
-
end
|
241
|
-
memo
|
242
|
-
end
|
243
|
-
end
|
244
|
-
|
245
|
-
def in_context(name, &block)
|
246
|
-
klass = Class.new(YamlTestCase)
|
247
|
-
Object::const_set "%sTest" % name.split(/\s/).map { |d| d.capitalize }.join('').gsub(/[^\w]+/, ''), klass
|
248
|
-
klass.context "[#{name.ansi(:bold)}]", &block
|
249
|
-
end
|
250
|
-
|
251
|
-
def fetch_or_return(var)
|
252
|
-
if var.is_a?(String) && var =~ /^\$(.+)/
|
253
|
-
$stash[var]
|
254
|
-
else
|
255
|
-
var
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
def set(var, val)
|
260
|
-
$stash["$#{var}"] = val
|
261
|
-
end
|
262
|
-
|
263
|
-
def skip?(actions)
|
264
|
-
skip = actions.select { |a| a['skip'] }.first
|
265
|
-
$stderr.puts "SKIP: #{skip.inspect}" if ENV['DEBUG']
|
266
|
-
|
267
|
-
def skip_version(skip)
|
268
|
-
if skip && skip['skip']['version']
|
269
|
-
|
270
|
-
return skip['skip']['reason'] ? skip['skip']['reason'] : true if skip['skip']['version'] == 'all'
|
271
|
-
|
272
|
-
min, max = skip['skip']['version'].split('-').map(&:strip)
|
273
|
-
|
274
|
-
min_normalized = sprintf "%03d-%03d-%03d",
|
275
|
-
*min.split('.')
|
276
|
-
.map(&:to_i)
|
277
|
-
.fill(0, min.split('.').length, 3-min.split('.').length)
|
278
|
-
|
279
|
-
max_normalized = sprintf "%03d-%03d-%03d",
|
280
|
-
*max.split('.')
|
281
|
-
.map(&:to_i)
|
282
|
-
.map(&:to_i)
|
283
|
-
.fill(0, max.split('.').length, 3-max.split('.').length)
|
284
|
-
|
285
|
-
es_normalized = sprintf "%03d-%03d-%03d", *$es_version.split('.').map(&:to_i)
|
286
|
-
|
287
|
-
if ( min.empty? || min_normalized <= es_normalized ) && ( max.empty? || max_normalized >= es_normalized )
|
288
|
-
return skip['skip']['reason'] ? skip['skip']['reason'] : true
|
289
|
-
end
|
290
|
-
|
291
|
-
return false
|
292
|
-
end
|
293
|
-
end
|
294
|
-
|
295
|
-
def skip_features(skip)
|
296
|
-
if skip && skip['skip']['features']
|
297
|
-
skip_features = skip['skip']['features'].respond_to?(:split) ? skip['skip']['features'].split(',') : skip['skip']['features']
|
298
|
-
if ( skip_features & SKIP_FEATURES.split(',') ).size > 0
|
299
|
-
return skip['skip']['features']
|
300
|
-
end
|
301
|
-
end
|
302
|
-
end
|
303
|
-
|
304
|
-
return skip_version(skip) || skip_features(skip)
|
305
|
-
end
|
306
|
-
|
307
|
-
extend self
|
308
|
-
end
|
309
|
-
|
310
|
-
class YamlTestCase < ::Minitest::Test; end
|
311
|
-
end
|
312
|
-
end
|
313
|
-
|
314
|
-
include Elasticsearch::YamlTestSuite
|
315
|
-
|
316
|
-
rest_api_test_source = '../../../../tmp/elasticsearch/rest-api-spec/src/main/resources/rest-api-spec/test'
|
317
|
-
PATH = Pathname(ENV.fetch('TEST_REST_API_SPEC', File.expand_path(rest_api_test_source, __FILE__)))
|
318
|
-
|
319
|
-
suites = Dir.glob(PATH.join('*')).map { |d| Pathname(d) }
|
320
|
-
suites = suites.select { |s| s.to_s =~ Regexp.new(ENV['FILTER']) } if ENV['FILTER']
|
321
|
-
|
322
|
-
suites.each do |suite|
|
323
|
-
name = Elasticsearch::YamlTestSuite::Utils.titleize(suite.basename)
|
324
|
-
|
325
|
-
Elasticsearch::YamlTestSuite::Runner.in_context name do
|
326
|
-
|
327
|
-
# --- Register context setup -------------------------------------------
|
328
|
-
#
|
329
|
-
setup do
|
330
|
-
$helper_client.indices.delete index: '_all', ignore: 404
|
331
|
-
$helper_client.indices.delete index: 'test-weird-index*', ignore: 404
|
332
|
-
$helper_client.indices.delete_template name: 'nomatch', ignore: 404
|
333
|
-
$helper_client.indices.delete_template name: 'test_2', ignore: 404
|
334
|
-
$helper_client.indices.delete_template name: 'test2', ignore: 404
|
335
|
-
$helper_client.indices.delete_template name: 'test', ignore: 404
|
336
|
-
$helper_client.indices.delete_template name: 'index_template', ignore: 404
|
337
|
-
$helper_client.indices.delete_template name: 'test_no_mappings', ignore: 404
|
338
|
-
$helper_client.indices.delete_template name: 'test_template', ignore: 404
|
339
|
-
$helper_client.snapshot.delete repository: 'test_repo_create_1', snapshot: 'test_snapshot', ignore: 404
|
340
|
-
$helper_client.snapshot.delete repository: 'test_repo_restore_1', snapshot: 'test_snapshot', ignore: 404
|
341
|
-
$helper_client.snapshot.delete repository: 'test_cat_snapshots_1', snapshot: 'snap1', ignore: 404
|
342
|
-
$helper_client.snapshot.delete repository: 'test_cat_snapshots_1', snapshot: 'snap2', ignore: 404
|
343
|
-
$helper_client.snapshot.delete_repository repository: 'test_repo_create_1', ignore: 404
|
344
|
-
$helper_client.snapshot.delete_repository repository: 'test_repo_restore_1', ignore: 404
|
345
|
-
$helper_client.snapshot.delete_repository repository: 'test_repo_get_1', ignore: 404
|
346
|
-
$helper_client.snapshot.delete_repository repository: 'test_repo_get_2', ignore: 404
|
347
|
-
$helper_client.snapshot.delete_repository repository: 'test_repo_status_1', ignore: 404
|
348
|
-
$helper_client.snapshot.delete_repository repository: 'test_cat_repo_1', ignore: 404
|
349
|
-
$helper_client.snapshot.delete_repository repository: 'test_cat_repo_2', ignore: 404
|
350
|
-
$helper_client.snapshot.delete_repository repository: 'test_cat_snapshots_1', ignore: 404
|
351
|
-
# FIXME: This shouldn't be needed -------------
|
352
|
-
%w[
|
353
|
-
test_cat_repo_1_loc
|
354
|
-
test_cat_repo_2_loc
|
355
|
-
test_cat_snapshots_1_loc
|
356
|
-
test_repo_get_1_loc
|
357
|
-
test_repo_status_1_loc
|
358
|
-
].each do |d|
|
359
|
-
FileUtils.rm_rf("/tmp/#{d}")
|
360
|
-
end
|
361
|
-
# ---------------------------------------------
|
362
|
-
$results = {}
|
363
|
-
$stash = {}
|
364
|
-
end
|
365
|
-
|
366
|
-
# --- Register context teardown ----------------------------------------
|
367
|
-
#
|
368
|
-
teardown do
|
369
|
-
$helper_client.indices.delete index: '_all', ignore: 404
|
370
|
-
|
371
|
-
# Wipe out cluster "transient" settings
|
372
|
-
settings = $helper_client.cluster.get_settings(flat_settings: true)['transient'].keys.reduce({}) {|s,i| s[i] = nil; s}
|
373
|
-
$helper_client.cluster.put_settings body: { transient: settings } unless settings.empty?
|
374
|
-
end
|
375
|
-
|
376
|
-
files = Dir[suite.join('*.{yml,yaml}')]
|
377
|
-
files.each do |file|
|
378
|
-
next if SKIPPED_TESTS.any? { |test| file =~ /#{test}/ }
|
379
|
-
begin
|
380
|
-
tests = YAML.load_stream File.new(file)
|
381
|
-
rescue RuntimeError => e
|
382
|
-
$stderr.puts "ERROR [#{e.class}] while loading [#{file}] file".ansi(:red)
|
383
|
-
# raise e
|
384
|
-
next
|
385
|
-
end
|
386
|
-
|
387
|
-
# Extract setup actions
|
388
|
-
setup_actions = tests.select { |t| t['setup'] }.first['setup'] rescue []
|
389
|
-
|
390
|
-
# Skip all the tests when `skip` is part of the `setup` part
|
391
|
-
if features = Runner.skip?(setup_actions)
|
392
|
-
$stdout.puts "#{'SKIP'.ansi(:yellow)} [#{name}] #{file.gsub(PATH.to_s, '').ansi(:bold)} (Feature not implemented: #{features})"
|
393
|
-
next
|
394
|
-
end
|
395
|
-
|
396
|
-
# Remove setup actions from tests
|
397
|
-
tests = tests.reject { |t| t['setup'] }
|
398
|
-
|
399
|
-
# Add setup actions to each individual test
|
400
|
-
tests.each { |t| t[t.keys.first] << { 'setup' => setup_actions } }
|
401
|
-
|
402
|
-
tests.each do |test|
|
403
|
-
context '' do
|
404
|
-
yaml_file_line = File.read(file).force_encoding("UTF-8").split("\n").index {|l| l.include? test.keys.first.to_s }
|
405
|
-
|
406
|
-
l = yaml_file_line ? "#L#{yaml_file_line.to_i + 1}" : ''
|
407
|
-
test_name = test.keys.first.to_s + " | #{file.gsub(PATH.to_s, '').gsub(/^\//, '')}" + l
|
408
|
-
actions = test.values.first
|
409
|
-
|
410
|
-
if reason = Runner.skip?(actions)
|
411
|
-
$stdout.puts "#{'SKIP'.ansi(:yellow)} [#{name}] #{test_name} (Reason: #{reason})"
|
412
|
-
next
|
413
|
-
end
|
414
|
-
|
415
|
-
# --- Register test setup -------------------------------------------
|
416
|
-
setup do
|
417
|
-
setup_actions = actions.select { |a| a['setup'] }
|
418
|
-
setup_actions.first['setup'].each do |action|
|
419
|
-
if action['do']
|
420
|
-
api, arguments = action['do'].to_a.first
|
421
|
-
arguments = Utils.symbolize_keys(arguments)
|
422
|
-
Runner.perform_api_call((test.to_s + '___setup'), api, arguments)
|
423
|
-
end
|
424
|
-
if action['set']
|
425
|
-
stash = action['set']
|
426
|
-
property, variable = stash.to_a.first
|
427
|
-
result = Runner.evaluate(test, property, $last_response)
|
428
|
-
$stderr.puts "STASH: '$#{variable}' => #{result.inspect}" if ENV['DEBUG']
|
429
|
-
Runner.set variable, result
|
430
|
-
end
|
431
|
-
end unless setup_actions.empty?
|
432
|
-
end
|
433
|
-
|
434
|
-
teardown do
|
435
|
-
teardown_actions = actions.select { |a| a['teardown'] }
|
436
|
-
teardown_actions.first['teardown'].each do |action|
|
437
|
-
if action['do']
|
438
|
-
api, arguments = action['do'].to_a.first
|
439
|
-
arguments = Utils.symbolize_keys(arguments)
|
440
|
-
Runner.perform_api_call((test.to_s + '___teardown'), api, arguments)
|
441
|
-
end
|
442
|
-
if action['set']
|
443
|
-
stash = action['set']
|
444
|
-
property, variable = stash.to_a.first
|
445
|
-
result = Runner.evaluate(test, property, $last_response)
|
446
|
-
$stderr.puts "STASH: '$#{variable}' => #{result.inspect}" if ENV['DEBUG']
|
447
|
-
Runner.set variable, result
|
448
|
-
end
|
449
|
-
end unless teardown_actions.empty?
|
450
|
-
end
|
451
|
-
|
452
|
-
# --- Register test method ------------------------------------------
|
453
|
-
should test_name do
|
454
|
-
if ENV['CI']
|
455
|
-
ref = ENV['TEST_BUILD_REF'].to_s.gsub(/origin\//, '') || 'master'
|
456
|
-
$stderr.puts "https://github.com/elasticsearch/elasticsearch/blob/#{ref}/rest-api-spec/test/" \
|
457
|
-
+ file.gsub(PATH.to_s, ''), ""
|
458
|
-
$stderr.puts YAML.dump(test) if ENV['DEBUG']
|
459
|
-
end
|
460
|
-
actions.each do |action|
|
461
|
-
$stderr.puts "ACTION: #{action.inspect}" if ENV['DEBUG']
|
462
|
-
|
463
|
-
# This check verifies that the YAML has correct indentation.
|
464
|
-
# See https://github.com/elastic/elasticsearch/issues/21980
|
465
|
-
raise "INVALID YAML: #{action.inspect}" if action.keys.size != 1
|
466
|
-
|
467
|
-
case
|
468
|
-
|
469
|
-
# --- Perform action ------------------------------------------
|
470
|
-
#
|
471
|
-
when action['do']
|
472
|
-
catch_exception = action['do'].delete('catch') if action['do']
|
473
|
-
api, arguments = action['do'].to_a.first
|
474
|
-
arguments = Utils.symbolize_keys(arguments)
|
475
|
-
|
476
|
-
begin
|
477
|
-
$results[test.hash] = Runner.perform_api_call(test, api, arguments)
|
478
|
-
rescue StandardError => e
|
479
|
-
begin
|
480
|
-
$results[test.hash] = MultiJson.load(e.message.match(/{.+}/, 1).to_s)
|
481
|
-
rescue MultiJson::ParseError
|
482
|
-
$stderr.puts "RESPONSE: Cannot parse JSON from error message: '#{e.message}'" if ENV['DEBUG']
|
483
|
-
end
|
484
|
-
|
485
|
-
if catch_exception
|
486
|
-
$stderr.puts "CATCH: '#{catch_exception}': #{e.inspect}" if ENV['DEBUG']
|
487
|
-
|
488
|
-
if 'param' == catch_exception
|
489
|
-
assert_equal 'ArgumentError', e.class.to_s
|
490
|
-
else
|
491
|
-
if e.class.to_s =~ /Elasticsearch/
|
492
|
-
case catch_exception
|
493
|
-
when 'missing'
|
494
|
-
assert_match /\[404\]/, e.message
|
495
|
-
when 'conflict'
|
496
|
-
assert_match /\[409\]/, e.message
|
497
|
-
when 'request'
|
498
|
-
assert_match /\[4\d\d\]|\[5\d\d\]/, e.message
|
499
|
-
when /\/.+\//
|
500
|
-
assert_match Regexp.new(catch_exception.tr('/', '')), e.message
|
501
|
-
end
|
502
|
-
else
|
503
|
-
raise e
|
504
|
-
end
|
505
|
-
end
|
506
|
-
|
507
|
-
else
|
508
|
-
raise e
|
509
|
-
end
|
510
|
-
end
|
511
|
-
|
512
|
-
# --- Evaluate predicates -------------------------------------
|
513
|
-
#
|
514
|
-
when property = action['is_true']
|
515
|
-
result = Runner.evaluate(test, property)
|
516
|
-
$stderr.puts "CHECK: Expected '#{property}' to be true, is: #{result.inspect}" if ENV['DEBUG']
|
517
|
-
assert(result, "Property '#{property}' should be true, is: #{result.inspect}")
|
518
|
-
|
519
|
-
when property = action['is_false']
|
520
|
-
result = Runner.evaluate(test, property)
|
521
|
-
$stderr.puts "CHECK: Expected '#{property}' to be nil, false, 0 or empty string, is: #{result.inspect}" if ENV['DEBUG']
|
522
|
-
assert_block "Property '#{property}' should be nil, false, 0 or empty string, but is: #{result.inspect}" do
|
523
|
-
result.nil? || result == false || result == 0 || result == ''
|
524
|
-
end
|
525
|
-
|
526
|
-
when a = action['match']
|
527
|
-
property, value = a.to_a.first
|
528
|
-
|
529
|
-
if value.is_a?(String) && value =~ %r{\s*^/\s*.*\s*/$\s*}mx # Begins and ends with /
|
530
|
-
pattern = Regexp.new(value.strip[1..-2], Regexp::EXTENDED|Regexp::MULTILINE)
|
531
|
-
else
|
532
|
-
value = Runner.fetch_or_return(value)
|
533
|
-
end
|
534
|
-
|
535
|
-
if property == '$body'
|
536
|
-
result = $results[test.hash]
|
537
|
-
else
|
538
|
-
result = Runner.evaluate(test, property)
|
539
|
-
end
|
540
|
-
|
541
|
-
if pattern
|
542
|
-
$stderr.puts "CHECK: Expected '#{property}' to match #{pattern}, is: #{result.inspect}" if ENV['DEBUG']
|
543
|
-
assert_match(pattern, result)
|
544
|
-
else
|
545
|
-
value = value.reduce({}) { |memo, (k,v)| memo[k] = Runner.fetch_or_return(v); memo } if value.is_a? Hash
|
546
|
-
$stderr.puts "CHECK: Expected '#{property}' to be '#{value}', is: #{result.inspect}" if ENV['DEBUG']
|
547
|
-
|
548
|
-
assert_equal(value, result)
|
549
|
-
end
|
550
|
-
|
551
|
-
when a = action['length']
|
552
|
-
property, value = a.to_a.first
|
553
|
-
|
554
|
-
result = Runner.evaluate(test, property)
|
555
|
-
length = result.size
|
556
|
-
$stderr.puts "CHECK: Expected '#{property}' to be #{value}, is: #{length.inspect}" if ENV['DEBUG']
|
557
|
-
assert_equal(value, length)
|
558
|
-
|
559
|
-
when a = action['lt'] || action['gt'] || action['lte'] || action['gte']
|
560
|
-
property, value = a.to_a.first
|
561
|
-
operator = case
|
562
|
-
when action['lt']
|
563
|
-
'<'
|
564
|
-
when action['gt']
|
565
|
-
'>'
|
566
|
-
when action['lte']
|
567
|
-
'<='
|
568
|
-
when action['gte']
|
569
|
-
'>='
|
570
|
-
end
|
571
|
-
|
572
|
-
result = Runner.evaluate(test, property)
|
573
|
-
message = "Expected '#{property}' to be #{operator} #{value}, is: #{result.inspect}"
|
574
|
-
|
575
|
-
$stderr.puts "CHECK: #{message}" if ENV['DEBUG']
|
576
|
-
assert_operator result, operator.to_sym, Runner.fetch_or_return(value).to_i
|
577
|
-
|
578
|
-
when stash = action['set']
|
579
|
-
property, variable = stash.to_a.first
|
580
|
-
result = Runner.evaluate(test, property)
|
581
|
-
$stderr.puts "STASH: '$#{variable}' => #{result.inspect}" if ENV['DEBUG']
|
582
|
-
Runner.set variable, result
|
583
|
-
end
|
584
|
-
end
|
585
|
-
end
|
586
|
-
end
|
587
|
-
end
|
588
|
-
end
|
589
|
-
|
590
|
-
end
|
591
|
-
|
592
|
-
end
|