org.apache.solr.SolrTestCaseHS.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.solr.SolrTestCaseHS.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF 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.apache.solr;

import java.io.File;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.invoke.MethodHandles;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import java.util.Set;

import org.apache.commons.io.FileUtils;
import org.apache.lucene.util.IOUtils;
import org.apache.solr.client.solrj.SolrClient;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.embedded.JettyConfig;
import org.apache.solr.client.solrj.embedded.JettySolrRunner;
import org.apache.solr.client.solrj.impl.NoOpResponseParser;
import org.apache.solr.client.solrj.request.QueryRequest;
import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.response.UpdateResponse;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.CoreDescriptor;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.servlet.DirectSolrConnection;
import org.noggit.JSONUtil;
import org.noggit.ObjectBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@SolrTestCaseJ4.SuppressSSL
//@LuceneTestCase.SuppressCodecs({"Lucene3x","Lucene40","Lucene41","Lucene42","Lucene45","Appending","Asserting"})
public class SolrTestCaseHS extends SolrTestCaseJ4 {

    private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

    @SafeVarargs
    public static <T> Set<T> set(T... a) {
        LinkedHashSet<T> s = new LinkedHashSet<>();
        for (T t : a) {
            s.add(t);
        }
        return s;
    }

    public static <T> T rand(T... vals) {
        return vals[random().nextInt(vals.length)];
    }

    public static ModifiableSolrParams params(SolrParams params, String... moreParams) {
        ModifiableSolrParams msp = new ModifiableSolrParams(params);
        for (int i = 0; i < moreParams.length; i += 2) {
            msp.add(moreParams[i], moreParams[i + 1]);
        }
        return msp;
    }

    public static Map<String, Object> toObject(Doc doc, IndexSchema schema, Collection<String> fieldNames) {
        Map<String, Object> result = new HashMap<>();
        for (Fld fld : doc.fields) {
            if (fieldNames != null && !fieldNames.contains(fld.ftype.fname))
                continue;
            SchemaField sf = schema.getField(fld.ftype.fname);
            if (!sf.multiValued()) {
                result.put(fld.ftype.fname, fld.vals.get(0));
            } else {
                result.put(fld.ftype.fname, fld.vals);
            }
        }
        return result;
    }

    public static Object createDocObjects(Map<Comparable, Doc> fullModel, Comparator sort, int rows,
            Collection<String> fieldNames) {
        List<Doc> docList = new ArrayList<>(fullModel.values());
        Collections.sort(docList, sort);
        List sortedDocs = new ArrayList(rows);
        for (Doc doc : docList) {
            if (sortedDocs.size() >= rows)
                break;
            Map<String, Object> odoc = toObject(doc, h.getCore().getLatestSchema(), fieldNames);
            sortedDocs.add(toObject(doc, h.getCore().getLatestSchema(), fieldNames));
        }
        return sortedDocs;
    }

    public static void compare(SolrQueryRequest req, String path, Object model, Map<Comparable, Doc> fullModel)
            throws Exception {
        String strResponse = h.query(req);

        Object realResponse = ObjectBuilder.fromJSON(strResponse);
        String err = JSONTestUtil.matchObj(path, realResponse, model);
        if (err != null) {
            log.error("RESPONSE MISMATCH: " + err + "\n\trequest=" + req + "\n\tresult=" + strResponse
                    + "\n\texpected=" + JSONUtil.toJSON(model) + "\n\tmodel=" + fullModel);

            // re-execute the request... good for putting a breakpoint here for debugging
            String rsp = h.query(req);

            fail(err);
        }

    }

    /** Pass "null" for the client to query the local server */
    public static void assertJQ(SolrClient client, SolrParams args, String... tests) throws Exception {
        String resp;
        resp = getJSON(client, args);
        matchJSON(resp, tests);
    }

