summaryrefslogtreecommitdiffstats
path: root/cadi/client/src/test/java/org
diff options
context:
space:
mode:
authorIanHowell <ian.howell@att.com>2018-04-23 13:39:31 -0500
committerIanHowell <ian.howell@att.com>2018-04-23 13:40:17 -0500
commit8bea94c36a838bdabd532cfd25e1275a66407827 (patch)
treeea94f38e1c027a10993b7defbc8ddf915f016333 /cadi/client/src/test/java/org
parent6a93111c678a3970ab2f1667511d59d5fba458f6 (diff)
Improve coverage of Cadi/client
Issue-ID: AAF-224 Change-Id: I26f487429bd46ab176ab6af76942baa068933943 Signed-off-by: IanHowell <ian.howell@att.com>
Diffstat (limited to 'cadi/client/src/test/java/org')
-rw-r--r--cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_AbsAuthentication.java103
-rw-r--r--cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_AbsTransferSS.java72
-rw-r--r--cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Future.java45
-rw-r--r--cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Rcli.java284
-rw-r--r--cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Result.java51
-rw-r--r--cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Retryable.java59
6 files changed, 614 insertions, 0 deletions
diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_AbsAuthentication.java b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_AbsAuthentication.java
new file mode 100644
index 00000000..cc67946e
--- /dev/null
+++ b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_AbsAuthentication.java
@@ -0,0 +1,103 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.cadi.client.test;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+import org.junit.*;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.client.AbsAuthentication;
+import org.onap.aaf.cadi.config.SecurityInfoC;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.HttpURLConnection;
+
+public class JU_AbsAuthentication {
+
+ private final static String ID = "id";
+ private final static String PASSWORD = "password";
+ private final static String WARNING = "Your service has 1000 consecutive bad service " +
+ "logins to AAF. AAF Access will be disabled after 10000\n";
+
+ private static ByteArrayOutputStream errStream;
+
+ @Before
+ public void setup() {
+ errStream = new ByteArrayOutputStream();
+ System.setErr(new PrintStream(errStream));
+ }
+
+ @After
+ public void tearDown() {
+ System.setErr(System.err);
+ }
+
+ @Test
+ public void test() throws IOException, InterruptedException {
+ AuthStub stub = new AuthStub(null, null, null);
+ assertThat(stub.getID(), is(nullValue()));
+ assertThat(stub.headValue(), is(""));
+ assertThat(stub.count(), is(0));
+
+ stub.setUser(ID);
+ assertThat(stub.getID(), is(ID));
+
+ stub = new AuthStub(null, ID, PASSWORD.getBytes());
+ assertThat(stub.getID(), is(ID));
+ assertThat(stub.headValue(), is(PASSWORD));
+ assertThat(stub.count(), is(0));
+
+ assertThat(stub.setLastResponse(200), is(0));
+ assertThat(stub.isDenied(), is(false));
+
+ for (int i = 1; i <= 10; i++) {
+ assertThat(stub.setLastResponse(401), is(i));
+ assertThat(stub.isDenied(), is(false));
+ }
+ assertThat(stub.setLastResponse(401), is(11));
+ assertThat(stub.isDenied(), is(true));
+
+ stub.setCount(999);
+ assertThat(stub.setLastResponse(401), is(1000));
+ assertThat(errStream.toString(), is(WARNING));
+
+ // coverage...
+ stub.setLastMiss(1);
+ assertThat(stub.isDenied(), is(false));
+ }
+
+ private class AuthStub extends AbsAuthentication<HttpURLConnection> {
+
+ public AuthStub(SecurityInfoC<HttpURLConnection> securityInfo, String user, byte[] headValue)
+ throws IOException { super(securityInfo, user, headValue); }
+
+ @Override public void setSecurity(HttpURLConnection client) throws CadiException { }
+ @Override public void setUser(String id) { super.setUser(id); }
+ @Override public String headValue() throws IOException { return super.headValue(); }
+
+ public void setLastMiss(long lastMiss) { this.lastMiss = lastMiss; }
+ public void setCount(int count) { this.count = count; }
+ }
+
+}
diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_AbsTransferSS.java b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_AbsTransferSS.java
new file mode 100644
index 00000000..507f90f4
--- /dev/null
+++ b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_AbsTransferSS.java
@@ -0,0 +1,72 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.cadi.client.test;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+import static org.mockito.Mockito.*;
+import org.junit.*;
+import org.mockito.*;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.client.AbsTransferSS;
+import org.onap.aaf.cadi.config.SecurityInfoC;
+import org.onap.aaf.cadi.principal.TaggedPrincipal;
+
+import java.net.HttpURLConnection;
+
+public class JU_AbsTransferSS {
+
+ @Mock TaggedPrincipal princMock;
+ @Mock SecurityInfoC<HttpURLConnection> siMock;
+
+ private static final String princName = "name";
+ private static final String princTag = "tag";
+ private static final String app = "app";
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ when(princMock.getName()).thenReturn(princName);
+ when(princMock.tag()).thenReturn(princTag);
+ }
+
+ @Test
+ public void test() {
+ TransferSSStub stub = new TransferSSStub(princMock, app);
+ assertThat(stub.getID(), is(princName));
+ assertThat(stub.getValue(), is(princName + ':' + app + ':' + princTag + ':' + "AS"));
+
+ stub = new TransferSSStub(null, app, siMock);
+ assertThat(stub.getID(), is(""));
+ assertThat(stub.getValue(), is(nullValue()));
+ }
+
+ private class TransferSSStub extends AbsTransferSS<HttpURLConnection> {
+ public TransferSSStub(TaggedPrincipal principal, String app) { super(principal, app); }
+ public TransferSSStub(TaggedPrincipal principal, String app, SecurityInfoC<HttpURLConnection> si) { super(principal, app, si); }
+ @Override public void setSecurity(HttpURLConnection client) throws CadiException { }
+ @Override public int setLastResponse(int respCode) { return 0; }
+ public String getValue() { return value; }
+ }
+
+}
diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Future.java b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Future.java
new file mode 100644
index 00000000..ad0bd535
--- /dev/null
+++ b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Future.java
@@ -0,0 +1,45 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.cadi.client.test;
+
+import org.junit.Test;
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.client.Future;
+
+// This class exists purely to instantiate (and therefore attain coverage of) the Future class
+
+public class JU_Future {
+
+ @Test
+ public void test() {
+ @SuppressWarnings("unused")
+ Future<Integer> f = new FutureStub();
+ }
+
+ private class FutureStub extends Future<Integer> {
+ @Override public boolean get(int timeout) throws CadiException { return false; }
+ @Override public int code() { return 0; }
+ @Override public String body() { return null; }
+ @Override public String header(String tag) { return null; }
+ }
+
+}
diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Rcli.java b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Rcli.java
new file mode 100644
index 00000000..f957878b
--- /dev/null
+++ b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Rcli.java
@@ -0,0 +1,284 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.cadi.client.test;
+
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+import static org.hamcrest.CoreMatchers.*;
+import org.junit.*;
+import org.mockito.*;
+
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.SecuritySetter;
+import org.onap.aaf.cadi.client.EClient;
+import org.onap.aaf.cadi.client.Future;
+import org.onap.aaf.cadi.client.Rcli;
+import org.onap.aaf.misc.env.APIException;
+import org.onap.aaf.misc.env.Data;
+import org.onap.aaf.misc.env.Data.TYPE;
+import org.onap.aaf.misc.rosetta.env.RosettaDF;
+import org.onap.aaf.misc.rosetta.env.RosettaData;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.net.HttpURLConnection;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Enumeration;
+
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class JU_Rcli {
+
+ @Mock RosettaDF<HttpURLConnection> dfMock;
+ @Mock RosettaData<HttpURLConnection> dataMock;
+ @Mock HttpURLConnection conMock;
+ @Mock HttpServletRequest reqMock;
+ @Mock HttpServletResponse respMock;
+ @Mock ServletInputStream isMock;
+
+ private final static String uriString = "example.com";
+ private final static String apiVersion = "v1.0";
+ private final static String fragment = "framgent";
+ private final static String queryParams = "queryParams";
+ private final static String contentType = "contentType";
+
+ private static URI uri;
+ private static Enumeration<String> enumeration;
+
+ private Client client;
+
+ @Before
+ public void setup() throws URISyntaxException, IOException {
+ MockitoAnnotations.initMocks(this);
+
+ when(dfMock.getTypeClass()).thenReturn(HttpURLConnection.class);
+ when(dfMock.newData()).thenReturn(dataMock);
+ when(dataMock.out((TYPE) any())).thenReturn(dataMock);
+
+ when(reqMock.getInputStream()).thenReturn(isMock);
+ when(isMock.read((byte[]) any())).thenReturn(-1);
+
+ uri = new URI(uriString);
+ enumeration = new CustomEnumeration();
+ client = new Client();
+ }
+
+ @Test
+ public void createTest() throws APIException, CadiException {
+ RcliStub rcli = new RcliStub(uri);
+ rcli.type(Data.TYPE.XML);
+
+ rcli.create(null, contentType, dfMock, conMock);
+ rcli.create("No question mark", contentType, dfMock, conMock);
+ rcli.create("question?mark", contentType, dfMock, conMock);
+
+ rcli.create(null, dfMock, conMock);
+ rcli.create("No question mark", dfMock, conMock);
+ rcli.create("question?mark", dfMock, conMock);
+
+ rcli.create(null, HttpURLConnection.class, dfMock, conMock);
+ rcli.create("No question mark", HttpURLConnection.class, dfMock, conMock);
+ rcli.create("question?mark", HttpURLConnection.class, dfMock, conMock);
+
+ rcli.create(null, HttpURLConnection.class);
+ rcli.create("No question mark", HttpURLConnection.class);
+ rcli.create("question?mark", HttpURLConnection.class);
+
+ rcli.create(null, contentType);
+ rcli.create("No question mark", contentType);
+ rcli.create("question?mark", contentType);
+ }
+
+ @Test
+ public void postFormTest() throws APIException, CadiException {
+ RcliStub rcli = new RcliStub(uri);
+
+ rcli.type(Data.TYPE.DEFAULT);
+ rcli.postForm(null, dfMock);
+ rcli.postForm("No question mark", dfMock);
+ rcli.postForm("question?mark", dfMock);
+
+ rcli.type(Data.TYPE.JSON);
+ rcli.postForm("question?mark", dfMock);
+
+ rcli.type(Data.TYPE.XML);
+ rcli.postForm("question?mark", dfMock);
+
+ }
+
+ @Test
+ public void readPostTest() throws APIException, CadiException {
+ RcliStub rcli = new RcliStub(uri);
+ rcli.type(Data.TYPE.DEFAULT);
+
+ rcli.readPost(null, dfMock, conMock);
+ rcli.readPost("No question mark", dfMock, conMock);
+ rcli.readPost("question?mark", dfMock, conMock);
+
+ rcli.readPost(null, dfMock, conMock, dfMock);
+ rcli.readPost("No question mark", dfMock, conMock, dfMock);
+ rcli.readPost("question?mark", dfMock, conMock, dfMock);
+
+ rcli.readPost("First string", "Second string");
+ }
+
+ @Test
+ public void readTest() throws APIException, CadiException {
+ RcliStub rcli = new RcliStub(uri);
+ rcli.type(Data.TYPE.DEFAULT);
+
+ rcli.read("First string", "Second string", "Third string", "Fourth string");
+ rcli.read("First string", "Second string", dfMock, "Third string", "Fourth string");
+ rcli.read("First string", dfMock, "Third string", "Fourth string");
+ rcli.read("First string", HttpURLConnection.class ,dfMock);
+ }
+
+ @Test
+ public void updateTest() throws APIException, CadiException {
+ RcliStub rcli = new RcliStub(uri);
+ rcli.type(Data.TYPE.DEFAULT);
+
+ rcli.update("First string", "Second string", dfMock, conMock);
+ rcli.update("First string", dfMock, conMock);
+ rcli.update("First string", HttpURLConnection.class, dfMock, conMock);
+ rcli.update("First string");
+ rcli.updateRespondString("First string", dfMock, conMock);
+ }
+
+ @Test
+ public void deleteTest() throws APIException, CadiException {
+ RcliStub rcli = new RcliStub(uri);
+ rcli.type(Data.TYPE.DEFAULT);
+
+ rcli.delete("First string", "Second string", dfMock, conMock);
+ rcli.delete("First string", dfMock, conMock);
+ rcli.delete("First string", HttpURLConnection.class, dfMock, conMock);
+ rcli.delete("First string", HttpURLConnection.class);
+ rcli.delete("First string", "Second string");
+ }
+
+ @Test
+ public void transferTest() throws APIException, CadiException {
+ RcliStub rcli = new RcliStub(uri);
+ rcli.type(Data.TYPE.DEFAULT);
+
+ when(reqMock.getRequestURI()).thenReturn(uriString);
+ when(reqMock.getHeaderNames()).thenReturn(enumeration);
+ rcli.transfer(reqMock, respMock, "string", 200);
+
+ // coverage...
+ when(reqMock.getMethod()).thenReturn("GET");
+ rcli.transfer(reqMock, respMock, "string", 200);
+ }
+
+ @Test(expected = CadiException.class)
+ public void transferThrowsTest() throws APIException, CadiException {
+ RcliStub rcli = new RcliStub(uri);
+ rcli.type(Data.TYPE.DEFAULT);
+
+ rcli.transfer(reqMock, respMock, "string", 200);
+ }
+
+ @Test
+ public void accessorMutatorTest() throws URISyntaxException {
+ RcliStub rcli = new RcliStub();
+ Rcli<?> rcliClone = rcli.forUser(null);
+
+ rcli = new RcliStub(uri);
+ assertThat(rcli.toString(), is(uriString));
+ assertThat(rcli.getURI(), is(uri));
+ assertThat(rcli.getReadTimeout(), is(5000));
+ assertThat(rcli.getConnectionTimeout(), is(3000));
+
+ rcli.connectionTimeout(3001);
+ assertThat(rcli.getConnectionTimeout(), is(3001));
+ rcli.readTimeout(5001);
+ assertThat(rcli.getReadTimeout(), is(5001));
+ rcli.apiVersion(apiVersion);
+ assertThat(rcli.isApiVersion(apiVersion), is(true));
+ rcli.type(Data.TYPE.XML);
+ assertThat(rcli.typeString(HttpURLConnection.class), is("application/HttpURLConnection+xml;version=" + apiVersion));
+ rcli.apiVersion(null);
+ assertThat(rcli.typeString(HttpURLConnection.class), is("application/HttpURLConnection+xml"));
+
+ rcli.setFragment(fragment);
+ rcli.setQueryParams(queryParams);
+
+ rcliClone = rcli.forUser(null);
+ assertThat(rcliClone.toString(), is(uriString));
+ }
+
+ private class RcliStub extends Rcli<HttpURLConnection> {
+ public RcliStub() { super(); }
+ public RcliStub(URI uri) { this.uri = uri; }
+ @Override public void setSecuritySetter(SecuritySetter<HttpURLConnection> ss) { }
+ @Override public SecuritySetter<HttpURLConnection> getSecuritySetter() { return null; }
+ @Override protected Rcli<HttpURLConnection> clone(URI uri, SecuritySetter<HttpURLConnection> ss) { return this; }
+ @Override public void invalidate() throws CadiException { }
+ @Override protected EClient<HttpURLConnection> client() throws CadiException { return client; }
+ public int getReadTimeout() { return readTimeout; }
+ public int getConnectionTimeout() { return connectionTimeout; }
+ }
+
+ private class CustomEnumeration implements Enumeration<String> {
+ private int idx = 0;
+ private final String[] elements = {"This", "is", "a", "test"};
+ @Override
+ public String nextElement() {
+ return idx >= elements.length ? null : elements[idx++];
+ }
+ @Override
+ public boolean hasMoreElements() {
+ return idx < elements.length;
+ }
+ }
+
+ private class Client implements EClient<HttpURLConnection> {
+ private Transfer transfer;
+ @Override public void setPayload(Transfer transfer) { this.transfer = transfer; }
+ @Override public void setMethod(String meth) { }
+ @Override public void setPathInfo(String pathinfo) { }
+ @Override public void addHeader(String tag, String value) { }
+ @Override public void setQueryParams(String q) { }
+ @Override public void setFragment(String f) { }
+ @Override public void send() throws APIException {
+ try {
+ if (transfer != null) {
+ transfer.transfer(new PrintStream(new ByteArrayOutputStream()));
+ }
+ } catch (IOException e) {
+ }
+ }
+ @Override public <T> Future<T> futureCreate(Class<T> t) { return null; }
+ @Override public Future<String> futureReadString() { return null; }
+ @Override public <T> Future<T> futureRead(RosettaDF<T> df, TYPE type) { return null; }
+ @Override public <T> Future<T> future(T t) { return null; }
+ @Override public Future<Void> future(HttpServletResponse resp, int expected) throws APIException { return null; }
+ }
+
+ //private class FutureStub implements Future<String> {
+ //}
+}
diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Result.java b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Result.java
new file mode 100644
index 00000000..05ca27f3
--- /dev/null
+++ b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Result.java
@@ -0,0 +1,51 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.cadi.client.test;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+import org.junit.*;
+
+import org.onap.aaf.cadi.client.Result;
+
+public class JU_Result {
+
+ private static final int OK = 200;
+ private static final int NOT_FOUND = 404;
+
+ @Test
+ public void test() {
+ Result<Integer> result;
+ result = Result.ok(OK, 10);
+ assertThat(result.toString(), is("Code: 200"));
+ assertThat(result.isOK(), is(true));
+
+ result = Result.err(NOT_FOUND, "File not found");
+ assertThat(result.toString(), is("Code: 404 = File not found"));
+ assertThat(result.isOK(), is(false));
+
+ result = Result.err(result);
+ assertThat(result.toString(), is("Code: 404 = File not found"));
+ assertThat(result.isOK(), is(false));
+ }
+
+}
diff --git a/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Retryable.java b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Retryable.java
new file mode 100644
index 00000000..84863744
--- /dev/null
+++ b/cadi/client/src/test/java/org/onap/aaf/cadi/client/test/JU_Retryable.java
@@ -0,0 +1,59 @@
+/**
+ * ============LICENSE_START====================================================
+ * org.onap.aaf
+ * ===========================================================================
+ * Copyright (c) 2018 AT&T Intellectual Property. 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
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END====================================================
+ *
+ */
+
+package org.onap.aaf.cadi.client.test;
+
+import static org.junit.Assert.*;
+import static org.hamcrest.CoreMatchers.*;
+import org.junit.*;
+
+import java.net.ConnectException;
+
+import org.onap.aaf.cadi.CadiException;
+import org.onap.aaf.cadi.Locator;
+import org.onap.aaf.cadi.client.Rcli;
+import org.onap.aaf.cadi.client.Retryable;
+import org.onap.aaf.misc.env.APIException;
+
+public class JU_Retryable {
+
+ @Test
+ public void test() {
+ RetryableStub retry = new RetryableStub();
+ assertThat(retry.item(), is(nullValue()));
+ assertThat(retry.lastClient(), is(nullValue()));
+
+ Locator.Item item = null;
+ assertThat(retry.item(item), is(item));
+
+ retry = new RetryableStub(retry);
+ assertThat(retry.item(), is(nullValue()));
+ assertThat(retry.lastClient(), is(nullValue()));
+ assertThat(retry.item(item), is(item));
+ }
+
+ private class RetryableStub extends Retryable<Integer> {
+ public RetryableStub() { super(); }
+ public RetryableStub(Retryable<?> ret) { super(ret); }
+ @Override public Integer code(Rcli<?> client) throws CadiException, ConnectException, APIException { return null; }
+ }
+
+}