/* * Licensed to Elasticsearch under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.elasticsearch.test.rest.yaml.section; import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.yaml.YamlXContent; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; import java.util.ArrayList; import java.util.List; import java.util.Set; import java.util.TreeSet; /** * Holds a REST test suite loaded from a specific yaml file. * Supports a setup section and multiple test sections. */ public class ClientYamlTestSuite { public static ClientYamlTestSuite parse(String api, Path file) throws IOException { if (!Files.isRegularFile(file)) { throw new IllegalArgumentException(file.toAbsolutePath() + " is not a file"); } String filename = file.getFileName().toString(); //remove the file extension int i = filename.lastIndexOf('.'); if (i > 0) { filename = filename.substring(0, i); } //our yaml parser seems to be too tolerant. Each yaml suite must end with \n, otherwise clients tests might break. try (FileChannel channel = FileChannel.open(file, StandardOpenOption.READ)) { ByteBuffer bb = ByteBuffer.wrap(new byte[1]); channel.read(bb, channel.size() - 1); if (bb.get(0) != 10) { throw new IOException("test suite [" + api + "/" + filename + "] doesn't end with line feed (\\n)"); } } try (XContentParser parser = YamlXContent.yamlXContent.createParser(ExecutableSection.XCONTENT_REGISTRY, Files.newInputStream(file))) { return parse(api, filename, parser); } catch(Exception e) { throw new IOException("Error parsing " + api + "/" + filename, e); } } public static ClientYamlTestSuite parse(String api, String suiteName, XContentParser parser) throws IOException { parser.nextToken(); assert parser.currentToken() == XContentParser.Token.START_OBJECT : "expected token to be START_OBJECT but was " + parser.currentToken(); ClientYamlTestSuite restTestSuite = new ClientYamlTestSuite(api, suiteName); restTestSuite.setSetupSection(SetupSection.parseIfNext(parser)); restTestSuite.setTeardownSection(TeardownSection.parseIfNext(parser)); while(true) { //the "---" section separator is not understood by the yaml parser. null is returned, same as when the parser is closed //we need to somehow distinguish between a null in the middle of a test ("---") // and a null at the end of the file (at least two consecutive null tokens) if(parser.currentToken() == null) { if (parser.nextToken() == null) { break; } } ClientYamlTestSection testSection = ClientYamlTestSection.parse(parser); if (!restTestSuite.addTestSection(testSection)) { throw new ParsingException(testSection.getLocation(), "duplicate test section [" + testSection.getName() + "]"); } } return restTestSuite; } private final String api; private final String name; private SetupSection setupSection; private TeardownSection teardownSection; private Set<ClientYamlTestSection> testSections = new TreeSet<>(); public ClientYamlTestSuite(String api, String name) { this.api = api; this.name = name; } public String getApi() { return api; } public String getName() { return name; } public String getPath() { return api + "/" + name; } public SetupSection getSetupSection() { return setupSection; } public void setSetupSection(SetupSection setupSection) { this.setupSection = setupSection; } public TeardownSection getTeardownSection() { return teardownSection; } public void setTeardownSection(TeardownSection teardownSection) { this.teardownSection = teardownSection; } /** * Adds a {@link org.elasticsearch.test.rest.yaml.section.ClientYamlTestSection} to the REST suite * @return true if the test section was not already present, false otherwise */ public boolean addTestSection(ClientYamlTestSection testSection) { return this.testSections.add(testSection); } public List<ClientYamlTestSection> getTestSections() { return new ArrayList<>(testSections); } }