MinimalContextNowTest.java

/*******************************************************************************
 * Copyright (c) 2021 Eclipse RDF4J contributors.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 *******************************************************************************/
package org.eclipse.rdf4j.query.algebra.evaluation.impl;

import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.eclipse.rdf4j.model.Literal;
import org.eclipse.rdf4j.model.Value;
import org.eclipse.rdf4j.model.base.CoreDatatype;
import org.eclipse.rdf4j.query.algebra.evaluation.QueryValueEvaluationStep;
import org.eclipse.rdf4j.query.impl.EmptyBindingSet;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class MinimalContextNowTest {

	@Test
	public void testNow() {
		// Tests that the now value is correctly initialized.
		QueryEvaluationContext.Minimal context = new QueryEvaluationContext.Minimal(null);
		QueryValueEvaluationStep prepared = new QueryValueEvaluationStep.ConstantQueryValueEvaluationStep(
				context.getNow());

		Assertions.assertNotNull(prepared);

		Value nowValue = prepared.evaluate(EmptyBindingSet.getInstance());

		Assertions.assertTrue(nowValue.isLiteral());
		Assertions.assertEquals(CoreDatatype.XSD.DATETIME, ((Literal) nowValue).getCoreDatatype());
	}

	@Test
	public void testConcurrentAccessToNow() throws ExecutionException, InterruptedException {
		int numberOfIterations = 100;
		int numberOfThreads = 10;

		ExecutorService executorService = Executors.newCachedThreadPool();
		try {

			for (int i = 0; i < numberOfIterations; i++) {
				QueryEvaluationContext.Minimal context = new QueryEvaluationContext.Minimal(null);

				CountDownLatch countDownLatch = new CountDownLatch(numberOfThreads);

				List<? extends Future<Literal>> futures = IntStream.range(0, numberOfThreads)
						.mapToObj(j -> executorService.submit(() -> {
							try {
								countDownLatch.countDown();
								countDownLatch.await();
								return context.getNow();
							} catch (InterruptedException e) {
								throw new RuntimeException(e);
							}
						}))
						.collect(Collectors.toList());

				Literal prev = null;
				for (Future<Literal> future : futures) {
					Literal now = future.get();
					Assertions.assertNotNull(now);
					if (prev != null) {
						Assertions.assertSame(prev, now);
					}
					prev = now;
				}

			}

		} finally {
			List<Runnable> runnables = executorService.shutdownNow();
			Assertions.assertTrue(runnables.isEmpty());
		}

	}
}