Java tutorial
/** * Copyright (c) 2017 Dell Inc., or its subsidiaries. All Rights Reserved. * * Licensed 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 */ package io.pravega.client.stream.impl; import com.google.common.collect.ImmutableSet; import io.grpc.Status; import io.grpc.StatusRuntimeException; import io.grpc.internal.ServerImpl; import io.grpc.netty.NettyChannelBuilder; import io.grpc.netty.NettyServerBuilder; import io.grpc.stub.StreamObserver; import io.pravega.client.segment.impl.Segment; import io.pravega.client.stream.ScalingPolicy; import io.pravega.client.stream.Stream; import io.pravega.client.stream.StreamConfiguration; import io.pravega.client.stream.Transaction; import io.pravega.common.Exceptions; import io.pravega.controller.stream.api.grpc.v1.Controller; import io.pravega.controller.stream.api.grpc.v1.Controller.ScaleStatusRequest; import io.pravega.controller.stream.api.grpc.v1.Controller.ScaleStatusResponse; import io.pravega.controller.stream.api.grpc.v1.Controller.CreateScopeStatus; import io.pravega.controller.stream.api.grpc.v1.Controller.CreateStreamStatus; import io.pravega.controller.stream.api.grpc.v1.Controller.CreateTxnRequest; import io.pravega.controller.stream.api.grpc.v1.Controller.DeleteScopeStatus; import io.pravega.controller.stream.api.grpc.v1.Controller.DeleteStreamStatus; import io.pravega.controller.stream.api.grpc.v1.Controller.GetSegmentsRequest; import io.pravega.controller.stream.api.grpc.v1.Controller.NodeUri; import io.pravega.controller.stream.api.grpc.v1.Controller.PingTxnRequest; import io.pravega.controller.stream.api.grpc.v1.Controller.PingTxnStatus; import io.pravega.controller.stream.api.grpc.v1.Controller.ScaleRequest; import io.pravega.controller.stream.api.grpc.v1.Controller.ScaleResponse; import io.pravega.controller.stream.api.grpc.v1.Controller.ScopeInfo; import io.pravega.controller.stream.api.grpc.v1.Controller.SegmentId; import io.pravega.controller.stream.api.grpc.v1.Controller.SegmentRanges; import io.pravega.controller.stream.api.grpc.v1.Controller.SegmentValidityResponse; import io.pravega.controller.stream.api.grpc.v1.Controller.SegmentsAtTime; import io.pravega.controller.stream.api.grpc.v1.Controller.SegmentsAtTime.SegmentLocation; import io.pravega.controller.stream.api.grpc.v1.Controller.StreamConfig; import io.pravega.controller.stream.api.grpc.v1.Controller.StreamInfo; import io.pravega.controller.stream.api.grpc.v1.Controller.SuccessorResponse; import io.pravega.controller.stream.api.grpc.v1.Controller.TxnId; import io.pravega.controller.stream.api.grpc.v1.Controller.TxnRequest; import io.pravega.controller.stream.api.grpc.v1.Controller.TxnState; import io.pravega.controller.stream.api.grpc.v1.Controller.UpdateStreamStatus; import io.pravega.controller.stream.api.grpc.v1.ControllerServiceGrpc.ControllerServiceImplBase; import io.pravega.shared.protocol.netty.PravegaNodeUri; import io.pravega.test.common.AssertExtensions; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import io.pravega.test.common.TestUtils; import lombok.val; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.tuple.Pair; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.Timeout; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; /** * Unit tests for ControllerImpl. * */ @Slf4j public class ControllerImplTest { private static final int SERVICE_PORT = 12345; @Rule public final Timeout globalTimeout = new Timeout(120, TimeUnit.SECONDS); // Test implementation for simulating the server responses. private ControllerServiceImplBase testServerImpl; private ServerImpl testGRPCServer = null; private int serverPort; // The controller RPC client. private ControllerImpl controllerClient = null; private ScheduledExecutorService executor; @Before public void setup() throws IOException { // Setup test server generating different success and failure responses. testServerImpl = new ControllerServiceImplBase() { @Override public void createStream(StreamConfig request, StreamObserver<CreateStreamStatus> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver.onNext( CreateStreamStatus.newBuilder().setStatus(CreateStreamStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream2")) { responseObserver.onNext( CreateStreamStatus.newBuilder().setStatus(CreateStreamStatus.Status.FAILURE).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream3")) { responseObserver.onNext(CreateStreamStatus.newBuilder() .setStatus(CreateStreamStatus.Status.SCOPE_NOT_FOUND).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream4")) { responseObserver.onNext(CreateStreamStatus.newBuilder() .setStatus(CreateStreamStatus.Status.STREAM_EXISTS).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream5")) { responseObserver.onNext(CreateStreamStatus.newBuilder() .setStatus(CreateStreamStatus.Status.INVALID_STREAM_NAME).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("streamparallel")) { // Simulating delay in sending response. Exceptions.handleInterrupted(() -> Thread.sleep(500)); responseObserver.onNext( CreateStreamStatus.newBuilder().setStatus(CreateStreamStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("streamdelayed")) { // Simulating delay in sending response. This is used for the keepalive test, // where response time > 30 seconds is required to simulate a failure. Exceptions.handleInterrupted(() -> Thread.sleep(40000)); responseObserver.onNext( CreateStreamStatus.newBuilder().setStatus(CreateStreamStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void updateStream(StreamConfig request, StreamObserver<UpdateStreamStatus> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver.onNext( UpdateStreamStatus.newBuilder().setStatus(UpdateStreamStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream2")) { responseObserver.onNext( UpdateStreamStatus.newBuilder().setStatus(UpdateStreamStatus.Status.FAILURE).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream3")) { responseObserver.onNext(UpdateStreamStatus.newBuilder() .setStatus(UpdateStreamStatus.Status.SCOPE_NOT_FOUND).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream4")) { responseObserver.onNext(UpdateStreamStatus.newBuilder() .setStatus(UpdateStreamStatus.Status.STREAM_NOT_FOUND).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream5")) { responseObserver.onNext(UpdateStreamStatus.newBuilder() .setStatus(UpdateStreamStatus.Status.UNRECOGNIZED).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void sealStream(StreamInfo request, StreamObserver<UpdateStreamStatus> responseObserver) { if (request.getStream().equals("stream1")) { responseObserver.onNext( UpdateStreamStatus.newBuilder().setStatus(UpdateStreamStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getStream().equals("stream2")) { responseObserver.onNext( UpdateStreamStatus.newBuilder().setStatus(UpdateStreamStatus.Status.FAILURE).build()); responseObserver.onCompleted(); } else if (request.getStream().equals("stream3")) { responseObserver.onNext(UpdateStreamStatus.newBuilder() .setStatus(UpdateStreamStatus.Status.SCOPE_NOT_FOUND).build()); responseObserver.onCompleted(); } else if (request.getStream().equals("stream4")) { responseObserver.onNext(UpdateStreamStatus.newBuilder() .setStatus(UpdateStreamStatus.Status.STREAM_NOT_FOUND).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void deleteStream(StreamInfo request, StreamObserver<DeleteStreamStatus> responseObserver) { if (request.getStream().equals("stream1")) { responseObserver.onNext( DeleteStreamStatus.newBuilder().setStatus(DeleteStreamStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getStream().equals("stream2")) { responseObserver.onNext( DeleteStreamStatus.newBuilder().setStatus(DeleteStreamStatus.Status.FAILURE).build()); responseObserver.onCompleted(); } else if (request.getStream().equals("stream3")) { responseObserver.onNext(DeleteStreamStatus.newBuilder() .setStatus(DeleteStreamStatus.Status.STREAM_NOT_FOUND).build()); responseObserver.onCompleted(); } else if (request.getStream().equals("stream4")) { responseObserver.onNext(DeleteStreamStatus.newBuilder() .setStatus(DeleteStreamStatus.Status.STREAM_NOT_SEALED).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void getCurrentSegments(StreamInfo request, StreamObserver<SegmentRanges> responseObserver) { if (request.getStream().equals("stream1")) { responseObserver.onNext(SegmentRanges.newBuilder() .addSegmentRanges(ModelHelper.createSegmentRange("scope1", "stream1", 6, 0.0, 0.4)) .addSegmentRanges(ModelHelper.createSegmentRange("scope1", "stream1", 7, 0.4, 1.0)) .build()); responseObserver.onCompleted(); } else if (request.getStream().equals("streamparallel")) { Exceptions.handleInterrupted(() -> Thread.sleep(500)); responseObserver.onNext(SegmentRanges.newBuilder() .addSegmentRanges( ModelHelper.createSegmentRange("scope1", "streamparallel", 0, 0.0, 0.4)) .addSegmentRanges( ModelHelper.createSegmentRange("scope1", "streamparallel", 1, 0.4, 1.0)) .build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void getSegments(GetSegmentsRequest request, StreamObserver<SegmentsAtTime> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { SegmentId segment1 = ModelHelper.createSegmentId("scope1", "stream1", 0); SegmentId segment2 = ModelHelper.createSegmentId("scope1", "stream1", 1); responseObserver.onNext(SegmentsAtTime.newBuilder() .addSegments(SegmentLocation.newBuilder().setSegmentId(segment1).setOffset(10).build()) .addSegments(SegmentLocation.newBuilder().setSegmentId(segment2).setOffset(20).build()) .build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void getSegmentsImmediatlyFollowing(SegmentId request, StreamObserver<SuccessorResponse> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { Map<SegmentId, Pair<Double, Double>> result = new HashMap<>(); if (request.getSegmentNumber() == 0) { result.put(ModelHelper.createSegmentId("scope1", "stream1", 2), Pair.of(0.0, 0.25)); result.put(ModelHelper.createSegmentId("scope1", "stream1", 3), Pair.of(0.25, 0.5)); } else if (request.getSegmentNumber() == 1) { result.put(ModelHelper.createSegmentId("scope1", "stream1", 4), Pair.of(0.5, 0.75)); result.put(ModelHelper.createSegmentId("scope1", "stream1", 5), Pair.of(0.75, 1.0)); } else if (request.getSegmentNumber() == 2 || request.getSegmentNumber() == 3) { result.put(ModelHelper.createSegmentId("scope1", "stream1", 6), Pair.of(0.0, 0.5)); } else if (request.getSegmentNumber() == 4 || request.getSegmentNumber() == 5) { result.put(ModelHelper.createSegmentId("scope1", "stream1", 7), Pair.of(0.5, 0.25)); } val builder = SuccessorResponse.newBuilder(); for (Entry<SegmentId, Pair<Double, Double>> entry : result.entrySet()) { builder.addSegments(SuccessorResponse.SegmentEntry.newBuilder() .setSegment(Controller.SegmentRange.newBuilder().setSegmentId(entry.getKey()) .setMinKey(entry.getValue().getLeft()) .setMaxKey(entry.getValue().getRight()).build()) .addValue(10 * entry.getKey().getSegmentNumber()).build()); } responseObserver.onNext(builder.build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void scale(ScaleRequest request, StreamObserver<ScaleResponse> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver .onNext(ScaleResponse.newBuilder().setStatus(ScaleResponse.ScaleStreamStatus.STARTED) .addSegments(ModelHelper.createSegmentRange("scope1", "stream1", 0, 0.0, 0.5)) .addSegments(ModelHelper.createSegmentRange("scope1", "stream1", 1, 0.5, 1.0)) .setEpoch(0).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void checkScale(ScaleStatusRequest request, StreamObserver<ScaleStatusResponse> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver.onNext(ScaleStatusResponse.newBuilder() .setStatus(ScaleStatusResponse.ScaleStatus.SUCCESS).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void getURI(SegmentId request, StreamObserver<NodeUri> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver .onNext(NodeUri.newBuilder().setEndpoint("localhost").setPort(SERVICE_PORT).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void isSegmentValid(SegmentId request, StreamObserver<SegmentValidityResponse> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver.onNext(SegmentValidityResponse.newBuilder().setResponse(true).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream2")) { responseObserver.onNext(SegmentValidityResponse.newBuilder().setResponse(false).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void createTransaction(CreateTxnRequest request, StreamObserver<Controller.CreateTxnResponse> responseObserver) { Controller.CreateTxnResponse.Builder builder = Controller.CreateTxnResponse.newBuilder(); if (request.getStreamInfo().getStream().equals("stream1")) { builder.setTxnId(TxnId.newBuilder().setHighBits(11L).setLowBits(22L).build()); builder.addActiveSegments(ModelHelper.createSegmentRange("scope1", "stream1", 0, 0.0, 0.5)); builder.addActiveSegments(ModelHelper.createSegmentRange("scope1", "stream1", 1, 0.5, 1.0)); responseObserver.onNext(builder.build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream2")) { builder.addActiveSegments(ModelHelper.createSegmentRange("scope1", "stream2", 0, 0.0, 1.0)); builder.setTxnId(TxnId.newBuilder().setHighBits(33L).setLowBits(44L).build()); responseObserver.onNext(builder.build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void commitTransaction(TxnRequest request, StreamObserver<Controller.TxnStatus> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver.onNext(Controller.TxnStatus.newBuilder() .setStatus(Controller.TxnStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream2")) { responseObserver.onNext(Controller.TxnStatus.newBuilder() .setStatus(Controller.TxnStatus.Status.FAILURE).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream3")) { responseObserver.onNext(Controller.TxnStatus.newBuilder() .setStatus(Controller.TxnStatus.Status.STREAM_NOT_FOUND).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream4")) { responseObserver.onNext(Controller.TxnStatus.newBuilder() .setStatus(Controller.TxnStatus.Status.TRANSACTION_NOT_FOUND).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void abortTransaction(TxnRequest request, StreamObserver<Controller.TxnStatus> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver.onNext(Controller.TxnStatus.newBuilder() .setStatus(Controller.TxnStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream2")) { responseObserver.onNext(Controller.TxnStatus.newBuilder() .setStatus(Controller.TxnStatus.Status.FAILURE).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream3")) { responseObserver.onNext(Controller.TxnStatus.newBuilder() .setStatus(Controller.TxnStatus.Status.STREAM_NOT_FOUND).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream4")) { responseObserver.onNext(Controller.TxnStatus.newBuilder() .setStatus(Controller.TxnStatus.Status.TRANSACTION_NOT_FOUND).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void pingTransaction(PingTxnRequest request, StreamObserver<PingTxnStatus> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver.onNext(PingTxnStatus.newBuilder().setStatus(PingTxnStatus.Status.OK).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void checkTransactionState(TxnRequest request, StreamObserver<TxnState> responseObserver) { if (request.getStreamInfo().getStream().equals("stream1")) { responseObserver.onNext(TxnState.newBuilder().setState(TxnState.State.OPEN).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream2")) { responseObserver.onNext(TxnState.newBuilder().setState(TxnState.State.UNKNOWN).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream3")) { responseObserver.onNext(TxnState.newBuilder().setState(TxnState.State.COMMITTING).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream4")) { responseObserver.onNext(TxnState.newBuilder().setState(TxnState.State.COMMITTED).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream5")) { responseObserver.onNext(TxnState.newBuilder().setState(TxnState.State.ABORTING).build()); responseObserver.onCompleted(); } else if (request.getStreamInfo().getStream().equals("stream6")) { responseObserver.onNext(TxnState.newBuilder().setState(TxnState.State.ABORTED).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void createScope(ScopeInfo request, StreamObserver<CreateScopeStatus> responseObserver) { if (request.getScope().equals("scope1")) { responseObserver.onNext( CreateScopeStatus.newBuilder().setStatus(CreateScopeStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getScope().equals("scope2")) { responseObserver.onNext( CreateScopeStatus.newBuilder().setStatus(CreateScopeStatus.Status.FAILURE).build()); responseObserver.onCompleted(); } else if (request.getScope().equals("scope3")) { responseObserver.onNext(CreateScopeStatus.newBuilder() .setStatus(CreateScopeStatus.Status.INVALID_SCOPE_NAME).build()); responseObserver.onCompleted(); } else if (request.getScope().equals("scope4")) { responseObserver.onNext(CreateScopeStatus.newBuilder() .setStatus(CreateScopeStatus.Status.SCOPE_EXISTS).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } @Override public void deleteScope(ScopeInfo request, StreamObserver<DeleteScopeStatus> responseObserver) { if (request.getScope().equals("scope1")) { responseObserver.onNext( DeleteScopeStatus.newBuilder().setStatus(DeleteScopeStatus.Status.SUCCESS).build()); responseObserver.onCompleted(); } else if (request.getScope().equals("scope2")) { responseObserver.onNext( DeleteScopeStatus.newBuilder().setStatus(DeleteScopeStatus.Status.FAILURE).build()); responseObserver.onCompleted(); } else if (request.getScope().equals("scope3")) { responseObserver.onNext(DeleteScopeStatus.newBuilder() .setStatus(DeleteScopeStatus.Status.SCOPE_NOT_EMPTY).build()); responseObserver.onCompleted(); } else if (request.getScope().equals("scope4")) { responseObserver.onNext(DeleteScopeStatus.newBuilder() .setStatus(DeleteScopeStatus.Status.SCOPE_NOT_FOUND).build()); responseObserver.onCompleted(); } else { responseObserver.onError(Status.INTERNAL.withDescription("Server error").asRuntimeException()); } } }; serverPort = TestUtils.getAvailableListenPort(); testGRPCServer = NettyServerBuilder.forPort(serverPort).addService(testServerImpl).build().start(); controllerClient = new ControllerImpl(URI.create("tcp://localhost:" + serverPort)); executor = Executors.newSingleThreadScheduledExecutor(); } @After public void tearDown() { executor.shutdown(); testGRPCServer.shutdownNow(); } @Test public void testKeepAlive() throws IOException, ExecutionException, InterruptedException { // Verify that keep-alive timeout less than permissible by the server results in a failure. ControllerImpl controller = new ControllerImpl(NettyChannelBuilder.forAddress("localhost", serverPort) .keepAliveTime(10, TimeUnit.SECONDS).usePlaintext(true)); CompletableFuture<Boolean> createStreamStatus = controller.createStream(StreamConfiguration.builder() .streamName("streamdelayed").scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Should throw Exception", createStreamStatus, throwable -> throwable instanceof StatusRuntimeException); // Verify that the same RPC with permissible keepalive time succeeds. int serverPort2 = TestUtils.getAvailableListenPort(); ServerImpl testServer = NettyServerBuilder.forPort(serverPort2).addService(testServerImpl) .permitKeepAliveTime(5, TimeUnit.SECONDS).build().start(); controller = new ControllerImpl(NettyChannelBuilder.forAddress("localhost", serverPort2) .keepAliveTime(10, TimeUnit.SECONDS).usePlaintext(true)); createStreamStatus = controller.createStream(StreamConfiguration.builder().streamName("streamdelayed") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); assertTrue(createStreamStatus.get()); testServer.shutdownNow(); } @Test public void testCreateStream() throws Exception { CompletableFuture<Boolean> createStreamStatus; createStreamStatus = controllerClient.createStream(StreamConfiguration.builder().streamName("stream1") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); assertTrue(createStreamStatus.get()); createStreamStatus = controllerClient.createStream(StreamConfiguration.builder().streamName("stream2") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Server should throw exception", createStreamStatus, Throwable -> true); createStreamStatus = controllerClient.createStream(StreamConfiguration.builder().streamName("stream3") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Server should throw exception", createStreamStatus, Throwable -> true); createStreamStatus = controllerClient.createStream(StreamConfiguration.builder().streamName("stream4") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); assertFalse(createStreamStatus.get()); createStreamStatus = controllerClient.createStream(StreamConfiguration.builder().streamName("stream5") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Server should throw exception", createStreamStatus, Throwable -> true); createStreamStatus = controllerClient.createStream(StreamConfiguration.builder().streamName("stream6") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Should throw Exception", createStreamStatus, throwable -> true); } @Test public void testUpdateStream() throws Exception { CompletableFuture<Boolean> updateStreamStatus; updateStreamStatus = controllerClient.updateStream(StreamConfiguration.builder().streamName("stream1") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); assertTrue(updateStreamStatus.get()); updateStreamStatus = controllerClient.updateStream(StreamConfiguration.builder().streamName("stream2") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Server should throw exception", updateStreamStatus, Throwable -> true); updateStreamStatus = controllerClient.updateStream(StreamConfiguration.builder().streamName("stream3") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Server should throw exception", updateStreamStatus, Throwable -> true); updateStreamStatus = controllerClient.updateStream(StreamConfiguration.builder().streamName("stream4") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Server should throw exception", updateStreamStatus, Throwable -> true); updateStreamStatus = controllerClient.updateStream(StreamConfiguration.builder().streamName("stream5") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Should throw Exception", updateStreamStatus, throwable -> true); updateStreamStatus = controllerClient.updateStream(StreamConfiguration.builder().streamName("stream6") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); AssertExtensions.assertThrows("Should throw Exception", updateStreamStatus, throwable -> true); } @Test public void testSealStream() throws Exception { CompletableFuture<Boolean> updateStreamStatus; updateStreamStatus = controllerClient.sealStream("scope1", "stream1"); assertTrue(updateStreamStatus.get()); updateStreamStatus = controllerClient.sealStream("scope1", "stream2"); AssertExtensions.assertThrows("Should throw exception", updateStreamStatus, Throwable -> true); updateStreamStatus = controllerClient.sealStream("scope1", "stream3"); AssertExtensions.assertThrows("Should throw Exception", updateStreamStatus, throwable -> true); updateStreamStatus = controllerClient.sealStream("scope1", "stream4"); AssertExtensions.assertThrows("Should throw Exception", updateStreamStatus, throwable -> true); updateStreamStatus = controllerClient.sealStream("scope1", "stream5"); AssertExtensions.assertThrows("Should throw Exception", updateStreamStatus, throwable -> true); } @Test public void testDeleteStream() { CompletableFuture<Boolean> deleteStreamStatus; deleteStreamStatus = controllerClient.deleteStream("scope1", "stream1"); assertTrue(deleteStreamStatus.join()); deleteStreamStatus = controllerClient.deleteStream("scope1", "stream2"); AssertExtensions.assertThrows("Should throw Exception", deleteStreamStatus, throwable -> true); deleteStreamStatus = controllerClient.deleteStream("scope1", "stream3"); assertFalse(deleteStreamStatus.join()); deleteStreamStatus = controllerClient.deleteStream("scope1", "stream4"); AssertExtensions.assertThrows("Should throw Exception", deleteStreamStatus, throwable -> true); deleteStreamStatus = controllerClient.deleteStream("scope1", "stream5"); AssertExtensions.assertThrows("Should throw Exception", deleteStreamStatus, throwable -> true); } @Test public void testGetCurrentSegments() throws Exception { CompletableFuture<StreamSegments> streamSegments; streamSegments = controllerClient.getCurrentSegments("scope1", "stream1"); assertTrue(streamSegments.get().getSegments().size() == 2); assertEquals(new Segment("scope1", "stream1", 6), streamSegments.get().getSegmentForKey(0.2)); assertEquals(new Segment("scope1", "stream1", 7), streamSegments.get().getSegmentForKey(0.6)); streamSegments = controllerClient.getCurrentSegments("scope1", "stream2"); AssertExtensions.assertThrows("Should throw Exception", streamSegments, throwable -> true); } @Test public void testGetSegmentsAtTime() throws Exception { CompletableFuture<Map<Segment, Long>> positions; positions = controllerClient.getSegmentsAtTime(new StreamImpl("scope1", "stream1"), 0); assertEquals(2, positions.get().size()); assertEquals(10, positions.get().get(new Segment("scope1", "stream1", 0)).longValue()); assertEquals(20, positions.get().get(new Segment("scope1", "stream1", 1)).longValue()); positions = controllerClient.getSegmentsAtTime(new StreamImpl("scope1", "stream2"), 0); AssertExtensions.assertThrows("Should throw Exception", positions, throwable -> true); } @Test public void testGetSegmentsImmediatlyFollowing() throws Exception { CompletableFuture<Map<Segment, List<Integer>>> successors; successors = controllerClient.getSuccessors(new Segment("scope1", "stream1", 0)) .thenApply(StreamSegmentsWithPredecessors::getSegmentToPredecessor); assertEquals(2, successors.get().size()); assertEquals(20, successors.get().get(new Segment("scope1", "stream1", 2)).get(0).longValue()); assertEquals(30, successors.get().get(new Segment("scope1", "stream1", 3)).get(0).longValue()); successors = controllerClient.getSuccessors(new Segment("scope1", "stream2", 0)) .thenApply(StreamSegmentsWithPredecessors::getSegmentToPredecessor); AssertExtensions.assertThrows("Should throw Exception", successors, throwable -> true); } @Test public void testScale() throws Exception { CompletableFuture<Boolean> scaleStream; StreamImpl stream = new StreamImpl("scope1", "stream1"); scaleStream = controllerClient.scaleStream(stream, new ArrayList<>(), new HashMap<>(), executor) .getFuture(); assertTrue(scaleStream.get()); CompletableFuture<StreamSegments> segments = controllerClient.getCurrentSegments("scope1", "stream1"); assertEquals(2, segments.get().getSegments().size()); assertEquals(new Segment("scope1", "stream1", 6), segments.get().getSegmentForKey(0.25)); assertEquals(new Segment("scope1", "stream1", 7), segments.get().getSegmentForKey(0.75)); scaleStream = controllerClient .scaleStream(new StreamImpl("scope1", "stream2"), new ArrayList<>(), new HashMap<>(), executor) .getFuture(); AssertExtensions.assertThrows("Should throw Exception", scaleStream, throwable -> true); scaleStream = controllerClient .scaleStream(new StreamImpl("UNKNOWN", "stream2"), new ArrayList<>(), new HashMap<>(), executor) .getFuture(); AssertExtensions.assertThrows("Should throw Exception", scaleStream, throwable -> true); scaleStream = controllerClient .scaleStream(new StreamImpl("scope1", "UNKNOWN"), new ArrayList<>(), new HashMap<>(), executor) .getFuture(); AssertExtensions.assertThrows("Should throw Exception", scaleStream, throwable -> true); } @Test public void testGetURI() throws Exception { CompletableFuture<PravegaNodeUri> endpointForSegment; endpointForSegment = controllerClient.getEndpointForSegment("scope1/stream1/0"); assertEquals(new PravegaNodeUri("localhost", SERVICE_PORT), endpointForSegment.get()); endpointForSegment = controllerClient.getEndpointForSegment("scope1/stream2/0"); AssertExtensions.assertThrows("Should throw Exception", endpointForSegment, throwable -> true); } @Test public void testIsSegmentValid() throws Exception { CompletableFuture<Boolean> segmentOpen; segmentOpen = controllerClient.isSegmentOpen(new Segment("scope1", "stream1", 0)); assertTrue(segmentOpen.get()); segmentOpen = controllerClient.isSegmentOpen(new Segment("scope1", "stream2", 0)); assertFalse(segmentOpen.get()); segmentOpen = controllerClient.isSegmentOpen(new Segment("scope1", "stream3", 0)); AssertExtensions.assertThrows("Should throw Exception", segmentOpen, throwable -> true); } @Test public void testCreateTransaction() throws Exception { CompletableFuture<TxnSegments> transaction; transaction = controllerClient.createTransaction(new StreamImpl("scope1", "stream1"), 0, 0, 0); assertEquals(new UUID(11L, 22L), transaction.get().getTxnId()); assertEquals(2, transaction.get().getSteamSegments().getSegments().size()); assertEquals(new Segment("scope1", "stream1", 0), transaction.get().getSteamSegments().getSegmentForKey(.2)); assertEquals(new Segment("scope1", "stream1", 1), transaction.get().getSteamSegments().getSegmentForKey(.8)); transaction = controllerClient.createTransaction(new StreamImpl("scope1", "stream2"), 0, 0, 0); assertEquals(new UUID(33L, 44L), transaction.get().getTxnId()); assertEquals(1, transaction.get().getSteamSegments().getSegments().size()); assertEquals(new Segment("scope1", "stream2", 0), transaction.get().getSteamSegments().getSegmentForKey(.2)); assertEquals(new Segment("scope1", "stream2", 0), transaction.get().getSteamSegments().getSegmentForKey(.8)); transaction = controllerClient.createTransaction(new StreamImpl("scope1", "stream3"), 0, 0, 0); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); } @Test public void testCommitTransaction() throws Exception { CompletableFuture<Void> transaction; transaction = controllerClient.commitTransaction(new StreamImpl("scope1", "stream1"), UUID.randomUUID()); assertTrue(transaction.get() == null); transaction = controllerClient.commitTransaction(new StreamImpl("scope1", "stream2"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); transaction = controllerClient.commitTransaction(new StreamImpl("scope1", "stream3"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); transaction = controllerClient.commitTransaction(new StreamImpl("scope1", "stream4"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); transaction = controllerClient.commitTransaction(new StreamImpl("scope1", "stream5"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); } @Test public void testAbortTransaction() throws Exception { CompletableFuture<Void> transaction; transaction = controllerClient.abortTransaction(new StreamImpl("scope1", "stream1"), UUID.randomUUID()); assertTrue(transaction.get() == null); transaction = controllerClient.abortTransaction(new StreamImpl("scope1", "stream2"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); transaction = controllerClient.abortTransaction(new StreamImpl("scope1", "stream3"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); transaction = controllerClient.abortTransaction(new StreamImpl("scope1", "stream4"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); transaction = controllerClient.abortTransaction(new StreamImpl("scope1", "stream5"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); } @Test public void testPingTransaction() throws Exception { CompletableFuture<Void> transaction; transaction = controllerClient.pingTransaction(new StreamImpl("scope1", "stream1"), UUID.randomUUID(), 0); assertTrue(transaction.get() == null); transaction = controllerClient.pingTransaction(new StreamImpl("scope1", "stream2"), UUID.randomUUID(), 0); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); } @Test public void testChecktransactionState() throws Exception { CompletableFuture<Transaction.Status> transaction; transaction = controllerClient.checkTransactionStatus(new StreamImpl("scope1", "stream1"), UUID.randomUUID()); assertEquals(Transaction.Status.OPEN, transaction.get()); transaction = controllerClient.checkTransactionStatus(new StreamImpl("scope1", "stream2"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); transaction = controllerClient.checkTransactionStatus(new StreamImpl("scope1", "stream3"), UUID.randomUUID()); assertEquals(Transaction.Status.COMMITTING, transaction.get()); transaction = controllerClient.checkTransactionStatus(new StreamImpl("scope1", "stream4"), UUID.randomUUID()); assertEquals(Transaction.Status.COMMITTED, transaction.get()); transaction = controllerClient.checkTransactionStatus(new StreamImpl("scope1", "stream5"), UUID.randomUUID()); assertEquals(Transaction.Status.ABORTING, transaction.get()); transaction = controllerClient.checkTransactionStatus(new StreamImpl("scope1", "stream6"), UUID.randomUUID()); assertEquals(Transaction.Status.ABORTED, transaction.get()); transaction = controllerClient.checkTransactionStatus(new StreamImpl("scope1", "stream7"), UUID.randomUUID()); AssertExtensions.assertThrows("Should throw Exception", transaction, throwable -> true); } @Test public void testCreateScope() throws Exception { CompletableFuture<Boolean> scopeStatus; scopeStatus = controllerClient.createScope("scope1"); assertTrue(scopeStatus.get()); scopeStatus = controllerClient.createScope("scope2"); AssertExtensions.assertThrows("Server should throw exception", scopeStatus, Throwable -> true); scopeStatus = controllerClient.createScope("scope3"); AssertExtensions.assertThrows("Server should throw exception", scopeStatus, Throwable -> true); scopeStatus = controllerClient.createScope("scope4"); assertFalse(scopeStatus.get()); scopeStatus = controllerClient.createScope("scope5"); AssertExtensions.assertThrows("Should throw Exception", scopeStatus, throwable -> true); } @Test public void testDeleteScope() { CompletableFuture<Boolean> deleteStatus; String scope1 = "scope1"; String scope2 = "scope2"; String scope3 = "scope3"; String scope4 = "scope4"; String scope5 = "scope5"; deleteStatus = controllerClient.deleteScope(scope1); assertTrue(deleteStatus.join()); deleteStatus = controllerClient.deleteScope(scope2); AssertExtensions.assertThrows("Server should throw exception", deleteStatus, Throwable -> true); deleteStatus = controllerClient.deleteScope(scope3); AssertExtensions.assertThrows("Server should throw exception", deleteStatus, Throwable -> true); deleteStatus = controllerClient.deleteScope(scope4); assertFalse(deleteStatus.join()); deleteStatus = controllerClient.deleteScope(scope5); AssertExtensions.assertThrows("Server should throw exception", deleteStatus, Throwable -> true); } @Test public void testParallelCreateStream() throws Exception { final ExecutorService executorService = Executors.newFixedThreadPool(10); Semaphore createCount = new Semaphore(-19); AtomicBoolean success = new AtomicBoolean(true); for (int i = 0; i < 10; i++) { executorService.submit(() -> { for (int j = 0; j < 2; j++) { try { CompletableFuture<Boolean> createStreamStatus; createStreamStatus = controllerClient .createStream(StreamConfiguration.builder().streamName("streamparallel") .scope("scope1").scalingPolicy(ScalingPolicy.fixed(1)).build()); log.info("{}", createStreamStatus.get()); assertTrue(createStreamStatus.get()); createCount.release(); } catch (Exception e) { log.error("Exception when creating stream: {}", e); // Don't wait for other threads to complete. success.set(false); createCount.release(20); } } }); } createCount.acquire(); executorService.shutdownNow(); assertTrue(success.get()); } @Test public void testParallelGetCurrentSegments() throws Exception { final ExecutorService executorService = Executors.newFixedThreadPool(10); Semaphore createCount = new Semaphore(-19); AtomicBoolean success = new AtomicBoolean(true); for (int i = 0; i < 10; i++) { executorService.submit(() -> { for (int j = 0; j < 2; j++) { try { CompletableFuture<StreamSegments> streamSegments; streamSegments = controllerClient.getCurrentSegments("scope1", "streamparallel"); assertTrue(streamSegments.get().getSegments().size() == 2); assertEquals(new Segment("scope1", "streamparallel", 0), streamSegments.get().getSegmentForKey(0.2)); assertEquals(new Segment("scope1", "streamparallel", 1), streamSegments.get().getSegmentForKey(0.6)); createCount.release(); } catch (Exception e) { log.error("Exception when getting segments: {}", e); // Don't wait for other threads to complete. success.set(false); createCount.release(20); } } }); } createCount.acquire(); executorService.shutdownNow(); assertTrue(success.get()); } @Test public void testCutpointSuccessors() throws Exception { PravegaNodeUri pravegaNodeUri = new PravegaNodeUri("localhost", SERVICE_PORT); String scope = "scope1"; String stream = "stream1"; Stream s = new StreamImpl(scope, stream); Map<Segment, Long> segments = new HashMap<>(); segments.put(new Segment(scope, stream, 0), 4L); segments.put(new Segment(scope, stream, 1), 6L); StreamCut cut = new StreamCut(s, segments); Set<Segment> successors = controllerClient.getSuccessors(cut).get(); assertEquals(ImmutableSet.of(new Segment(scope, stream, 0), new Segment(scope, stream, 1), new Segment(scope, stream, 2), new Segment(scope, stream, 3), new Segment(scope, stream, 4), new Segment(scope, stream, 5), new Segment(scope, stream, 6), new Segment(scope, stream, 7)), successors); } }