<commit_before>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.rendering;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.yahoo.component.ComponentId;
import com.yahoo.component.chain.Chain;
import com.yahoo.concurrent.ThreadFactoryFactory;
import com.yahoo.container.QrSearchersConfig;
import com.yahoo.data.access.simple.Value;
import com.yahoo.data.access.slime.SlimeAdapter;
import com.yahoo.document.DataType;
import com.yahoo.document.DocumentId;
import com.yahoo.document.Field;
import com.yahoo.document.StructDataType;
import com.yahoo.document.datatypes.StringFieldValue;
import com.yahoo.document.datatypes.Struct;
import com.yahoo.document.datatypes.TensorFieldValue;
import com.yahoo.document.predicate.Predicate;
import com.yahoo.prelude.Index;
import com.yahoo.prelude.IndexFacts;
import com.yahoo.prelude.IndexModel;
import com.yahoo.prelude.SearchDefinition;
import com.yahoo.prelude.fastsearch.FastHit;
import com.yahoo.prelude.hitfield.JSONString;
import com.yahoo.prelude.hitfield.RawData;
import com.yahoo.prelude.searcher.JuniperSearcher;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.grouping.Continuation;
import com.yahoo.search.grouping.result.DoubleBucketId;
import com.yahoo.search.grouping.result.Group;
import com.yahoo.search.grouping.result.GroupList;
import com.yahoo.search.grouping.result.RootGroup;
import com.yahoo.search.grouping.result.StringId;
import com.yahoo.search.result.Coverage;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.result.FeatureData;
import com.yahoo.search.result.Hit;
import com.yahoo.search.result.HitGroup;
import com.yahoo.search.result.NanNumber;
import com.yahoo.search.result.Relevance;
import com.yahoo.search.result.StructuredData;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.search.searchchain.testutil.DocumentSourceSearcher;
import com.yahoo.search.statistics.ElapsedTimeTestCase;
import com.yahoo.search.statistics.ElapsedTimeTestCase.CreativeTimeSource;
import com.yahoo.search.statistics.ElapsedTimeTestCase.UselessSearcher;
import com.yahoo.search.statistics.TimeTracker;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Slime;
import com.yahoo.tensor.Tensor;
import com.yahoo.tensor.TensorType;
import com.yahoo.tensor.serialization.TypedBinaryFormat;
import com.yahoo.text.Utf8;
import com.yahoo.yolean.Exceptions;
import com.yahoo.yolean.trace.TraceNode;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

/**
 * Functional testing of {@link JsonRenderer}.
 *
 * @author <NAME>
 * @author bratseth
 */
public class JsonRendererTestCase {

    private static final ObjectMapper jsonMapper = new ObjectMapper();

    @Rule
    public Timeout globalTimeout = Timeout.seconds(300);

    private static ThreadPoolExecutor executor;
    private JsonRenderer renderer;

    @BeforeClass
    public static void createSharedExecutor() {
        ThreadFactory threadFactory = ThreadFactoryFactory.getThreadFactory("test-rendering");
        executor = new ThreadPoolExecutor(4, 4, 1L, TimeUnit.MINUTES, new LinkedBlockingQueue<>(), threadFactory);
        executor.prestartAllCoreThreads();
    }

    @Before
    public void createRenderer() {
        renderer = new JsonRenderer(executor);
        renderer.init();
    }

    @After
    public void destroyRenderer() {
        renderer.deconstruct();
        renderer = null;
    }

    @AfterClass
    public static void destroyExecutor() throws InterruptedException {
        executor.shutdown();
        if (!executor.awaitTermination(1, TimeUnit.MINUTES)) {
            throw new RuntimeException("Failed to shutdown executor");
        }
        executor = null;
    }