    public static void matchJSON(String response, String... tests) throws Exception {
        boolean failed = false;

        for (String test : tests) {
            if (test == null || test.length() == 0)
                continue;

            try {
                failed = true;
                String err = JSONTestUtil.match(response, test, JSONTestUtil.DEFAULT_DELTA);
                failed = false;
                if (err != null) {
                    log.error("query failed JSON validation. error=" + err + "\n expected =" + test
                            + "\n response = " + response);
                    throw new RuntimeException(err);
                }
            } finally {
                if (failed) {
                    log.error("JSON query validation threw an exception." + "\n expected =" + test
                            + "\n response = " + response);
                }
            }
        }
    }

    /***
    public static void clearNCache() {
      SolrQueryRequest req = req();
      req.getSearcher().getnCache().clear();  // OFF-HEAP
      req.close();
    }***/

    public static void clearQueryCache() {
        SolrQueryRequest req = req();
        req.getSearcher();
        req.close();
    }

    public static String getQueryResponse(SolrClient client, String wt, SolrParams params) throws Exception {
        if (client == null) {
            return getQueryResponse(wt, params);
        }
        ModifiableSolrParams p = new ModifiableSolrParams(params);
        p.set("wt", wt);
        String path = p.get("qt");
        p.remove("qt");
        p.set("indent", "true");

        QueryRequest query = new QueryRequest(p);
        if (path != null) {
            query.setPath(path);
        }

        query.setResponseParser(new NoOpResponseParser(wt));
        NamedList<Object> rsp = client.request(query);

        String raw = (String) rsp.get("response");

        return raw;
    }

    public static String getQueryResponse(String wt, SolrParams params) throws Exception {
        ModifiableSolrParams p = new ModifiableSolrParams(params);
        p.set("wt", wt);
        String path = p.get("qt");
        p.remove("qt");
        p.set("indent", "true");

        DirectSolrConnection connection = new DirectSolrConnection(h.getCore());
        String raw = connection.request(path, p, null);
        return raw;
    }

    public static String getJSON(SolrClient client, SolrParams params) throws Exception {
        return getQueryResponse(client, "json", params);
    }

    /** Adds a document using the specific client, or to the local test core if null.
     * Returns the version.  TODO: work in progress... version not always returned.  */
    public static Long add(SolrClient client, SolrInputDocument sdoc, ModifiableSolrParams params)
            throws Exception {
        if (client == null) {
            Long version = addAndGetVersion(sdoc, params);
            return version;
        } else {
            UpdateRequest updateRequest = new UpdateRequest();
            if (params != null) {
                updateRequest.setParams(params);
            }
            updateRequest.add(sdoc);
            UpdateResponse rsp = updateRequest.process(client);
            // TODO - return version
            return null;
        }
    }

    public static class Client {
        ClientProvider provider;
        ModifiableSolrParams queryDefaults;
        public Tester tester = new Tester();

        public static class Tester {
            public void assertJQ(SolrClient client, SolrParams args, String... tests) throws Exception {
                SolrTestCaseHS.assertJQ(client, args, tests);
            }
        }

        public static Client localClient = new Client(null, 1);

        public static Client localClient() {
            return new Client(null, 1);
        }

        public Client(List<SolrClient> clients, int seed) {
            if (clients != null) {
                provider = new ClientProvider(clients, seed);
            }
        }

        public static int hash(int x) {
            // from Thomas Mueller
            x = ((x >>> 16) ^ x) * 0x45d9f3b;
            x = ((x >>> 16) ^ x) * 0x45d9f3b;
            x = ((x >>> 16) ^ x);
            return x;
        }

        public ModifiableSolrParams queryDefaults() {
            if (queryDefaults == null) {
                queryDefaults = new ModifiableSolrParams();
            }
            return queryDefaults;
        }

        public boolean local() {
            return provider == null;
        }

        public ClientProvider getClientProvider() {
            return provider;
        }

        public void testJQ(SolrParams args, String... tests) throws Exception {
            if (queryDefaults != null) {
                ModifiableSolrParams newParams = params(queryDefaults);
                newParams.add(args);
                args = newParams;
            }
            SolrClient client = provider == null ? null : provider.client(null, args);
            tester.assertJQ(client, args, tests);
        }

