diff --git a/.gitignore b/.gitignore index 4960fdce3..e76fa34be 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,8 @@ cm-file target logs hs_err_pid*.log +out/ +src/main/resources/META-INF/* dependency/ build/ memory-data.csv diff --git a/README.md b/README.md index c119e9108..788272f27 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,9 @@ This script will create a stream with the given name if the stream doesn't exist Demo app will start running and putting sample video frames in a loop into Kinesis Video Streams. You can change your stream settings in [`DemoAppMain.java`](./src/main/demo/com/amazonaws/kinesisvideo/demoapp/DemoAppMain.java) before you run the app. +> [!NOTE] +> Make sure the stream name that you specify exists in the region the app runs in. This demo app is set to run in us-west-2 by default. + To run [`DemoAppMain.java`](./src/main/demo/com/amazonaws/kinesisvideo/demoapp/DemoAppMain.java) in `./src/main/demo` with JVM arguments: 1. Credentials: `aws.accessKeyId`, `aws.secretKey`, `aws.sessionToken` (optional) @@ -111,7 +114,7 @@ java -classpath target/*jar-with-dependencies.jar \ > * `KinesisVideoProducerJNI.dll` for Windows > [!TIP] -> Pre-built JNI libraries for some systems can be found in `src/resources/lib`. +> Pre-built JNI libraries for some systems can be found in `src/main/resources/lib`. > [!NOTE] > If your system isn't part of the pre-built JNI libraries, you will need to build the JNI yourself. You can find instructions [here](https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-java/wiki/Building-and-Using-JNI). diff --git a/src/main/demo/com/amazonaws/kinesisvideo/demoapp/DemoAppCachedInfo.java b/src/main/demo/com/amazonaws/kinesisvideo/demoapp/DemoAppCachedInfo.java index 819298b89..3e1805048 100644 --- a/src/main/demo/com/amazonaws/kinesisvideo/demoapp/DemoAppCachedInfo.java +++ b/src/main/demo/com/amazonaws/kinesisvideo/demoapp/DemoAppCachedInfo.java @@ -85,7 +85,7 @@ public static void main(final String[] args) { // Create CachedInfoServiceCallback final CachedInfoMultiAuthServiceCallbacksImpl serviceCallbacks = new CachedInfoMultiAuthServiceCallbacksImpl(log, executor, - configuration, new JavaKinesisVideoServiceClient(log)); + configuration, new JavaKinesisVideoServiceClient()); // create Kinesis Video high level client final KinesisVideoClient kinesisVideoClient = KinesisVideoJavaClientFactory .createKinesisVideoClient(log, configuration, executor, null, serviceCallbacks); diff --git a/src/main/java/com/amazonaws/kinesisvideo/auth/DefaultAuthCallbacks.java b/src/main/java/com/amazonaws/kinesisvideo/auth/DefaultAuthCallbacks.java index e0ef90a3e..d5c97aac3 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/auth/DefaultAuthCallbacks.java +++ b/src/main/java/com/amazonaws/kinesisvideo/auth/DefaultAuthCallbacks.java @@ -1,6 +1,7 @@ package com.amazonaws.kinesisvideo.auth; import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.amazonaws.kinesisvideo.common.preconditions.Preconditions; import com.amazonaws.kinesisvideo.producer.AuthCallbacks; @@ -53,12 +54,22 @@ public class DefaultAuthCallbacks implements AuthCallbacks { */ private long expiration; + /** + * Timeout for the credentials + */ + private int updateTimeoutMillis; + public DefaultAuthCallbacks(@Nonnull KinesisVideoCredentialsProvider credentialsProvider, - @Nonnull final ScheduledExecutorService executor, - @Nonnull Logger log) { + @Nonnull final ScheduledExecutorService executor) { + this(credentialsProvider, executor, CREDENTIALS_UPDATE_TIMEOUT_MILLIS); + } + + public DefaultAuthCallbacks(@Nonnull KinesisVideoCredentialsProvider credentialsProvider, + @Nonnull final ScheduledExecutorService executor, final int updateTimeoutMillis) { this.credentialsProvider = Preconditions.checkNotNull(credentialsProvider); this.executor = Preconditions.checkNotNull(executor); - this.log = Preconditions.checkNotNull(log); + this.log = LogManager.getLogger(DefaultAuthCallbacks.class); + this.updateTimeoutMillis = updateTimeoutMillis; } @Nullable @@ -78,6 +89,10 @@ public void run() { final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { final KinesisVideoCredentials credentials = credentialsProvider.getUpdatedCredentials(); + if (credentials == null) { + log.error("Credentials must not be null"); + throw new IllegalArgumentException("Credentials must not be null"); + } expiration = credentials.getExpiration().getTime() * Time.HUNDREDS_OF_NANOS_IN_A_MILLISECOND; final ObjectOutput outputStream = new ObjectOutputStream(byteArrayOutputStream); @@ -85,12 +100,7 @@ public void run() { outputStream.flush(); serializedCredentials = byteArrayOutputStream.toByteArray(); outputStream.close(); - } catch (final IOException e) { - // return null - serializedCredentials = null; - expiration = 0; - log.error("Exception was thrown trying to get updated credentials", e); - } catch (final KinesisVideoException e) { + } catch (final IOException | KinesisVideoException | IllegalArgumentException e) { // return null serializedCredentials = null; expiration = 0; @@ -111,12 +121,8 @@ public void run() { // Await for the future to complete try { - future.get(CREDENTIALS_UPDATE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS); - } catch (final InterruptedException e) { - log.error("Awaiting for the credentials update threw an exception", e); - } catch (final ExecutionException e) { - log.error("Awaiting for the credentials update threw an exception", e); - } catch (final TimeoutException e) { + future.get(this.updateTimeoutMillis, TimeUnit.MILLISECONDS); + } catch (final InterruptedException | TimeoutException | ExecutionException e) { log.error("Awaiting for the credentials update threw an exception", e); } diff --git a/src/main/java/com/amazonaws/kinesisvideo/auth/EmptyCredentialsProvider.java b/src/main/java/com/amazonaws/kinesisvideo/auth/EmptyCredentialsProvider.java index ebb7d3426..c7e285787 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/auth/EmptyCredentialsProvider.java +++ b/src/main/java/com/amazonaws/kinesisvideo/auth/EmptyCredentialsProvider.java @@ -5,15 +5,15 @@ /** * Empty credentials provider */ -public final class EmptyCredentialsProvider implements KinesisVideoCredentialsProvider{ +public final class EmptyCredentialsProvider implements KinesisVideoCredentialsProvider { @Override - public KinesisVideoCredentials getCredentials() throws KinesisVideoException{ + public KinesisVideoCredentials getCredentials() throws KinesisVideoException { return KinesisVideoCredentials.EMPTY_KINESIS_VIDEO_CREDENTIALS; } @Override - public KinesisVideoCredentials getUpdatedCredentials() throws KinesisVideoException{ + public KinesisVideoCredentials getUpdatedCredentials() throws KinesisVideoException { return KinesisVideoCredentials.EMPTY_KINESIS_VIDEO_CREDENTIALS; } } \ No newline at end of file diff --git a/src/main/java/com/amazonaws/kinesisvideo/auth/KinesisVideoCredentials.java b/src/main/java/com/amazonaws/kinesisvideo/auth/KinesisVideoCredentials.java index 63d5ed3d4..379fba87b 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/auth/KinesisVideoCredentials.java +++ b/src/main/java/com/amazonaws/kinesisvideo/auth/KinesisVideoCredentials.java @@ -11,7 +11,7 @@ import java.util.Date; @SuppressFBWarnings("EI_EXPOSE_REP") -public class KinesisVideoCredentials implements Serializable{ +public class KinesisVideoCredentials implements Serializable { /** * Sentinel value indicating the credentials never expire */ diff --git a/src/main/java/com/amazonaws/kinesisvideo/internal/client/NativeKinesisVideoClient.java b/src/main/java/com/amazonaws/kinesisvideo/internal/client/NativeKinesisVideoClient.java index c074093a3..6190a433e 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/internal/client/NativeKinesisVideoClient.java +++ b/src/main/java/com/amazonaws/kinesisvideo/internal/client/NativeKinesisVideoClient.java @@ -98,8 +98,7 @@ public NativeKinesisVideoClient( @Nonnull final ScheduledExecutorService executor) { this(log, new DefaultAuthCallbacks(configuration.getCredentialsProvider(), - executor, - log), + executor), configuration.getStorageCallbacks(), new DefaultServiceCallbacksImpl(log, executor, configuration, serviceClient), new DefaultStreamCallbacks()); diff --git a/src/main/java/com/amazonaws/kinesisvideo/internal/service/DefaultServiceCallbacksImpl.java b/src/main/java/com/amazonaws/kinesisvideo/internal/service/DefaultServiceCallbacksImpl.java index 29963cd90..7d8f44ddb 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/internal/service/DefaultServiceCallbacksImpl.java +++ b/src/main/java/com/amazonaws/kinesisvideo/internal/service/DefaultServiceCallbacksImpl.java @@ -6,6 +6,7 @@ import com.amazonaws.kinesisvideo.client.KinesisVideoClientConfiguration; import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException; import com.amazonaws.kinesisvideo.common.function.Consumer; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.amazonaws.kinesisvideo.common.preconditions.Preconditions; import com.amazonaws.kinesisvideo.internal.producer.KinesisVideoProducer; @@ -44,12 +45,14 @@ public class DefaultServiceCallbacksImpl implements ServiceCallbacks { private class CompletionCallback implements Consumer { private final KinesisVideoProducerStream stream; private final long uploadHandle; + private final Logger log; public CompletionCallback(@Nonnull final KinesisVideoProducerStream stream, final long uploadHandle) { this.stream = Preconditions.checkNotNull(stream); this.uploadHandle = uploadHandle; + this.log = LogManager.getLogger(DefaultServiceCallbacksImpl.class); } @Override @@ -340,6 +343,10 @@ public void run() { final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { final KinesisVideoCredentials credentials = credentialsProvider.getUpdatedCredentials(); + if (credentials == null) { + log.error("Credentials must not be null"); + throw new IllegalArgumentException(); + } // Serialize the credentials expiration = credentials.getExpiration().getTime() * Time.HUNDREDS_OF_NANOS_IN_A_MILLISECOND; @@ -350,9 +357,7 @@ public void run() { outputStream.flush(); serializedCredentials = byteArrayOutputStream.toByteArray(); outputStream.close(); - } catch (final IOException e) { - log.error(e); - } catch (final KinesisVideoException e) { + } catch (final IOException | KinesisVideoException | IllegalArgumentException e) { log.error(e); } finally { try { diff --git a/src/main/java/com/amazonaws/kinesisvideo/java/client/JavaKinesisVideoClient.java b/src/main/java/com/amazonaws/kinesisvideo/java/client/JavaKinesisVideoClient.java index 01c129cbb..4a67471f7 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/java/client/JavaKinesisVideoClient.java +++ b/src/main/java/com/amazonaws/kinesisvideo/java/client/JavaKinesisVideoClient.java @@ -61,8 +61,7 @@ public JavaKinesisVideoClient( @Nonnull final StreamCallbacks streamCallbacks) { super(log, new DefaultAuthCallbacks(configuration.getCredentialsProvider(), - executor, - log), + executor), configuration.getStorageCallbacks(), serviceCallbacks, streamCallbacks, diff --git a/src/main/java/com/amazonaws/kinesisvideo/java/client/KinesisVideoJavaClientFactory.java b/src/main/java/com/amazonaws/kinesisvideo/java/client/KinesisVideoJavaClientFactory.java index 7f88e5024..901ef10be 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/java/client/KinesisVideoJavaClientFactory.java +++ b/src/main/java/com/amazonaws/kinesisvideo/java/client/KinesisVideoJavaClientFactory.java @@ -165,7 +165,7 @@ public static KinesisVideoClient createKinesisVideoClient( final Logger log = LogManager.getLogger(KinesisVideoJavaClientFactory.class); - final JavaKinesisVideoServiceClient serviceClient = new JavaKinesisVideoServiceClient(log); + final JavaKinesisVideoServiceClient serviceClient = new JavaKinesisVideoServiceClient(); final KinesisVideoClient kinesisVideoClient = new JavaKinesisVideoClient(log, configuration, @@ -193,7 +193,7 @@ public static KinesisVideoClient createKinesisVideoClient( final Logger log = LogManager.getLogger(KinesisVideoJavaClientFactory.class); - final JavaKinesisVideoServiceClient serviceClient = new JavaKinesisVideoServiceClient(log); + final JavaKinesisVideoServiceClient serviceClient = new JavaKinesisVideoServiceClient(); final KinesisVideoClient kinesisVideoClient = new JavaKinesisVideoClient(log, configuration, @@ -220,7 +220,7 @@ public static KinesisVideoClient createKinesisVideoClient( final KinesisVideoClient kinesisVideoClient = new JavaKinesisVideoClient(log, configuration, serviceCallbacks == null ? new DefaultServiceCallbacksImpl(log, executor, configuration, - new JavaKinesisVideoServiceClient(log)) : serviceCallbacks, + new JavaKinesisVideoServiceClient()) : serviceCallbacks, executor, streamCallbacks == null ? new DefaultStreamCallbacks() : streamCallbacks); diff --git a/src/main/java/com/amazonaws/kinesisvideo/java/service/CachedInfoMultiAuthServiceCallbacksImpl.java b/src/main/java/com/amazonaws/kinesisvideo/java/service/CachedInfoMultiAuthServiceCallbacksImpl.java index 0285a9d91..4f344fda7 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/java/service/CachedInfoMultiAuthServiceCallbacksImpl.java +++ b/src/main/java/com/amazonaws/kinesisvideo/java/service/CachedInfoMultiAuthServiceCallbacksImpl.java @@ -1,10 +1,12 @@ package com.amazonaws.kinesisvideo.java.service; import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.kinesisvideo.auth.DefaultAuthCallbacks; import com.amazonaws.kinesisvideo.auth.KinesisVideoCredentials; import com.amazonaws.kinesisvideo.auth.KinesisVideoCredentialsProvider; import com.amazonaws.kinesisvideo.client.KinesisVideoClientConfiguration; import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.amazonaws.kinesisvideo.common.preconditions.Preconditions; import com.amazonaws.kinesisvideo.internal.producer.KinesisVideoProducer; @@ -62,6 +64,7 @@ public CachedInfoMultiAuthServiceCallbacksImpl(@Nonnull Logger log, @Nonnull Sch * StreamArn -> Tags for the stream */ private Map tagInfoMap = new HashMap<>(); + private final Logger log = LogManager.getLogger(CachedInfoMultiAuthServiceCallbacksImpl.class); /** @@ -163,6 +166,11 @@ public void getStreamingToken( try { final KinesisVideoCredentials credentials = kvsCredentialsProvider.getUpdatedCredentials(); + if (credentials == null) { + log.error("Credentials must not be null"); + throw new IllegalArgumentException(); + } + // Serialize the credentials expiration = credentials.getExpiration().getTime() * Time.HUNDREDS_OF_NANOS_IN_A_MILLISECOND; @@ -172,9 +180,7 @@ public void getStreamingToken( outputStream.flush(); serializedCredentials = byteArrayOutputStream.toByteArray(); outputStream.close(); - } catch (final IOException e) { - log.error(e); - } catch (final KinesisVideoException e) { + } catch (final IOException | KinesisVideoException | IllegalArgumentException e) { log.error(e); } finally { try { diff --git a/src/main/java/com/amazonaws/kinesisvideo/java/service/JavaKinesisVideoServiceClient.java b/src/main/java/com/amazonaws/kinesisvideo/java/service/JavaKinesisVideoServiceClient.java index 7319c18e7..44d4e4711 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/java/service/JavaKinesisVideoServiceClient.java +++ b/src/main/java/com/amazonaws/kinesisvideo/java/service/JavaKinesisVideoServiceClient.java @@ -35,6 +35,7 @@ import com.amazonaws.services.kinesisvideo.model.GetDataEndpointResult; import com.amazonaws.services.kinesisvideo.model.TagStreamRequest; import com.amazonaws.services.kinesisvideo.model.TagStreamResult; +import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import javax.annotation.Nonnull; @@ -52,7 +53,7 @@ public final class JavaKinesisVideoServiceClient implements KinesisVideoServiceC private static final int RECEIVE_TIMEOUT_1HR = 60 * 60 * 1000; private static final String ABSOLUTE_TIMECODE = "ABSOLUTE"; private static final String RELATIVE_TIMECODE = "RELATIVE"; - + private static final Logger logger = LogManager.getLogger(JavaKinesisVideoServiceClient.class); private final Logger log; private KinesisVideoClientConfiguration configuration; @@ -108,7 +109,7 @@ public AWSCredentials getCredentials() { return amazonKinesisVideoClient; } - private static AWSCredentials createAwsCredentials( + static AWSCredentials createAwsCredentials( @Nullable final KinesisVideoCredentialsProvider credentialsProvider) throws KinesisVideoException { if (null == credentialsProvider) { @@ -117,7 +118,12 @@ private static AWSCredentials createAwsCredentials( final KinesisVideoCredentials kinesisVideoCredentials = credentialsProvider.getCredentials(); - AWSCredentials credentials = null; + if (kinesisVideoCredentials == null) { + logger.error("kinesisVideoCredentials is null"); + return null; + } + + AWSCredentials credentials; if (kinesisVideoCredentials.getSessionToken() == null) { credentials = new AWSCredentials() { @@ -153,7 +159,7 @@ public String getAWSSecretKey() { return credentials; } - private static AWSCredentialsProvider createAwsCredentialsProvider( + static AWSCredentialsProvider createAwsCredentialsProvider( @Nullable final KinesisVideoCredentialsProvider credentialsProvider, @Nonnull final Logger log) throws KinesisVideoException { @@ -165,40 +171,9 @@ private static AWSCredentialsProvider createAwsCredentialsProvider( return new AWSCredentialsProvider() { @Override public AWSCredentials getCredentials() { - AWSCredentials awsCredentials = null; + AWSCredentials awsCredentials; try { - final KinesisVideoCredentials kinesisVideoCredentials = credentialsProvider.getCredentials(); - - if (kinesisVideoCredentials.getSessionToken() == null) { - awsCredentials = new AWSCredentials() { - @Override - public String getAWSAccessKeyId() { - return kinesisVideoCredentials.getAccessKey(); - } - - @Override - public String getAWSSecretKey() { - return kinesisVideoCredentials.getSecretKey(); - } - }; - } else { - awsCredentials = new AWSSessionCredentials() { - @Override - public String getSessionToken() { - return kinesisVideoCredentials.getSessionToken(); - } - - @Override - public String getAWSAccessKeyId() { - return kinesisVideoCredentials.getAccessKey(); - } - - @Override - public String getAWSSecretKey() { - return kinesisVideoCredentials.getSecretKey(); - } - }; - } + awsCredentials = createAwsCredentials(credentialsProvider); } catch (final KinesisVideoException e) { log.error("Getting credentials threw an exception.", e); awsCredentials = null; @@ -230,6 +205,10 @@ private static ClientConfiguration createClientConfiguration(final int timeoutIn .withDnsResolver(new KvsFilteredDnsResolver(ipVersionFilter)); } + public JavaKinesisVideoServiceClient() { + this(LogManager.getLogger(JavaKinesisVideoServiceClient.class)); + } + public JavaKinesisVideoServiceClient(@Nonnull final Logger log) { this.log = Preconditions.checkNotNull(log); } @@ -339,21 +318,27 @@ public void deleteStream(@Nonnull final String streamName, final StreamDescription streamDescription = describeStream(streamName, timeoutInMillis, credentialsProvider); - final DeleteStreamRequest deleteStreamRequest = new DeleteStreamRequest() - .withStreamARN(streamDescription.getStreamArn()) - .withCurrentVersion(streamDescription.getUpdateVersion()); - - log.debug("calling delete stream: {}", deleteStreamRequest.toString()); - final DeleteStreamResult deleteStreamResult; + try { + if (streamDescription == null) { + log.error("Stream description must not be null"); + throw new IllegalArgumentException(); + } + + final DeleteStreamRequest deleteStreamRequest = new DeleteStreamRequest() + .withStreamARN(streamDescription.getStreamArn()) + .withCurrentVersion(streamDescription.getUpdateVersion()); + + log.debug("calling delete stream: {}", deleteStreamRequest.toString()); deleteStreamResult = serviceClient.deleteStream(deleteStreamRequest); + log.debug("delete stream result: {}", deleteStreamResult.toString()); } catch (final AmazonClientException e) { log.error("Service call failed.", e); throw new KinesisVideoException(e); + } catch (final IllegalArgumentException e) { + log.error("Stream description null.", e); } - - log.debug("delete stream result: {}", deleteStreamResult.toString()); } @Override @@ -463,7 +448,7 @@ public void putMedia(@Nonnull final String streamName, putMediaClient.putMediaInBackground(); } - private static StreamDescription toStreamDescription(@Nonnull final DescribeStreamResult result) { + static StreamDescription toStreamDescription(@Nonnull final DescribeStreamResult result) { Preconditions.checkNotNull(result); return new StreamDescription( StreamDescription.STREAM_DESCRIPTION_CURRENT_VERSION, diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/StreamInfo.java b/src/main/java/com/amazonaws/kinesisvideo/producer/StreamInfo.java index 1bbbcef56..49b14886a 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/producer/StreamInfo.java +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/StreamInfo.java @@ -3,7 +3,10 @@ import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException; import com.amazonaws.kinesisvideo.common.preconditions.Preconditions; +import com.amazonaws.kinesisvideo.demoapp.DemoAppCachedInfo; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -25,11 +28,13 @@ */ @SuppressFBWarnings("EI_EXPOSE_REP") public class StreamInfo { + + private static final Logger log = LogManager.getLogger(StreamInfo.class); + /** * StreamInfo structure current version. * IMPORTANT: Must be kept in sync with the native counterpart. */ - //TODO: Update version along with native library builds public static final int STREAM_INFO_CURRENT_VERSION = 2; /** @@ -94,9 +99,9 @@ public static enum NalAdaptationFlags { NAL_ADAPTATION_ANNEXB_NALS.getIntValue() | NAL_ADAPTATION_ANNEXB_CPD_NALS.getIntValue()); - private int value; + private final int value; - private NalAdaptationFlags(final int i) { + NalAdaptationFlags(final int i) { value = i; } @@ -130,9 +135,9 @@ public static enum StorePressurePolicy { */ CONTENT_STORE_PRESSURE_POLICY_DROP_TAIL_ITEM(1); - private int value; + private final int value; - private StorePressurePolicy(final int i) { + StorePressurePolicy(final int i) { value = i; } @@ -339,7 +344,14 @@ public StreamInfo(final int version, @Nullable final String name, @Nonnull final mSegmentUuid = segmentUuid; mTrackInfoList = trackInfoList; mFrameOrderMode = frameOrderMode; - mStorePressurePolicy = storePressurePolicy; + if (mRetentionPeriod > 0) { + mStorePressurePolicy = storePressurePolicy; + } else { + // Persisted ACKs are used to clear the content store. In retention = 0 case, + // there are no persisted ACKS, so OOM policy should not be used. + mStorePressurePolicy = StorePressurePolicy.CONTENT_STORE_PRESSURE_POLICY_DROP_TAIL_ITEM; + log.info("{}: Overriding {} with {} since retention = 0", name, storePressurePolicy, mStorePressurePolicy); + } mAllowStreamCreation = allowStreamCreation; } diff --git a/src/test/java/com/amazonaws/kinesisvideo/auth/DefaultAuthCallbacksTest.java b/src/test/java/com/amazonaws/kinesisvideo/auth/DefaultAuthCallbacksTest.java new file mode 100644 index 000000000..cb525d48c --- /dev/null +++ b/src/test/java/com/amazonaws/kinesisvideo/auth/DefaultAuthCallbacksTest.java @@ -0,0 +1,113 @@ +package com.amazonaws.kinesisvideo.auth; + +import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException; +import com.amazonaws.kinesisvideo.producer.AuthCallbacks; +import com.amazonaws.kinesisvideo.producer.AuthInfo; +import com.amazonaws.kinesisvideo.producer.AuthInfoType; +import com.amazonaws.kinesisvideo.producer.Time; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import org.junit.Before; +import org.junit.Test; + +import javax.annotation.Nullable; +import java.util.Date; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class DefaultAuthCallbacksTest { + + private ScheduledExecutorService executor; + + @Before + public void setUp() { + executor = Executors.newSingleThreadScheduledExecutor(new ThreadFactoryBuilder() + .setNameFormat("DefaultAuthCallbacksTest-thread-%d").build()); + } + + @Test + public void testGetSecurityTokenReturnsValidAuthInfo() { + // Set credentials that expire in 1 hour + final long currentTimeMillis = System.currentTimeMillis(); + final Date expirationDate = new Date(currentTimeMillis + 3600 * 1000); + final KinesisVideoCredentials credentials = new KinesisVideoCredentials("AKIA123", "secret", "token", expirationDate); + + final KinesisVideoCredentialsProvider credentialsProvider = new StaticCredentialsProvider(credentials); + final AuthCallbacks authCallbacks = new DefaultAuthCallbacks(credentialsProvider, executor); + + final AuthInfo authInfo = authCallbacks.getSecurityToken(); + + assertNotNull(authInfo); + assertEquals(AuthInfoType.SECURITY_TOKEN, authInfo.getAuthType()); + assertNotNull(authInfo.getData()); + assertTrue("Expiration should be in the future!", authInfo.getExpiration() > currentTimeMillis * Time.HUNDREDS_OF_NANOS_IN_A_MILLISECOND); + + assertTrue(new String(authInfo.getData()).contains("accessKey")); + } + + @Test + public void testGetSecurityTokenReturnsNullDataWhenCredentialsNull() { + final KinesisVideoCredentialsProvider nullReturningCredentialsProvider = new KinesisVideoCredentialsProvider() { + @Nullable + @Override + public KinesisVideoCredentials getCredentials() throws KinesisVideoException { + return null; + } + + @Nullable + @Override + public KinesisVideoCredentials getUpdatedCredentials() throws KinesisVideoException { + return null; + } + }; + final AuthCallbacks authCallbacks = new DefaultAuthCallbacks(nullReturningCredentialsProvider, executor); + + final AuthInfo authInfo = authCallbacks.getSecurityToken(); + + assertNotNull(authInfo); + assertNull(authInfo.getData()); + assertEquals(0, authInfo.getExpiration()); + } + + @Test + public void testCredentialsTookTooLongToRefresh() { + + final int TIMEOUT_MILLIS = 50; + + final KinesisVideoCredentialsProvider slowCredentialsProvider = new KinesisVideoCredentialsProvider() { + @Nullable + @Override + public KinesisVideoCredentials getCredentials() throws KinesisVideoException { + try { + Thread.sleep(TIMEOUT_MILLIS + 3000); + } catch (final Exception e) { + fail(); + } + return new KinesisVideoCredentials("AKIA123", "secret", "token", new Date()); + } + + @Nullable + @Override + public KinesisVideoCredentials getUpdatedCredentials() throws KinesisVideoException { + try { + Thread.sleep(TIMEOUT_MILLIS + 3000); + } catch (final Exception e) { + fail(); + } + return new KinesisVideoCredentials("AKIA123", "secret", "token", new Date()); + } + }; + final AuthCallbacks authCallbacks = new DefaultAuthCallbacks(slowCredentialsProvider, executor, TIMEOUT_MILLIS); + + final AuthInfo authInfo = authCallbacks.getSecurityToken(); + + assertNotNull(authInfo); + assertNull(authInfo.getData()); + assertEquals(0, authInfo.getExpiration()); + } +} diff --git a/src/test/java/com/amazonaws/kinesisvideo/auth/EmptyCredentialsProviderTest.java b/src/test/java/com/amazonaws/kinesisvideo/auth/EmptyCredentialsProviderTest.java new file mode 100644 index 000000000..87d104dbf --- /dev/null +++ b/src/test/java/com/amazonaws/kinesisvideo/auth/EmptyCredentialsProviderTest.java @@ -0,0 +1,38 @@ +package com.amazonaws.kinesisvideo.auth; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; + +public class EmptyCredentialsProviderTest { + + @Test + public void testGetCredentialsReturnsEmptyCredentials() throws Exception { + final EmptyCredentialsProvider provider = new EmptyCredentialsProvider(); + final KinesisVideoCredentials credentials = provider.getCredentials(); + + assertNotNull("Credentials should not be null", credentials); + assertEquals("Access key should be empty", "", credentials.getAccessKey()); + assertEquals("Secret key should be empty", "", credentials.getSecretKey()); + assertNull("Session token should be null", credentials.getSessionToken()); + assertEquals("Expiration should be 'never expire'", + KinesisVideoCredentials.CREDENTIALS_NEVER_EXPIRE, + credentials.getExpiration()); + } + + @Test + public void testGetUpdatedCredentialsReturnsEmptyCredentials() throws Exception { + final EmptyCredentialsProvider provider = new EmptyCredentialsProvider(); + final KinesisVideoCredentials credentials = provider.getUpdatedCredentials(); + + assertNotNull("Credentials should not be null", credentials); + assertEquals("Access key should be empty", "", credentials.getAccessKey()); + assertEquals("Secret key should be empty", "", credentials.getSecretKey()); + assertNull("Session token should be null", credentials.getSessionToken()); + assertEquals("Expiration should be 'never expire'", + KinesisVideoCredentials.CREDENTIALS_NEVER_EXPIRE, + credentials.getExpiration()); + } +} diff --git a/src/test/java/com/amazonaws/kinesisvideo/auth/KinesisVideoCredentialsTest.java b/src/test/java/com/amazonaws/kinesisvideo/auth/KinesisVideoCredentialsTest.java new file mode 100644 index 000000000..5104ecf23 --- /dev/null +++ b/src/test/java/com/amazonaws/kinesisvideo/auth/KinesisVideoCredentialsTest.java @@ -0,0 +1,69 @@ +package com.amazonaws.kinesisvideo.auth; + +import org.junit.Test; + +import java.util.Date; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class KinesisVideoCredentialsTest { + + @Test + public void testConstructorWithoutSessionToken() { + final String accessKey = "AKIA_TEST_KEY"; + final String secretKey = "SECRET_TEST_KEY"; + + final KinesisVideoCredentials creds = new KinesisVideoCredentials(accessKey, secretKey); + + assertEquals(accessKey, creds.getAccessKey()); + assertEquals(secretKey, creds.getSecretKey()); + assertNull(creds.getSessionToken()); + assertEquals(KinesisVideoCredentials.CREDENTIALS_NEVER_EXPIRE, creds.getExpiration()); + } + + @Test + public void testConstructorWithSessionToken() { + final String accessKey = "AKIA_WITH_SESSION"; + final String secretKey = "SECRET_WITH_SESSION"; + final String sessionToken = "SESSION_TOKEN"; + final Date expiration = new Date(System.currentTimeMillis() + 60000); // 1 minute from now + + final KinesisVideoCredentials creds = new KinesisVideoCredentials(accessKey, secretKey, sessionToken, expiration); + + assertEquals(accessKey, creds.getAccessKey()); + assertEquals(secretKey, creds.getSecretKey()); + assertEquals(sessionToken, creds.getSessionToken()); + assertEquals(expiration, creds.getExpiration()); + } + + @Test + public void testEmptyCredentials() { + final KinesisVideoCredentials emptyCreds = KinesisVideoCredentials.EMPTY_KINESIS_VIDEO_CREDENTIALS; + + assertEquals("", emptyCreds.getAccessKey()); + assertEquals("", emptyCreds.getSecretKey()); + assertNull(emptyCreds.getSessionToken()); + assertEquals(KinesisVideoCredentials.CREDENTIALS_NEVER_EXPIRE, emptyCreds.getExpiration()); + } + + @Test(expected = NullPointerException.class) + public void testConstructorNullAccessKey() { + new KinesisVideoCredentials(null, "secret"); + } + + @Test(expected = NullPointerException.class) + public void testConstructorNullSecretKey() { + new KinesisVideoCredentials("access", null); + } + + @Test(expected = NullPointerException.class) + public void testFullConstructorNullAccessKey() { + new KinesisVideoCredentials(null, "secret", "token", new Date()); + } + + @Test(expected = NullPointerException.class) + public void testFullConstructorNullSecretKey() { + new KinesisVideoCredentials("access", null, "token", new Date()); + } +} diff --git a/src/test/java/com/amazonaws/kinesisvideo/client/KinesisVideoClientConfigurationTest.java b/src/test/java/com/amazonaws/kinesisvideo/client/KinesisVideoClientConfigurationTest.java index 308f0a49b..4fcf02b8a 100644 --- a/src/test/java/com/amazonaws/kinesisvideo/client/KinesisVideoClientConfigurationTest.java +++ b/src/test/java/com/amazonaws/kinesisvideo/client/KinesisVideoClientConfigurationTest.java @@ -126,7 +126,9 @@ public void testIpVersionSet() { @Test public void testToStringDoesntThrowNullPointerException() { - final KinesisVideoClientConfiguration config = KinesisVideoClientConfiguration.builder().build(); + final KinesisVideoClientConfiguration config = KinesisVideoClientConfiguration.builder() + .withStorageCallbacks(null) + .build(); final String toStringOutput = config.toString(); // Ensure it's not the default Object.toString() output diff --git a/src/test/java/com/amazonaws/kinesisvideo/common/ProducerTestBase.java b/src/test/java/com/amazonaws/kinesisvideo/common/ProducerTestBase.java index 9d7942ff2..4477ea79b 100644 --- a/src/test/java/com/amazonaws/kinesisvideo/common/ProducerTestBase.java +++ b/src/test/java/com/amazonaws/kinesisvideo/common/ProducerTestBase.java @@ -144,10 +144,9 @@ protected void createProducer(DeviceInfo deviceInfo) { .withCredentialsProvider(new JavaCredentialsProviderImpl(awsCredentialsProvider)) .build(); - serviceClient = new JavaKinesisVideoServiceClient(log); + serviceClient = new JavaKinesisVideoServiceClient(); authCallbacks = new DefaultAuthCallbacks(configuration.getCredentialsProvider(), - executor, - log); + executor); // use TestStorageCallbacks and TestStreamCallbacks to override the callbacks to update the flags in case of // overflow, errors and other events. The current ProducerTestBase object is passed to their constructors so // that they can access the flags to be updated diff --git a/src/test/java/com/amazonaws/kinesisvideo/java/service/JavaKinesisVideoServiceClientTest.java b/src/test/java/com/amazonaws/kinesisvideo/java/service/JavaKinesisVideoServiceClientTest.java new file mode 100644 index 000000000..8b59baa23 --- /dev/null +++ b/src/test/java/com/amazonaws/kinesisvideo/java/service/JavaKinesisVideoServiceClientTest.java @@ -0,0 +1,162 @@ +package com.amazonaws.kinesisvideo.java.service; + +import com.amazonaws.auth.AWSCredentials; +import com.amazonaws.auth.AWSCredentialsProvider; +import com.amazonaws.auth.AWSSessionCredentials; +import com.amazonaws.kinesisvideo.auth.KinesisVideoCredentials; +import com.amazonaws.kinesisvideo.auth.KinesisVideoCredentialsProvider; +import com.amazonaws.kinesisvideo.auth.StaticCredentialsProvider; +import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException; +import com.amazonaws.kinesisvideo.producer.StreamDescription; +import com.amazonaws.kinesisvideo.producer.StreamStatus; +import com.amazonaws.services.kinesisvideo.model.DescribeStreamResult; +import com.amazonaws.services.kinesisvideo.model.StreamInfo; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.junit.Test; + +import javax.annotation.Nullable; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +public class JavaKinesisVideoServiceClientTest { + + private static final Logger log = LogManager.getLogger(JavaKinesisVideoServiceClientTest.class); + + private final Instant now = Instant.now(); + private final Date expiration = Date.from(now.plus(Duration.ofHours(1))); + + private final KinesisVideoCredentials basicCreds = new KinesisVideoCredentials("ACCESS_KEY", "SECRET_KEY"); + private final KinesisVideoCredentials sessionCreds = new KinesisVideoCredentials("ACCESS_KEY", "SECRET_KEY", "SESSION_TOKEN", expiration); + + @Test + public void testCreateAwsCredentials_withBasicCredentials() throws KinesisVideoException { + final KinesisVideoCredentialsProvider provider = new StaticCredentialsProvider(basicCreds); + + final AWSCredentials credentials = JavaKinesisVideoServiceClient.createAwsCredentials(provider); + + assertNotNull(credentials); + + assertEquals("ACCESS_KEY", credentials.getAWSAccessKeyId()); + assertEquals("SECRET_KEY", credentials.getAWSSecretKey()); + } + + @Test + public void testCreateAwsCredentials_withAWSSessionCredentials() throws KinesisVideoException { + final KinesisVideoCredentialsProvider provider = new StaticCredentialsProvider(sessionCreds); + + final AWSCredentials credentials = JavaKinesisVideoServiceClient.createAwsCredentials(provider); + + assertNotNull(credentials); + assertTrue(credentials instanceof AWSSessionCredentials); + + final AWSSessionCredentials sessionCredentials = (AWSSessionCredentials) credentials; + + assertEquals("ACCESS_KEY", sessionCredentials.getAWSAccessKeyId()); + assertEquals("SECRET_KEY", sessionCredentials.getAWSSecretKey()); + assertEquals("SESSION_TOKEN", sessionCredentials.getSessionToken()); + } + + @Test + public void whenCredentialsProviderIsNull_thenCredentialsProviderIsNull() throws KinesisVideoException { + final AWSCredentialsProvider credentialsProvider = JavaKinesisVideoServiceClient.createAwsCredentialsProvider(null, log); + assertNull(credentialsProvider); + } + + @Test + public void whenCredentialsProviderIsNull_thenCredentialsIsNull() throws KinesisVideoException { + final AWSCredentials credentials = JavaKinesisVideoServiceClient.createAwsCredentials(null); + assertNull(credentials); + } + + @Test + public void whenCredentialsProviderReturnsNull_thenCredentialsReturnsNull() throws KinesisVideoException { + final KinesisVideoCredentialsProvider nullReturningCredentialsProvider = new KinesisVideoCredentialsProvider() { + + @Nullable + @Override + public KinesisVideoCredentials getCredentials() throws KinesisVideoException { + return null; + } + + @Nullable + @Override + public KinesisVideoCredentials getUpdatedCredentials() throws KinesisVideoException { + return null; + } + }; + + final AWSCredentialsProvider credentialsProvider = JavaKinesisVideoServiceClient.createAwsCredentialsProvider(nullReturningCredentialsProvider, log); + + // No exceptions should be thrown + credentialsProvider.refresh(); + assertNull(credentialsProvider.getCredentials()); + } + + @Test + public void whenCredentialsProviderThrowsException_thenCredentialsReturnsNull() throws KinesisVideoException { + final KinesisVideoCredentialsProvider nullReturningCredentialsProvider = new KinesisVideoCredentialsProvider() { + + @Nullable + @Override + public KinesisVideoCredentials getCredentials() throws KinesisVideoException { + throw new KinesisVideoException(); + } + + @Nullable + @Override + public KinesisVideoCredentials getUpdatedCredentials() throws KinesisVideoException { + throw new KinesisVideoException(); + } + }; + + final AWSCredentialsProvider credentialsProvider = JavaKinesisVideoServiceClient.createAwsCredentialsProvider(nullReturningCredentialsProvider, log); + + // No exceptions should be thrown + credentialsProvider.refresh(); + assertNull(credentialsProvider.getCredentials()); + } + + @Test(expected = NullPointerException.class) + public void testToStreamDescription_NullResult() { + JavaKinesisVideoServiceClient.toStreamDescription(null); + } + + @Test + public void testToStreamDescription_BasicConversion() { + final String streamName = "my-stream"; + final String streamArn = "arn:aws:kinesisvideo:us-west-2:123456789012:stream/my-stream/1234567890"; + final String version = "1"; + final Date creationTime = new Date(); + final Integer dataRetentionInHours = 0; + final String status = "ACTIVE"; + final String kmsKeyId = "arn:aws:kms:us-west-2:123456789012:key/abcde123-4567-890a-bcde-1234567890ab"; + + final DescribeStreamResult result = new DescribeStreamResult() + .withStreamInfo(new StreamInfo() + .withStreamName(streamName) + .withStreamARN(streamArn) + .withVersion(version) + .withCreationTime(creationTime) + .withStatus(status) + .withDataRetentionInHours(dataRetentionInHours) + .withKmsKeyId(kmsKeyId)); + + final StreamDescription streamDescription = JavaKinesisVideoServiceClient.toStreamDescription(result); + + assertNotNull(streamDescription); + assertEquals(streamName, streamDescription.getStreamName()); + assertEquals(streamArn, streamDescription.getStreamArn()); + assertEquals(version, streamDescription.getUpdateVersion()); + assertEquals(creationTime.getTime(), streamDescription.getCreationTime()); + assertEquals(StreamStatus.ACTIVE.intValue(), streamDescription.getStreamStatus()); + assertEquals((long) dataRetentionInHours, streamDescription.getRetention()); + assertEquals(kmsKeyId, streamDescription.getKmsKeyId()); + } +} diff --git a/src/test/java/com/amazonaws/kinesisvideo/producer/StreamInfoTest.java b/src/test/java/com/amazonaws/kinesisvideo/producer/StreamInfoTest.java new file mode 100644 index 000000000..5ab7789b2 --- /dev/null +++ b/src/test/java/com/amazonaws/kinesisvideo/producer/StreamInfoTest.java @@ -0,0 +1,169 @@ +package com.amazonaws.kinesisvideo.producer; + +import com.amazonaws.kinesisvideo.common.ProducerTestBase; +import org.junit.Test; + +import static com.amazonaws.kinesisvideo.producer.MkvTrackInfoType.VIDEO; +import static com.amazonaws.kinesisvideo.producer.StreamInfo.NalAdaptationFlags.NAL_ADAPTATION_FLAG_NONE; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.DEFAULT_BITRATE; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.DEFAULT_GOP_DURATION; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.DEFAULT_REPLAY_DURATION; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.DEFAULT_STALENESS_DURATION; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.DEFAULT_TIMESCALE; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.DEFAULT_TRACK_ID; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.KEYFRAME_FRAGMENTATION; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.NOT_ADAPTIVE; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.NO_KMS_KEY_ID; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.NO_RETENTION; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.RECALCULATE_METRICS; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.RECOVER_ON_FAILURE; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.RELATIVE_TIMECODES; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.REQUEST_FRAGMENT_ACKS; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.RETENTION_ONE_HOUR; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.USE_FRAME_TIMECODES; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.VERSION_TWO; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.VIDEO_CODEC_ID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; + +public class StreamInfoTest extends ProducerTestBase { + + + /** + * Persisted ACKs are used to clear the content store. In retention = 0 case, there are no persisted ACKS, + * so OOM policy should not be used. + */ + @Test + public void whenStorePressurePolicyRetentionZero_thenContentStorePolicyOverrideDropTailItem() { + + final byte[] AVCC_EXTRA_DATA = { + (byte) 0x01, (byte) 0x42, (byte) 0x00, (byte) 0x1E, (byte) 0xFF, (byte) 0xE1, (byte) 0x00, (byte) 0x22, + (byte) 0x27, (byte) 0x42, (byte) 0x00, (byte) 0x1E, (byte) 0x89, (byte) 0x8B, (byte) 0x60, (byte) 0x50, + (byte) 0x1E, (byte) 0xD8, (byte) 0x08, (byte) 0x80, (byte) 0x00, (byte) 0x13, (byte) 0x88, + (byte) 0x00, (byte) 0x03, (byte) 0xD0, (byte) 0x90, (byte) 0x70, (byte) 0x30, (byte) 0x00, (byte) 0x5D, + (byte) 0xC0, (byte) 0x00, (byte) 0x17, (byte) 0x70, (byte) 0x5E, (byte) 0xF7, (byte) 0xC1, (byte) 0xF0, + (byte) 0x88, (byte) 0x46, (byte) 0xE0, (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x28, (byte) 0xCE, + (byte) 0x1F, (byte) 0x20}; + + final TrackInfo[] trackInfoList = new TrackInfo[]{ + new TrackInfo(DEFAULT_TRACK_ID, VIDEO_CODEC_ID, "VideoTrack", AVCC_EXTRA_DATA, VIDEO)}; + + final StreamInfo streamInfo = new StreamInfo(VERSION_TWO, + "Test Stream 1", + StreamInfo.StreamingType.STREAMING_TYPE_REALTIME, + "video/h264", + NO_KMS_KEY_ID, + NO_RETENTION, + NOT_ADAPTIVE, + TEST_LATENCY, + DEFAULT_GOP_DURATION, + KEYFRAME_FRAGMENTATION, + USE_FRAME_TIMECODES, + RELATIVE_TIMECODES, + REQUEST_FRAGMENT_ACKS, + RECOVER_ON_FAILURE, + DEFAULT_BITRATE, + fps_, + TEST_BUFFER_DURATION, + DEFAULT_REPLAY_DURATION, + DEFAULT_STALENESS_DURATION, + DEFAULT_TIMESCALE, + RECALCULATE_METRICS, + new Tag[]{ + new Tag("device", "Test Device"), + new Tag("stream", "Test Stream")}, + NAL_ADAPTATION_FLAG_NONE, + null, + trackInfoList, + FrameOrderMode.FRAME_ORDER_MODE_PASS_THROUGH, + StreamInfo.StorePressurePolicy.CONTENT_STORE_PRESSURE_POLICY_OOM, + false); + + assertEquals("When retention=0, the content store policy should be overwritten to drop tail item", + StreamInfo.StorePressurePolicy.CONTENT_STORE_PRESSURE_POLICY_DROP_TAIL_ITEM.getIntValue(), + streamInfo.getStorePressurePolicy()); + } + + @Test + public void testGettersReturnExpectedValues() { + final byte[] AVCC_EXTRA_DATA = { + (byte) 0x01, (byte) 0x42, (byte) 0x00, (byte) 0x1E, (byte) 0xFF, (byte) 0xE1, (byte) 0x00, (byte) 0x22, + (byte) 0x27, (byte) 0x42, (byte) 0x00, (byte) 0x1E, (byte) 0x89, (byte) 0x8B, (byte) 0x60, (byte) 0x50, + (byte) 0x1E, (byte) 0xD8, (byte) 0x08, (byte) 0x80, (byte) 0x00, (byte) 0x13, (byte) 0x88, + (byte) 0x00, (byte) 0x03, (byte) 0xD0, (byte) 0x90, (byte) 0x70, (byte) 0x30, (byte) 0x00, (byte) 0x5D, + (byte) 0xC0, (byte) 0x00, (byte) 0x17, (byte) 0x70, (byte) 0x5E, (byte) 0xF7, (byte) 0xC1, (byte) 0xF0, + (byte) 0x88, (byte) 0x46, (byte) 0xE0, (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x28, (byte) 0xCE, + (byte) 0x1F, (byte) 0x20}; + + final TrackInfo[] trackInfoList = new TrackInfo[]{ + new TrackInfo(DEFAULT_TRACK_ID, VIDEO_CODEC_ID, "VideoTrack", AVCC_EXTRA_DATA, VIDEO)}; + + final Tag[] tags = new Tag[]{ + new Tag("device", "Test Device"), + new Tag("stream", "Test Stream")}; + + final StreamInfo streamInfo = new StreamInfo(VERSION_TWO, + "Test Stream 1", + StreamInfo.StreamingType.STREAMING_TYPE_REALTIME, + "video/h264", + NO_KMS_KEY_ID, + RETENTION_ONE_HOUR, + NOT_ADAPTIVE, + TEST_LATENCY, + DEFAULT_GOP_DURATION, + KEYFRAME_FRAGMENTATION, + USE_FRAME_TIMECODES, + RELATIVE_TIMECODES, + REQUEST_FRAGMENT_ACKS, + RECOVER_ON_FAILURE, + DEFAULT_BITRATE, + fps_, + TEST_BUFFER_DURATION, + DEFAULT_REPLAY_DURATION, + DEFAULT_STALENESS_DURATION, + DEFAULT_TIMESCALE, + RECALCULATE_METRICS, + tags, + NAL_ADAPTATION_FLAG_NONE, + null, + trackInfoList, + FrameOrderMode.FRAME_ORDER_MODE_PASS_THROUGH, + StreamInfo.StorePressurePolicy.CONTENT_STORE_PRESSURE_POLICY_OOM, + false); + + assertEquals(VERSION_TWO, streamInfo.getVersion()); + assertEquals("Test Stream 1", streamInfo.getName()); + assertEquals("video/h264", streamInfo.getContentType()); + assertEquals(NO_KMS_KEY_ID, streamInfo.getKmsKeyId()); + assertEquals(StreamInfo.StreamingType.STREAMING_TYPE_REALTIME.getIntValue(), streamInfo.getStreamingType()); + assertEquals(RETENTION_ONE_HOUR, streamInfo.getRetentionPeriod()); + assertEquals(NOT_ADAPTIVE, streamInfo.isAdaptive()); + assertEquals(TEST_LATENCY, streamInfo.getMaxLatency()); + assertEquals(DEFAULT_GOP_DURATION, streamInfo.getFragmentDuration()); + assertEquals(KEYFRAME_FRAGMENTATION, streamInfo.isKeyFrameFragmentation()); + assertEquals(USE_FRAME_TIMECODES, streamInfo.isFrameTimecodes()); + assertEquals(RELATIVE_TIMECODES, streamInfo.isAbsoluteFragmentTimes()); + assertEquals(REQUEST_FRAGMENT_ACKS, streamInfo.isFragmentAcks()); + assertEquals(RECOVER_ON_FAILURE, streamInfo.isRecoverOnError()); + assertEquals(DEFAULT_BITRATE, streamInfo.getAvgBandwidthBps()); + assertEquals(fps_, streamInfo.getFrameRate()); + assertEquals(TEST_BUFFER_DURATION, streamInfo.getBufferDuration()); + assertEquals(DEFAULT_REPLAY_DURATION, streamInfo.getReplayDuration()); + assertEquals(DEFAULT_STALENESS_DURATION, streamInfo.getConnectionStalenessDuration()); + assertEquals(DEFAULT_TIMESCALE, streamInfo.getTimecodeScale()); + assertEquals(RECALCULATE_METRICS, streamInfo.isRecalculateMetrics()); + assertNotNull(streamInfo.getTags()); + assertEquals(tags.length, streamInfo.getTags().length); + assertEquals("device", streamInfo.getTags()[0].getName()); + assertEquals("Test Device", streamInfo.getTags()[0].getValue()); + assertEquals(trackInfoList.length, streamInfo.getTrackInfoList().length); + assertEquals(DEFAULT_TRACK_ID, trackInfoList[0].getTrackId()); + assertEquals(VIDEO_CODEC_ID, trackInfoList[0].getCodecId()); + assertEquals("VideoTrack", trackInfoList[0].getTrackName()); + assertEquals(FrameOrderMode.FRAME_ORDER_MODE_PASS_THROUGH.intValue(), streamInfo.getFrameOrderMode()); + assertEquals(NAL_ADAPTATION_FLAG_NONE.getIntValue(), streamInfo.getNalAdaptationFlags()); + assertEquals(StreamInfo.StorePressurePolicy.CONTENT_STORE_PRESSURE_POLICY_OOM.getIntValue(), streamInfo.getStorePressurePolicy()); + assertFalse(streamInfo.isAllowStreamCreation()); + } +} \ No newline at end of file