    @Test
    public void testDocumentId() throws IOException, InterruptedException, ExecutionException {
        String expected = "{"
                + "    \"root\": {"
                + "        \"children\": ["
                + "            {"
                + "                \"fields\": {"
                + "                    \"documentid\": \"id:unittest:smoke::whee\""
                + "                },"
                + "                \"id\": \"id:unittest:smoke::whee\","
                + "                \"relevance\": 1.0"
                + "            }"
                + "        ],"
                + "        \"fields\": {"
                + "            \"totalCount\": 1"
                + "        },"
                + "        \"id\": \"toplevel\","
                + "        \"relevance\": 1.0"
                + "    }"
                + "}";
        Result r = newEmptyResult();
        Hit h = new Hit("docIdTest");
        h.setField("documentid", new DocumentId("id:unittest:smoke::whee"));
        r.hits().add(h);
        r.setTotalHitCount(1L);
        String summary = render(r);
        assertEqualJson(expected, summary);
    }<commit_msg>Revert "Stabilize JsonRendererTestCase"<commit_after>// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.rendering;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.yahoo.component.ComponentId;
import com.yahoo.component.chain.Chain;
import com.yahoo.container.QrSearchersConfig;
import com.yahoo.data.access.simple.Value;
import com.yahoo.data.access.slime.SlimeAdapter;
import com.yahoo.document.DataType;
import com.yahoo.document.DocumentId;
import com.yahoo.document.Field;
import com.yahoo.document.StructDataType;
import com.yahoo.document.datatypes.StringFieldValue;
import com.yahoo.document.datatypes.Struct;
import com.yahoo.document.datatypes.TensorFieldValue;
import com.yahoo.document.predicate.Predicate;
import com.yahoo.prelude.Index;
import com.yahoo.prelude.IndexFacts;
import com.yahoo.prelude.IndexModel;
import com.yahoo.prelude.SearchDefinition;
import com.yahoo.prelude.fastsearch.FastHit;
import com.yahoo.prelude.hitfield.JSONString;
import com.yahoo.prelude.hitfield.RawData;
import com.yahoo.prelude.searcher.JuniperSearcher;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
import com.yahoo.search.grouping.Continuation;
import com.yahoo.search.grouping.result.DoubleBucketId;
import com.yahoo.search.grouping.result.Group;
import com.yahoo.search.grouping.result.GroupList;
import com.yahoo.search.grouping.result.RootGroup;
import com.yahoo.search.grouping.result.StringId;
import com.yahoo.search.result.Coverage;
import com.yahoo.search.result.ErrorMessage;
import com.yahoo.search.result.FeatureData;
import com.yahoo.search.result.Hit;
import com.yahoo.search.result.HitGroup;
import com.yahoo.search.result.NanNumber;
import com.yahoo.search.result.Relevance;
import com.yahoo.search.result.StructuredData;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.search.searchchain.testutil.DocumentSourceSearcher;
import com.yahoo.search.statistics.ElapsedTimeTestCase;
import com.yahoo.search.statistics.ElapsedTimeTestCase.CreativeTimeSource;
import com.yahoo.search.statistics.ElapsedTimeTestCase.UselessSearcher;
import com.yahoo.search.statistics.TimeTracker;
import com.yahoo.slime.Cursor;
import com.yahoo.slime.Slime;
import com.yahoo.tensor.Tensor;
import com.yahoo.tensor.TensorType;
import com.yahoo.tensor.serialization.TypedBinaryFormat;
import com.yahoo.text.Utf8;
import com.yahoo.yolean.Exceptions;
import com.yahoo.yolean.trace.TraceNode;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.Timeout;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

/**
 * Functional testing of {@link JsonRenderer}.
 *
 * @author <NAME>
 * @author bratseth
 */
public class JsonRendererTestCase {

    private static final ObjectMapper jsonMapper = new ObjectMapper();

    @Rule
    public Timeout globalTimeout = Timeout.seconds(300);

    private final JsonRenderer originalRenderer;
    private JsonRenderer renderer;

    public JsonRendererTestCase() {
        originalRenderer = new JsonRenderer();
    }

    @Before
    public void setUp() throws Exception {
        // Use the shared renderer as a prototype object, as specified in the API contract
        renderer = (JsonRenderer) originalRenderer.clone();
        renderer.init();
    }

    @Test
    public void testDocumentId() throws IOException, InterruptedException, ExecutionException {
        String expected = "{"
                + "    \"root\": {"
                + "        \"children\": ["
                + "            {"
                + "                \"fields\": {"
                + "                    \"documentid\": \"id:unittest:smoke::whee\""
                + "                },"
                + "                \"id\": \"id:unittest:smoke::whee\","
                + "                \"relevance\": 1.0"
                + "            }"
                + "        ],"
                + "        \"fields\": {"
                + "            \"totalCount\": 1"
                + "        },"
                + "        \"id\": \"toplevel\","
                + "        \"relevance\": 1.0"
                + "    }"
                + "}";
        Result r = newEmptyResult();
        Hit h = new Hit("docIdTest");
        h.setField("documentid", new DocumentId("id:unittest:smoke::whee"));
        r.hits().add(h);
        r.setTotalHitCount(1L);
        String summary = render(r);
        assertEqualJson(expected, summary);
    }
{'fraction_non_alphanumeric': 0.11556254626202812, 'fraction_numerical': 0.0025906735751295338, 'mean_word_length': 3.1255725190839696, 'pattern_counts': {'":': 20, '<': 6, '<?xml version=': 0, '>': 6, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3526961', 'n_tokens_mistral': 3281, 'n_tokens_neox': 3081, 'n_words': 573}