        public Long add(SolrInputDocument sdoc, ModifiableSolrParams params) throws Exception {
            SolrClient client = provider == null ? null : provider.client(sdoc, params);
            return SolrTestCaseHS.add(client, sdoc, params);
        }

        public void commit() throws IOException, SolrServerException {
            if (local()) {
                assertU(SolrTestCaseJ4.commit());
                return;
            }

            for (SolrClient client : provider.all()) {
                client.commit();
            }
        }

        public void deleteByQuery(String query, ModifiableSolrParams params)
                throws IOException, SolrServerException {
            if (local()) {
                assertU(delQ(query)); // todo - handle extra params
                return;
            }

            for (SolrClient client : provider.all()) {
                client.deleteByQuery(query); // todo - handle extra params
            }
        }

    }

    public static class ClientProvider {
        public static String idField = "id";

        List<SolrClient> clients;
        Random r;
        int hashSeed;

        // thisIsIgnored needed because we need a diff signature
        public ClientProvider(List<SolrClient> clients, int seed) {
            this.hashSeed = Client.hash(seed);
            this.clients = clients;
            r = new Random(seed);
        }

        public SolrClient client(SolrInputDocument sdoc, SolrParams params) {
            String idStr = null;
            if (sdoc != null) {
                idStr = sdoc.getFieldValue(idField).toString();
            } else if (params != null) {
                idStr = params.get(idField);
            }

            int hash;
            if (idStr != null) {
                // make the client chosen the same for a duplicate ID
                hash = idStr.hashCode() ^ hashSeed;
            } else {
                hash = r.nextInt();
            }

            return clients.get((hash & Integer.MAX_VALUE) % clients.size());
        }

        public List<SolrClient> all() {
            return clients;
        }

        public int getSeed() {
            return hashSeed;
        }
    }

    //
    // Helper to run an internal Jetty instance.
    // Example:
    //  SolrInstance s1 = new SolrInstance(createTempDir("s1"), "solrconfig-tlog.xml", "schema_latest.xml");
    //  s1.start();
    //  SolrClient c1 = s1.getSolrJ();
    //  assertJQ(c1, params("q", "*:*"), "/response/numFound==3");
    //  String json = getJSON(c1, params("q","id:1"));
    //  s1.stop();
    //
    // To manage multiple servers, see SolrInstances
    //
    public static class SolrInstance {
        private static Logger log = SolrTestCaseHS.log;
        private String collection = "collection1";
        private int port = 0;
        private String solrconfigFile;
        private String schemaFile;
        private File baseDir;
        private JettySolrRunner jetty;
        private SolrClient solrj;

        private boolean homeCreated = false;

        public SolrInstance(File homeDir, String solrconfigFile, String schemaFile) {
            this.baseDir = homeDir;
            this.solrconfigFile = solrconfigFile;
            this.schemaFile = schemaFile;
        }

        public String getBaseDir() {
            return baseDir.toString();
        }

        public String getBaseURL() {
            return (SolrTestCaseJ4.isSSLMode() ? "https" : "http") + "://127.0.0.1:" + port + "/solr";
        }

        public String getCollectionURL() {
            return getBaseURL() + "/" + collection;
        }

        /** string appropriate for passing in shards param (i.e. missing http://) */
        public String getShardURL() {
            return "127.0.0.1:" + port + "/solr" + "/" + collection;
        }

        public SolrClient getSolrJ() {
            if (solrj == null) {
                solrj = getHttpSolrClient(getCollectionURL());
            }
            return solrj;
        }

        /** If it needs to change */
        public void setPort(int port) {
            this.port = port;
        }

