diff options
author | Kanagaraj Manickam k00365106 <kanagaraj.manickam@huawei.com> | 2017-12-11 20:34:44 +0530 |
---|---|---|
committer | Kanagaraj Manickam k00365106 <kanagaraj.manickam@huawei.com> | 2017-12-12 15:48:55 +0530 |
commit | 0d97a835fa2052ded5a31e8921baf641c8e9bb57 (patch) | |
tree | 800584529f77c8ff26f05a73abd3fa71205a69a7 /profiles/http/src/test | |
parent | 03c54a40daf75644ec0bcbc73636e3eb427c1604 (diff) |
Make Http as separate plugin
Issue-ID: CLI-66
Change-Id: I8ad78f417f6dbb00e29effdd3ed8ec1939aee81d
Signed-off-by: Kanagaraj Manickam k00365106 <kanagaraj.manickam@huawei.com>
Diffstat (limited to 'profiles/http/src/test')
22 files changed, 1321 insertions, 0 deletions
diff --git a/profiles/http/src/test/java/org/onap/cli/fw/cmd/OnapHttpCommandTest.java b/profiles/http/src/test/java/org/onap/cli/fw/cmd/OnapHttpCommandTest.java new file mode 100644 index 00000000..bb318e1f --- /dev/null +++ b/profiles/http/src/test/java/org/onap/cli/fw/cmd/OnapHttpCommandTest.java @@ -0,0 +1,80 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.cmd; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +import org.junit.Test; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.http.cmd.OnapHttpCommand; +import org.onap.cli.fw.http.connect.HttpInput; +import org.onap.cli.fw.input.OnapCommandParameter; +import org.onap.cli.fw.input.OnapCommandParameterType; + +public class OnapHttpCommandTest { + + @Test(expected = OnapCommandException.class) + public void runTest() throws OnapCommandException { + OnapCommandParameter param1 = new OnapCommandParameter(); + param1.setLongOption("host-username"); + param1.setName("host-username"); + param1.setParameterType(OnapCommandParameterType.STRING); + OnapCommandParameter param2 = new OnapCommandParameter(); + param2.setLongOption("host-password"); + param2.setName("host-password"); + param2.setParameterType(OnapCommandParameterType.STRING); + OnapCommandParameter param3 = new OnapCommandParameter(); + param3.setLongOption("host-url"); + param3.setName("host-url"); + param3.setParameterType(OnapCommandParameterType.STRING); + OnapCommandParameter param4 = new OnapCommandParameter(); + param4.setLongOption("string-param"); + param4.setName("string-param"); + param4.setParameterType(OnapCommandParameterType.STRING); + OnapCommandParameter param5 = new OnapCommandParameter(); + param5.setLongOption("long-opt"); + param5.setName("long-opt"); + param5.setParameterType(OnapCommandParameterType.STRING); + + Set<OnapCommandParameter> paramslist = new HashSet<>(); + paramslist.add(param1); + paramslist.add(param2); + paramslist.add(param3); + paramslist.add(param4); + paramslist.add(param5); + + HttpInput inp = new HttpInput(); + inp.setBody("body"); + inp.setMethod("method"); + inp.setReqCookies(new HashMap<String, String>()); + inp.setReqHeaders(new HashMap<String, String>()); + inp.setReqQueries(new HashMap<String, String>()); + inp.setUri("uri"); + + OnapHttpCommand com = new OnapHttpCommand(); + com.setParameters(paramslist); + com.getParameters(); + com.getParametersMap(); + com.setInput(inp); + com.initializeSchema("sample-test-schema.yaml"); + com.execute(); + + } + +} diff --git a/profiles/http/src/test/java/org/onap/cli/fw/http/HttpInputOutputTest.java b/profiles/http/src/test/java/org/onap/cli/fw/http/HttpInputOutputTest.java new file mode 100644 index 00000000..99ee3d34 --- /dev/null +++ b/profiles/http/src/test/java/org/onap/cli/fw/http/HttpInputOutputTest.java @@ -0,0 +1,69 @@ +/* + * Copyright 2016-17 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http; + +import static org.junit.Assert.assertTrue; + +import java.util.HashMap; + +import org.junit.Test; +import org.onap.cli.fw.http.connect.HttpInput; +import org.onap.cli.fw.http.connect.HttpResult; + +public class HttpInputOutputTest { + + @Test + public void httpInputTest() { + HttpInput inp = new HttpInput(); + inp.setBody("body"); + inp.setMethod("method"); + inp.setReqCookies(null); + inp.setReqHeaders(null); + inp.setReqQueries(null); + inp.setUri("uri"); + + assertTrue("body".equals(inp.getBody()) && "method".equals(inp.getMethod()) && null == inp.getReqCookies() + && inp.getReqHeaders().isEmpty() && inp.getReqQueries().isEmpty() && "uri".equals(inp.getUri())); + + inp.setReqCookies(new HashMap<String, String>()); + inp.setReqHeaders(new HashMap<String, String>()); + inp.setReqQueries(new HashMap<String, String>()); + + assertTrue( + "\nURL: uri\nMethod: method\nRequest Queries: {}\nRequest Body: body\nRequest Headers: {}\nRequest Cookies: {}\nbinaryData=false" + .equals(inp.toString())); + } + + @Test + public void httpResultTest() { + HttpResult out = new HttpResult(); + out.setBody("body"); + out.setRespCookies(null); + out.setRespHeaders(null); + out.setStatus(205); + + assertTrue("body".equals(out.getBody()) && null == out.getRespCookies() && null == out.getRespHeaders() + && 205 == out.getStatus()); + + out.setRespCookies(new HashMap<String, String>()); + out.setRespHeaders(new HashMap<String, String>()); + out.setStatus(200); + assertTrue("\nHTTP Status: 200\nResponse Body: body\nResponse Headers: {}\nResponse Cookies: {}" + .equals(out.toString())); + } + +} diff --git a/profiles/http/src/test/java/org/onap/cli/fw/http/OnapHttpConnectionTest.java b/profiles/http/src/test/java/org/onap/cli/fw/http/OnapHttpConnectionTest.java new file mode 100644 index 00000000..fe29936a --- /dev/null +++ b/profiles/http/src/test/java/org/onap/cli/fw/http/OnapHttpConnectionTest.java @@ -0,0 +1,208 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; + +import org.apache.http.client.ClientProtocolException; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.protocol.HttpContext; +import org.junit.Before; +import org.junit.Test; +import org.onap.cli.fw.http.connect.HttpInput; +import org.onap.cli.fw.http.connect.HttpResult; +import org.onap.cli.fw.http.connect.OnapHttpConnection; +import org.onap.cli.fw.http.error.OnapCommandHttpFailure; + +import mockit.Invocation; +import mockit.Mock; +import mockit.MockUp; + +public class OnapHttpConnectionTest { + HttpInput inp = null; + OnapHttpConnection con = null; + + @Before + public void setup() { + mockHttpRequest(null); + inp = new HttpInput(); + inp.setMethod("get"); + inp.setBody("body"); + Map<String, String> map1 = new HashMap<>(); + map1.put("header1", "value1"); + inp.setReqHeaders(map1); + Map<String, String> map2 = new HashMap<>(); + map2.put("query1", "value1"); + inp.setReqQueries(map2); + Map<String, String> map = new HashMap<>(); + map.put("cookie1", "value1"); + inp.setReqCookies(map); + inp.setUri("http://192.168.99.10:80"); + } + + @Test(expected = OnapCommandHttpFailure.class) + public void httpUnSecuredGetExceptionTest() throws OnapCommandHttpFailure { + new MockUp<CloseableHttpClient>() { + @Mock + public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) + throws IOException, ClientProtocolException { + + throw new IOException("IO Exception"); + } + }; + inp.setMethod("get"); + con = new OnapHttpConnection(true); + con.getDebugInfo(); + con.get(inp); + + } + + @Test(expected = OnapCommandHttpFailure.class) + public void httpUnSecuredPostExceptionTest() throws OnapCommandHttpFailure { + new MockUp<CloseableHttpClient>() { + @Mock + public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) + throws IOException, ClientProtocolException { + + throw new IOException("IO Exception"); + } + }; + + inp.setMethod("post"); + con = new OnapHttpConnection(true); + con.post(inp); + } + + + @Test(expected = OnapCommandHttpFailure.class) + public void httpUnSecuredPostExceptionTest1() throws OnapCommandHttpFailure { + new MockUp<CloseableHttpClient>() { + @Mock + public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) + throws IOException, ClientProtocolException { + + throw new IOException("IO Exception"); + } + }; + + inp.setMethod("post"); + inp.setBinaryData(true); + con = new OnapHttpConnection(true); + con.post(inp); + } + + @Test(expected = OnapCommandHttpFailure.class) + public void httpUnSecuredPutExceptionTest() throws OnapCommandHttpFailure { + new MockUp<CloseableHttpClient>() { + @Mock + public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) + throws IOException, ClientProtocolException { + + throw new IOException("IO Exception"); + } + }; + inp.setMethod("put"); + con = new OnapHttpConnection(true); + con.put(inp); + } + + @Test(expected = OnapCommandHttpFailure.class) + public void httpUnSecuredDeleteExceptionTest() throws OnapCommandHttpFailure { + new MockUp<CloseableHttpClient>() { + @Mock + public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) + throws IOException, ClientProtocolException { + + throw new IOException("IO Exception"); + } + }; + inp.setMethod("delete"); + con = new OnapHttpConnection(true); + con.delete(inp); + } + + @Test(expected = IllegalArgumentException.class) + public void httpUnSecuredOtherExceptionTest() throws OnapCommandHttpFailure { + new MockUp<CloseableHttpClient>() { + @Mock + public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) + throws IOException, ClientProtocolException { + + throw new IOException("IO Exception"); + } + }; + inp.setMethod("other"); + con = new OnapHttpConnection(true); + con.request(inp); + } + + @Test() + public void httpUnSecuredCloseExceptionTest() throws OnapCommandHttpFailure { + inp.setMethod("other"); + con = new OnapHttpConnection(true); + con.close(); + } + + @Test + public void httpSecuredGetExceptionTest() { + + // ProtocolVersion p = new ProtocolVersion("http",1,0); + // HttpResponse hr = DefaultHttpResponseFactory.INSTANCE.newHttpResponse(p, 200 , null) ; + + new MockUp<CloseableHttpClient>() { + @Mock + public CloseableHttpResponse execute(HttpUriRequest request, HttpContext context) + throws IOException, ClientProtocolException { + + throw new IOException("IO Exception"); + } + }; + try { + HttpInput inp = new HttpInput(); + inp.setMethod("get"); + inp.setBody("body"); + inp.setReqHeaders(new HashMap<String, String>()); + inp.setReqQueries(new HashMap<String, String>()); + inp.setUri("https://192.168.99.10:80"); + OnapHttpConnection con = new OnapHttpConnection(false); + con.get(inp); + } catch (OnapCommandHttpFailure e) { + assertEquals("0x3001::IO Exception", e.getMessage()); + } + } + + private static void mockHttpRequest(HttpResult result) { + new MockUp<OnapHttpConnection>() { + boolean isMock = false; + + @Mock + public HttpResult request(Invocation inv, HttpInput input) throws OnapCommandHttpFailure { + if (isMock) { + return result; + } else { + return inv.proceed(input); + } + } + }; + } +} diff --git a/profiles/http/src/test/java/org/onap/cli/fw/http/auth/OnapAuthClientCommandBasedTest.java b/profiles/http/src/test/java/org/onap/cli/fw/http/auth/OnapAuthClientCommandBasedTest.java new file mode 100644 index 00000000..d3059449 --- /dev/null +++ b/profiles/http/src/test/java/org/onap/cli/fw/http/auth/OnapAuthClientCommandBasedTest.java @@ -0,0 +1,121 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.auth; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Before; +import org.junit.Test; +import org.onap.cli.fw.conf.OnapCommandConfig; +import org.onap.cli.fw.conf.OnapCommandConstants; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.error.OnapCommandProductVersionInvalid; +import org.onap.cli.fw.http.cmd.OnapHttpCommand; +import org.onap.cli.fw.http.conf.OnapCommandHttpConstants; +import org.onap.cli.fw.registrar.OnapCommandRegistrar; + +public class OnapAuthClientCommandBasedTest { + + @Before + public void setup() throws OnapCommandProductVersionInvalid, OnapCommandException { + OnapCommandRegistrar.getRegistrar().setEnabledProductVersion(OnapCommandConfig.getPropertyValue(OnapCommandConstants.OPEN_CLI_PRODUCT_NAME)); + } + + @Test + public void yesCatalogYesAuthTest() throws OnapCommandException { + try { + OnapHttpCommand cmd = getCommand("sample-test-schema-yes-auth-yes-catalog.yaml"); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_HOST_URL).setValue("http://localhost:8080"); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setValue("test"); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setValue("password"); + + cmd.execute(); + } catch (OnapCommandException e) { + fail("External command Yes Auth Yes Catalog failed to run"); + e.printStackTrace(System.out); + } + } + + @Test + public void yesCatalogNoAuthTest() throws OnapCommandException { + try { + OnapHttpCommand cmd = getCommand("sample-test-schema-no-auth-yes-catalog.yaml"); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_HOST_URL).setValue("http://localhost:8080"); + + cmd.execute(); + } catch (OnapCommandException e) { + fail("External command Yes Auth No Catalog failed to run " + e.getMessage()); + e.printStackTrace(System.out); + } + } + + @Test + public void noCatalogYesAuthTest() throws OnapCommandException { + try { + OnapHttpCommand cmd = getCommand("sample-test-schema-yes-auth-no-catalog.yaml"); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_HOST_URL).setValue("http://localhost:8080"); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_USERNAME).setValue("test"); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_PASSWORD).setValue("password"); + + cmd.execute(); + } catch (OnapCommandException e) { + fail("External command Yes Auth No Catalog failed to run"); + e.printStackTrace(System.out); + } + } + + @Test + public void noCatalogYesAuthWithAdditionalParamsTest() throws OnapCommandException { + try { + OnapHttpCommand cmd = getCommand("sample-test-schema-yes-auth-with-additional-params-no-catalog.yaml"); + assertTrue(cmd.getParametersMap().containsKey("string-param")); + } catch (OnapCommandException e) { + fail("External command Yes Auth No Catalog failed to run"); + e.printStackTrace(System.out); + } + } + + @Test + public void noCatalogNoAuthTest() throws OnapCommandException { + try { + OnapHttpCommand cmd = getCommand("sample-test-schema-no-auth-no-catalog.yaml"); + cmd.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_HOST_URL).setValue("http://localhost:8080"); + + cmd.execute(); + } catch (OnapCommandException e) { + fail("External command No Auth No Catalog failed to run"); + e.printStackTrace(System.out); + } + } + + private OnapHttpCommand getCommand(String yaml) throws OnapCommandException { + OnapHttpCommand cmd = new OnapHttpCommand() { + @Override + protected void processRequest() throws OnapCommandException { + if (!this.getService().isModeDirect()) { + String url = this.authClient.getServiceUrl(); + assert url.equals(this.getParametersMap().get(OnapCommandHttpConstants.DEAFULT_PARAMETER_HOST_URL).getValue() + "/"); + } + } + }; + + cmd.initializeSchema(yaml); + + return cmd; + } + } diff --git a/profiles/http/src/test/java/org/onap/cli/fw/http/auth/OnapServiceTest.java b/profiles/http/src/test/java/org/onap/cli/fw/http/auth/OnapServiceTest.java new file mode 100644 index 00000000..8501150e --- /dev/null +++ b/profiles/http/src/test/java/org/onap/cli/fw/http/auth/OnapServiceTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.auth; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.onap.cli.fw.http.conf.OnapCommandHttpConstants; + +public class OnapServiceTest { + + @Test + public void serviceTest() { + OnapCommandHttpService ser = new OnapCommandHttpService(); + ser.setName("name"); + ser.setVersion("1.0"); + ser.setBasePath("basePath"); + ser.setAuthType(OnapCommandHttpConstants.AUTH_NONE); + assertTrue(ser.getName().equals("name") && ser.getVersion().equals("1.0") + && ser.getBasePath().equals("basePath") && ser.isNoAuth()); + + } + +} diff --git a/profiles/http/src/test/java/org/onap/cli/fw/http/error/OnapCommandErrorTest.java b/profiles/http/src/test/java/org/onap/cli/fw/http/error/OnapCommandErrorTest.java new file mode 100644 index 00000000..cd2131e9 --- /dev/null +++ b/profiles/http/src/test/java/org/onap/cli/fw/http/error/OnapCommandErrorTest.java @@ -0,0 +1,84 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.error; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; +import org.onap.cli.fw.error.OnapCommandResultMapProcessingFailed; + +public class OnapCommandErrorTest { + @Test + public void oclipCommandResultMapProcessingFailedTest() { + OnapCommandResultMapProcessingFailed failed = new OnapCommandResultMapProcessingFailed("name", + new Exception("failed")); + assertEquals("0x3002::Failed to parse the result format of command name, failed", failed.getMessage()); + } + + @Test + public void oclipCommandHttpHeaderNotFoundTest() { + OnapCommandHttpHeaderNotFound failed = new OnapCommandHttpHeaderNotFound("name"); + assertEquals("0x3003::Http header name is not returned from the service", failed.getMessage()); + } + + @Test + public void oclipCommandHttpFailureTest1() { + OnapCommandHttpFailure failed = new OnapCommandHttpFailure("Failed"); + assertEquals("0x3001::Failed", failed.getMessage()); + + failed = new OnapCommandHttpFailure(new Exception("failed"), 201); + assertEquals("201::0x3001::failed", failed.getMessage()); + } + + @Test + public void oclipCommandHttpFailureTest2() { + OnapCommandHttpFailure failed = new OnapCommandHttpFailure("Failed", 203); + + assertEquals("203::0x3001::Failed", failed.getMessage()); + } + + @Test + public void oclipCommandLoginFailedTest1() { + OnapCommandLoginFailed failed = new OnapCommandLoginFailed(new Exception("Failed")); + + assertEquals("0x4001::Login failed, Failed", failed.getMessage()); + } + + @Test + public void oclipCommandLoginFailedTest2() { + OnapCommandLoginFailed failed = new OnapCommandLoginFailed("Failed", 201); + + assertEquals("201::0x4001::Login failed, Failed", failed.getMessage()); + } + + @Test + public void oclipCommandLogoutFailedTest() { + OnapCommandLogoutFailed failed = new OnapCommandLogoutFailed(new Exception("Failed")); + assertEquals("0x4002::Logout failed, Failed", failed.getMessage()); + + failed = new OnapCommandLogoutFailed(200); + assertEquals("200::0x4002::Logout failed", failed.getMessage()); + } + + @Test + public void oclipCommandServiceNotFoundTest() { + OnapCommandServiceNotFound failed = new OnapCommandServiceNotFound("Service"); + + assertEquals("0xd001::Service Service is not found in MSB", failed.getMessage()); + } + +} diff --git a/profiles/http/src/test/java/org/onap/cli/fw/http/schema/ValidateSchemaTest.java b/profiles/http/src/test/java/org/onap/cli/fw/http/schema/ValidateSchemaTest.java new file mode 100644 index 00000000..ddf30ba7 --- /dev/null +++ b/profiles/http/src/test/java/org/onap/cli/fw/http/schema/ValidateSchemaTest.java @@ -0,0 +1,39 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.schema; + +import static org.junit.Assert.assertTrue; + +import java.util.List; + +import org.junit.Test; +import org.onap.cli.fw.cmd.OnapCommand; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.schema.OnapCommandSchemaLoader; + +public class ValidateSchemaTest { + @Test + public void validateTest() throws OnapCommandException { + + OnapCommand cmd1 = new OnapCommand() { + @Override + protected void run() throws OnapCommandException {} + }; + List<String> errorList1 = OnapCommandSchemaLoader.loadSchema(cmd1, "schema-validate-http.yaml", true, true); + assertTrue(errorList1.size() > 0); + } +} diff --git a/profiles/http/src/test/java/org/onap/cli/fw/http/utils/OnapCommandUtilsTest.java b/profiles/http/src/test/java/org/onap/cli/fw/http/utils/OnapCommandUtilsTest.java new file mode 100644 index 00000000..12920515 --- /dev/null +++ b/profiles/http/src/test/java/org/onap/cli/fw/http/utils/OnapCommandUtilsTest.java @@ -0,0 +1,139 @@ +/* + * Copyright 2017 Huawei Technologies Co., Ltd. + * + * 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. + */ + +package org.onap.cli.fw.http.utils; + + + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; +import org.onap.cli.fw.cmd.OnapCommand; +import org.onap.cli.fw.error.OnapCommandException; +import org.onap.cli.fw.error.OnapCommandInvalidParameterType; +import org.onap.cli.fw.error.OnapCommandInvalidPrintDirection; +import org.onap.cli.fw.error.OnapCommandInvalidResultAttributeScope; +import org.onap.cli.fw.error.OnapCommandInvalidSchema; +import org.onap.cli.fw.error.OnapCommandInvalidSchemaVersion; +import org.onap.cli.fw.error.OnapCommandParameterNameConflict; +import org.onap.cli.fw.error.OnapCommandParameterOptionConflict; +import org.onap.cli.fw.error.OnapCommandSchemaNotFound; +import org.onap.cli.fw.http.cmd.OnapHttpCommand; +import org.onap.cli.fw.http.connect.HttpResult; +import org.onap.cli.fw.http.error.OnapCommandHttpHeaderNotFound; +import org.onap.cli.fw.http.error.OnapCommandHttpInvalidResponseBody; +import org.onap.cli.fw.http.schema.OnapCommandSchemaHttpLoader; +import org.onap.cli.fw.input.OnapCommandParameter; +import org.onap.cli.fw.schema.OnapCommandSchema; +import org.onap.cli.fw.schema.OnapCommandSchemaLoader; +import org.onap.cli.fw.utils.OnapCommandUtils; + +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +public class OnapCommandUtilsTest { + + @Test(expected = OnapCommandInvalidSchema.class) + public void oclipCommandUtilsInputStreamNullTest() throws OnapCommandException { + OnapCommandSchemaLoader.validateSchemaVersion("sample-test1-schema-http1.yaml", "1.0"); + } + + @Test + public void oclipCommandUtilsInputStreamNotNullTest() throws OnapCommandException { + Map<String, ?> map = OnapCommandSchemaLoader.validateSchemaVersion("sample-test1-schema-http.yaml", "1.0"); + assertTrue(map != null); + } + + @Test + public void loadHttpBasedSchemaTest() throws OnapCommandException { + OnapHttpCommand cmd = new OnapHttpCommandSample(); + cmd.setName("sample-create-http"); + try { + OnapCommandSchemaHttpLoader.loadHttpSchema(cmd, "sample-test-schema-http.yaml", true, true); + assertTrue(cmd.getSuccessStatusCodes().size() == 2); + } catch (OnapCommandParameterNameConflict | OnapCommandParameterOptionConflict + | OnapCommandInvalidParameterType | OnapCommandInvalidPrintDirection + | OnapCommandInvalidResultAttributeScope | OnapCommandSchemaNotFound | OnapCommandInvalidSchema + | OnapCommandInvalidSchemaVersion e) { + fail("Test should not have thrown this exception : " + e.getMessage()); + } + } + + + @Test + public void loadOnapCommandSchemaAuthRequiredTest() throws OnapCommandException { + OnapCommand cmd = new OnapCommand() { + + @Override + protected void run() throws OnapCommandException { + // TODO Auto-generated method stub + + } + }; + OnapCommandSchemaLoader.loadSchema(cmd, "sample-test-schema-auth-required.yaml", true, false); + assertTrue("sample-test".equals(cmd.getName())); + + Map<String, OnapCommandParameter> map = OnapCommandUtils.getInputMap(cmd.getParameters()); + assertTrue(map.size() == 7); + } + + @Test(expected = OnapCommandHttpHeaderNotFound.class) + public void populateOutputsTest() throws OnapCommandException { + HttpResult output = new HttpResult(); + output.setBody( + "{\"serviceName\":\"test\",\"version\":\"v1\",\"url\":\"/api/test/v1\",\"protocol\":\"REST\",\"visualRange\":\"1\",\"lb_policy\":\"hash\",\"nodes\":[{\"ip\":\"127.0.0.1\",\"port\":\"8012\",\"ttl\":0,\"nodeId\":\"test_127.0.0.1_8012\",\"expiration\":\"2017-02-10T05:33:25Z\",\"created_at\":\"2017-02-10T05:33:25Z\",\"updated_at\":\"2017-02-10T05:33:25Z\"}],\"status\":\"1\"}"); + Map<String, String> mapHead = new HashMap<>(); + mapHead.put("head1", "value1"); + output.setRespHeaders(mapHead); + output.setStatus(0); + + Map<String, String> params = new HashMap<>(); + params.put("head", "$h{head1}"); + params.put("body", "$b{$.serviceName}"); + params.put("key", "value"); + + Map<String, ArrayList<String>> input1 = OnapCommandHttpUtils.populateOutputs(params, output); + assertEquals("{head=[value1], body=[test], key=[value]}", input1.toString()); + + params.put("body", "$b{{$.serviceName}"); + try { + input1 = OnapCommandHttpUtils.populateOutputs(params, output); + } catch (OnapCommandHttpInvalidResponseBody e) { + assertEquals( + "0x3004::Http response body does not have json entry {$.serviceName, Missing property in path $['{$']", + e.getMessage()); + } + output.setBody("{}"); + input1 = OnapCommandHttpUtils.populateOutputs(params, output); + params.put("head", "$h{head2}"); + output.setBody("{\"test\"}"); + input1 = OnapCommandHttpUtils.populateOutputs(params, output); + } + + @OnapCommandSchema(schema = "sample-test-schema-http.yaml") + class OnapHttpCommandSample extends OnapHttpCommand { + + @Override + protected void run() throws OnapCommandException { + } + } +} diff --git a/profiles/http/src/test/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand b/profiles/http/src/test/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/profiles/http/src/test/resources/META-INF/services/org.onap.cli.fw.cmd.OnapCommand diff --git a/profiles/http/src/test/resources/open-cli-schema/sample-test1-schema-http.yaml b/profiles/http/src/test/resources/open-cli-schema/sample-test1-schema-http.yaml new file mode 100644 index 00000000..f162231f --- /dev/null +++ b/profiles/http/src/test/resources/open-cli-schema/sample-test1-schema-http.yaml @@ -0,0 +1,95 @@ +open_cli_schema_version: 1.0 +name: sample-test1 +description: Oclip sample command to test the command features + +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +parameters: + - name: bool-param + type: bool + description: Oclip boolean param, by default its always false. + short_option: b + long_option: bool + is_optional: true + default_value: false + - name: secure-param + type: string + description: Oclip secure param such as password + short_option: x + long_option: secure + is_secured: true + is_optional: false + default_Value: pass123# + - name: string-param + type: string + description: Oclip string param + long_option: string-param + short_option: c + is_optional: false + default_Value: test + - name: yaml-param + type: json + description: Oclip yaml file location param + long_option: yaml-param + short_option: y + is_optional: false + - name: json-param + type: json + description: Oclip json file location param + long_option: json-param + short_option: j + is_optional: false + - name: long-param + type: digit + description: Oclip long param + short_option: l + long_option: long-opt + is_optional: false + default_value: 10 + - name: url-param + type: url + description: Oclip url param + short_option: r + long_option: url + is_optional: false + default_value: http://localhost:8082/file.txt + - name: env-param + type: string + description: Oclip env param. + short_option: z + long_option: env + is_optional: false + default_value: ${ENV_VAR} + - name: positional-args + type: string + description: Oclip positional args, if no short option and no long option given for it + is_optional: false + default_value: http://localhost:8082/file.txt +http: + request: + uri: /vims + method: POST + body: '{"name":"${name}","vendor":"${vendor}","version":"${vim-version}","description":"${description}","type":"${type}","url":"${url}","userName":"${username}","password":"${password}","domain":"${domain}","tenant":"${tenant}"}' + headers: + success_codes: + - 201 + - 200 + result_map: + id: $b{$.vimId} + name: $b{$.name} + vendor: $b{$.vendor} + type: $b{$.type} + version: $b{$.version} + url: $b{$.url} + description: $b{$.description} + username: $b{$.userName} + password: $b{$.password} + domain: $b{$.domain} + tenant: $b{$.tenant} + create-time: $b{$.createTime} + sample_response: + body:'{"id":"string","name":"string","vendor":"string","version":"string","description":"string","type":"string","createTime":"string","url":"string","userName":"string","password":"string","domain":"string","tenant":"string"}'
\ No newline at end of file diff --git a/profiles/http/src/test/resources/open-cli-schema/testauth-login.yaml b/profiles/http/src/test/resources/open-cli-schema/testauth-login.yaml new file mode 100644 index 00000000..3e9211ef --- /dev/null +++ b/profiles/http/src/test/resources/open-cli-schema/testauth-login.yaml @@ -0,0 +1,28 @@ +open_cli_schema_version: 1.0 + +name: testauth-login + +description: basic login auth command + +info: + product: open-cli + service: test + type: auth + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +parameters: + - name: string-param + type: string + description: Oclip string param + long_option: string-param + short_option: c + is_optional: false + default_Value: test + +# followings are dummy simulator for http command +http: + request: + uri: / + method: GET + success_codes: + - 200 diff --git a/profiles/http/src/test/resources/open-cli-schema/testauth-logout.yaml b/profiles/http/src/test/resources/open-cli-schema/testauth-logout.yaml new file mode 100644 index 00000000..dfe33638 --- /dev/null +++ b/profiles/http/src/test/resources/open-cli-schema/testauth-logout.yaml @@ -0,0 +1,19 @@ +open_cli_schema_version: 1.0 + +name: testauth-logout + +description: basic logout auth command + +info: + product: open-cli + service: test + type: auth + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +# followings are dummy simulator for http command +http: + request: + uri: / + method: GET + success_codes: + - 200
\ No newline at end of file diff --git a/profiles/http/src/test/resources/open-cli.properties b/profiles/http/src/test/resources/open-cli.properties new file mode 100644 index 00000000..026b1f13 --- /dev/null +++ b/profiles/http/src/test/resources/open-cli.properties @@ -0,0 +1,31 @@ +cli.product_name=open-cli +cli.version=1.0 + +cli.discover_always=false + +#schema validation +cli.schema.top_level_params_list=open_cli_schema_version,name,description,parameters,results,http,info +cli.schema.top_level_mandatory_list=open_cli_schema_version + +cli.schema.info_params_list=product,service,type,author,ignore +cli.schema.info_params_mandatory_list=product,service + +cli.schema.input_params_list=name,description,type,short_option,long_option, is_optional,default_value,is_secured,is_include +cli.schema.input_params_mandatory_list=name,description,type + +cli.schema.result_params_list=name,description,scope,type,is_secured, default_value +cli.schema.result_params_mandatory_list=name, description, type, scope + +cli.schema.boolean_values=true,false +cli.command.type=cmd,auth,catalog + +# moco properties +cli.sample.gen.enable=false +cli.sample.gen.target=. + +# mrkanag Move this to db, once exteranl command registration is supported in place of discovery +cli.schema.type.supported=http + +#other properties to load (it should be hanled when plugins are made as externally register-able +#when command plugin management support is enabled in oclip +cli.plugins-prps=open-cli-http.properties
\ No newline at end of file diff --git a/profiles/http/src/test/resources/sample-test-schema-auth-required.yaml b/profiles/http/src/test/resources/sample-test-schema-auth-required.yaml new file mode 100644 index 00000000..bb919d9a --- /dev/null +++ b/profiles/http/src/test/resources/sample-test-schema-auth-required.yaml @@ -0,0 +1,16 @@ +open_cli_schema_version: 1.0 +name: sample-test +description: Oclip sample command to test the command features +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com +parameters: + - name: bool-param + type: bool + description: Oclip boolean param, by default its always false. + short_option: b + long_option: bool + is_optional: true + default_value: false
\ No newline at end of file diff --git a/profiles/http/src/test/resources/sample-test-schema-http.yaml b/profiles/http/src/test/resources/sample-test-schema-http.yaml new file mode 100644 index 00000000..4ae6e9e0 --- /dev/null +++ b/profiles/http/src/test/resources/sample-test-schema-http.yaml @@ -0,0 +1,92 @@ +open_cli_schema_version: 1.0 +name: sample-create-http +description: Register microservice into Onap +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com +parameters: + - name: service-name + description: Oclip service name + type: string + short_option: x + long_option: service-name + is_optional: false + - name: service-version + description: Oclip service version + type: string + short_option: y + long_option: service-version + is_optional: false + - name: service-url + description: Oclip service base url + type: url + short_option: r + long_option: service-url + is_optional: false + - name: status + description: Oclip service status + type: digit + short_option: z + long_option: service-status + is_optional: true + default_value: 1 + - name: node-ip + description: Oclip service running node IP + type: string + - name: node-port + description: Oclip service running node port + type: string + - name: create-or-update + description: Oclip service create or update + type: bool + default_value: true +results: + direction: portrait + attributes: + - name: name + description: Oclip service name + scope: short + type: string + - name: version + description: Oclip service version + scope: short + type: string + - name: url + description: Oclip service base url + scope: short + type: url + - name: status + description: Oclip service status + scope: short + type: digit + - name: nodes + description: Oclip service running nodes + scope: long + type: string + - name: location + description: Oclip service location + scope: long + type: url +http: + request: + uri: /services + method: POST + body: '{"serviceName":"${service-name}","version":"${service-version}","url":"${service-url}","protocol":"REST","visualRange":"1","lb_policy":"hash","nodes":[{"ip":"${node-ip}","port":"${node-port}","ttl":0}]}' + headers: + queries: + createOrUpdate: ${create-or-update} + success_codes: + - 201 + - 200 + result_map: + name: $b{$.serviceName} + version: $b{$.version} + url: $b{$.url} + status: $b{$.status} + nodes: $b{$.nodes[*].ip}:$b{$.nodes[*].port} + location: $h{Location} + + sample_response: + body: {"serviceName":"test","version":"v1","url":"/api/test/v1","protocol":"REST","visualRange":"1","lb_policy":"hash","nodes":[{"ip":"127.0.0.1","port":"8012","ttl":0,"nodeId":"test_127.0.0.1_8012","expiration":"2017-02-10T05:33:25Z","created_at":"2017-02-10T05:33:25Z","updated_at":"2017-02-10T05:33:25Z"}],"status":"1"}
\ No newline at end of file diff --git a/profiles/http/src/test/resources/sample-test-schema-no-auth-no-catalog.yaml b/profiles/http/src/test/resources/sample-test-schema-no-auth-no-catalog.yaml new file mode 100644 index 00000000..2629a2f9 --- /dev/null +++ b/profiles/http/src/test/resources/sample-test-schema-no-auth-no-catalog.yaml @@ -0,0 +1,26 @@ +open_cli_schema_version: 1.0 + +name: sample-cmd-no-auth-no-catalog + +description: sample + +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +http: + + service: + name: sample + version: v1 + auth: none + mode: direct + request: + uri: /test + method: GET + success_codes: + - 200 + result_map: + name: ${name} diff --git a/profiles/http/src/test/resources/sample-test-schema-no-auth-yes-catalog.yaml b/profiles/http/src/test/resources/sample-test-schema-no-auth-yes-catalog.yaml new file mode 100644 index 00000000..15b5bf0c --- /dev/null +++ b/profiles/http/src/test/resources/sample-test-schema-no-auth-yes-catalog.yaml @@ -0,0 +1,28 @@ +open_cli_schema_version: 1.0 + +name: sample-cmd-no-auth-no-catalog + +description: sample + + +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +http: + + service: + name: sample + version: v1 + auth: none + mode: catalog + + request: + uri: /test + method: GET + success_codes: + - 200 + result_map: + name: ${name} diff --git a/profiles/http/src/test/resources/sample-test-schema-swagger.yaml b/profiles/http/src/test/resources/sample-test-schema-swagger.yaml new file mode 100644 index 00000000..4108d4e6 --- /dev/null +++ b/profiles/http/src/test/resources/sample-test-schema-swagger.yaml @@ -0,0 +1,28 @@ +open_cli_schema_version: 1.0 +name: sample-test-swagger +description: Sample swagger command test. +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com +parameters: + - name: user + type: string + description: Oclip user + short_option: n + long_option: username + is_optional: false +results: + direction: portrait + attributes: + - name: name + description: Oclip user + scope: short + type: string +exec: + api: org.onap.common_services.auth.auth_service.client.api.DefaultApi + client: org.onap.common_services.auth.auth_service.client.invoker.ApiClient + entity: org.onap.common_services.auth.auth_service.client.model.User, username(userName), password, description + method: create + exception: org.onap.common_services.auth.auth_service.client.invoker.ApiException
\ No newline at end of file diff --git a/profiles/http/src/test/resources/sample-test-schema-yes-auth-no-catalog.yaml b/profiles/http/src/test/resources/sample-test-schema-yes-auth-no-catalog.yaml new file mode 100644 index 00000000..bb0ae46b --- /dev/null +++ b/profiles/http/src/test/resources/sample-test-schema-yes-auth-no-catalog.yaml @@ -0,0 +1,26 @@ +open_cli_schema_version: 1.0 + +name: sample-cmd-yes-auth-no-catalog + +description: sample + +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +http: + + service: + name: sample + version: v1 + auth: basic + mode: direct + request: + uri: /test + method: GET + success_codes: + - 200 + result_map: + name: ${name} diff --git a/profiles/http/src/test/resources/sample-test-schema-yes-auth-with-additional-params-no-catalog.yaml b/profiles/http/src/test/resources/sample-test-schema-yes-auth-with-additional-params-no-catalog.yaml new file mode 100644 index 00000000..a5a39f92 --- /dev/null +++ b/profiles/http/src/test/resources/sample-test-schema-yes-auth-with-additional-params-no-catalog.yaml @@ -0,0 +1,28 @@ +open_cli_schema_version: 1.0 + +name: sample-cmd-yes-auth-no-catalog-extra-params + +description: sample + + +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +http: + + service: + name: sample + version: v1 + auth: testauth + mode: catalog + + request: + uri: /test + method: GET + success_codes: + - 200 + result_map: + name: ${name} diff --git a/profiles/http/src/test/resources/sample-test-schema-yes-auth-yes-catalog.yaml b/profiles/http/src/test/resources/sample-test-schema-yes-auth-yes-catalog.yaml new file mode 100644 index 00000000..4efd4c51 --- /dev/null +++ b/profiles/http/src/test/resources/sample-test-schema-yes-auth-yes-catalog.yaml @@ -0,0 +1,28 @@ +open_cli_schema_version: 1.0 + +name: sample-cmd-no-auth-no-catalog + +description: sample + + +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +http: + + service: + name: sample + version: v1 + auth: basic + mode: catalog + + request: + uri: /test + method: GET + success_codes: + - 200 + result_map: + name: ${name} diff --git a/profiles/http/src/test/resources/schema-validate-http.yaml b/profiles/http/src/test/resources/schema-validate-http.yaml new file mode 100644 index 00000000..7bdafc56 --- /dev/null +++ b/profiles/http/src/test/resources/schema-validate-http.yaml @@ -0,0 +1,98 @@ +open_cli_schema_version: 1.0 +description: Register microservice into Onap +name: schema-validate +info: + product: open-cli + service: test + type: cmd + author: Kanagaraj Manickam kanagaraj.manickam@huawei.com + +parameters: + - name: service-name1 + description: Oclip service name + type: string + short_option: x + long_option: service-name + is_optional: false + - name: service-version + description: Oclip service version + type: string + short_option: x + long_option: service-version + is_optional: false + - name: service-url + description: Oclip service base url + type: url1 + short_option: u + long_option: service-url + is_optional: false1 + - name: status + description: Oclip service status + type: digit + short_option: z + long_option: service-version + is_optional: true + default_value: 1 + - name: node-ip + description: Oclip service running node IP + type: string + - name: node-port + description: Oclip service running node port + type: string + - name: create-or-update + description: Oclip service create or update + type: cfbcv + default_value: true +results: + direction: portrait + attributes: + - name: name + description: Oclip service name + scope: short + type: string + - name: version + description: Oclip service version + scope: short + type: string + - name: status + description: Oclip service base url + scope: short + type: url + - name: status + description: Oclip service status + scope: short1 + type: digit + - name: nodes + description: Oclip service running nodes + scope: long + type: string + - name: location + description: Oclip service location + scope: long + type: url +http: + service: + name: msb + version: v1 + type: direct + auth: none + request: + uri: /services + method: POST1 + body: '{"serviceName":"${service}","serviceName":"${service-name}","version":"${service-version}","url":"${service-url}","protocol":"REST","visualRange":"1","lb_policy":"hash","nodes":[{"ip":"${node-ip}","port":"${node-port}","ttl":0}]}' + headers: + queries: + createOrUpdate: ${create-or-update1} + success_codes: + - 201 + - 300 + result_map: + name: $b{$.serviceName} + version: $b{$.version} + url: $b{$.url} + status1: $b{$.status} + nodes: $b{$.nodes[*].ip}:$b{$.nodes[*].port} + location: $h{Location} + sample_response: + body: {"serviceName":"test","version":"v1","url":"/api/test/v1","protocol":"REST","visualRange":"1","lb_policy":"hash","nodes":[{"ip":"127.0.0.1","port":"8012","ttl":0,"nodeId":"test_127.0.0.1_8012","expiration":"2017-02-10T05:33:25Z","created_at":"2017-02-10T05:33:25Z","updated_at":"2017-02-10T05:33:25Z"}],"status":"1"} + |