        public void createHome() throws Exception {
            homeCreated = true;
            SolrTestCaseJ4.copySolrHomeToTemp(baseDir, collection);
            copyConfFile(baseDir, collection, solrconfigFile);
            copyConfFile(baseDir, collection, schemaFile);

            File collDir = new File(baseDir, collection);
            try (Writer w = new OutputStreamWriter(
                    Files.newOutputStream(collDir.toPath().resolve("core.properties")), StandardCharsets.UTF_8)) {
                Properties coreProps = new Properties();
                coreProps.put("name", "collection1");
                coreProps.put("config", solrconfigFile);
                coreProps.put("schema", schemaFile);
                coreProps.store(w, "");
            }
        }

        public void start() throws Exception {
            if (!homeCreated) {
                createHome();
            }

            if (jetty == null) {
                JettyConfig jettyConfig = JettyConfig.builder().stopAtShutdown(true).setContext("/solr")
                        .setPort(port).withSSLConfig(sslConfig).build();
                Properties nodeProperties = new Properties();
                nodeProperties.setProperty("solrconfig", solrconfigFile);
                nodeProperties.setProperty(CoreDescriptor.CORE_SCHEMA, schemaFile);
                jetty = new JettySolrRunner(baseDir.getAbsolutePath(), nodeProperties, jettyConfig);
            }

            // silly stuff included from solrconfig.snippet.randomindexconfig.xml
            System.setProperty("solr.tests.maxBufferedDocs", String.valueOf(100000));

            jetty.start();
            port = jetty.getLocalPort();
            log.info("===> Started solr server port=" + port + " home=" + getBaseDir());
        }

        public void stop() throws Exception {
            jetty.stop();
            if (solrj != null)
                solrj.close();
        }

        public void tearDown() throws Exception {
            IOUtils.deleteFilesIfExist(baseDir.toPath());
        }

        private static void copyConfFile(File dstRoot, String destCollection, String file) throws Exception {
            File subHome = new File(dstRoot, destCollection + File.separator + "conf");
            String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
            FileUtils.copyFile(new File(top, file), new File(subHome, file));
        }

        public void copyConfigFile(File dstRoot, String destCollection, String file) throws Exception {
            if (!homeCreated) {
                createHome();
            }

            File subHome = new File(dstRoot, destCollection + File.separator + "conf");
            String top = SolrTestCaseJ4.TEST_HOME() + "/collection1/conf";
            FileUtils.copyFile(new File(top, file), new File(subHome, file));
        }

    }

    //  Manages a number of Solr servers and provides a Client to partition documents and randomly assign query requests.
    //  Example:
    //        SolrInstances servers = new SolrInstances(3, "solrconfig-tlog.xml","schema_latest.xml");
    //        Client = servers.getClient(0);
    //        client.add(sdoc("id", "3"), null);
    //        client.commit();
    //        client.testJQ(params("q", "*:*"), "/response/numFound==3")
    //        servers.stop();
    //
    public static class SolrInstances {
        public List<SolrInstance> slist;
        public Client client;

        public SolrInstances(int numServers, String solrconfig, String schema) throws Exception {
            slist = new ArrayList<>(numServers);
            for (int i = 0; i < numServers; i++) {
                SolrInstance instance = new SolrInstance(createTempDir("s" + i).toFile(), solrconfig, schema);
                slist.add(instance);
                instance.start();
            }
        }

        public void stop() throws Exception {
            for (SolrInstance instance : slist) {
                instance.stop();
            }
        }

        // For params.set("shards", getShards())
        public String getShards() {
            return getShardsParam(slist);
        }

        public List<SolrClient> getSolrJs() {
            List<SolrClient> solrjs = new ArrayList<>(slist.size());
            for (SolrInstance instance : slist) {
                solrjs.add(instance.getSolrJ());
            }
            return solrjs;
        }

        public Client getClient(int seed) {
            if (client == null) {
                client = new Client(getSolrJs(), seed);
            }
            return client;
        }

        public static String getShardsParam(List<SolrInstance> instances) {
            StringBuilder sb = new StringBuilder();
            boolean first = true;
            for (SolrInstance instance : instances) {
                if (first) {
                    first = false;
                } else {
                    sb.append(',');
                }
                sb.append(instance.getShardURL());
            }
            return sb.toString();
        }

    }

}