Repository: incubator-stratos Updated Branches: refs/heads/stratos-651-cli-test-suite [created] cb3a22e8c
added integration test suite Project: http://git-wip-us.apache.org/repos/asf/incubator-stratos/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-stratos/commit/cb3a22e8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-stratos/tree/cb3a22e8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-stratos/diff/cb3a22e8 Branch: refs/heads/stratos-651-cli-test-suite Commit: cb3a22e8c0a07027e6a90dd6923cce08122a7c15 Parents: 6892d21 Author: Chris Snow <[email protected]> Authored: Sun May 11 05:48:50 2014 +0000 Committer: Chris Snow <[email protected]> Committed: Sun May 11 05:48:50 2014 +0000 ---------------------------------------------------------------------- components/org.apache.stratos.cli/README.md | 7 + components/org.apache.stratos.cli/pom.xml | 118 ++++++++++- .../src/test/python/.gitignore | 20 ++ .../src/test/python/__files/body_cookie.json | 1 + .../test/python/__files/body_tenant_create.json | 1 + .../python/__files/body_tenant_deactivate.json | 1 + .../test/python/__files/body_tenant_list.json | 1 + .../src/test/python/__init__.py | 19 ++ .../src/test/python/mappings/cookie.json | 18 ++ .../src/test/python/mappings/tenant-create.json | 19 ++ .../test/python/mappings/tenant-deactivate.json | 16 ++ .../src/test/python/mappings/tenant-list.json | 16 ++ .../src/test/python/test_common.py | 99 ++++++++++ .../src/test/python/test_interactive.py | 195 +++++++++++++++++++ .../src/test/python/test_noninteractive.py | 87 +++++++++ .../src/test/python/wiremock.py | 106 ++++++++++ 16 files changed, 723 insertions(+), 1 deletion(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/README.md ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/README.md b/components/org.apache.stratos.cli/README.md new file mode 100644 index 0000000..f03d1b3 --- /dev/null +++ b/components/org.apache.stratos.cli/README.md @@ -0,0 +1,7 @@ +### CLI Integration Tests + +Run CLI integration tests with: + +```mvn -P cli-test integration-test``` + +You will need python ane pexpect installed. http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/pom.xml ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/pom.xml b/components/org.apache.stratos.cli/pom.xml index 18d01d2..62b9e97 100644 --- a/components/org.apache.stratos.cli/pom.xml +++ b/components/org.apache.stratos.cli/pom.xml @@ -34,6 +34,7 @@ <properties> <slf4j.version>1.7.6</slf4j.version> + <wiremock.version>1.46</wiremock.version> </properties> <dependencies> @@ -119,7 +120,7 @@ <descriptors> <descriptor>src/main/assembly/src.xml</descriptor> </descriptors> - <appendAssemblyId>false</appendAssemblyId> + <appendAssemblyId>false</appendAssemblyId> </configuration> <executions> <execution> @@ -131,7 +132,122 @@ </execution> </executions> </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-dependency-plugin</artifactId> + <version>2.7</version> + <executions> + <execution> + <id>copy</id> + <phase>pre-integration-test</phase> + <goals> + <goal>copy</goal> + </goals> + <configuration> + <artifactItems> + <!-- Copy the CLI --> + <artifactItem> + <groupId>${project.groupId}</groupId> + <artifactId>${project.artifactId}</artifactId> + <version>${project.version}</version> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${maven.output.build.path}</outputDirectory> + </artifactItem> + </artifactItems> + <artifactItems> + <artifactItem> + <groupId>com.github.tomakehurst</groupId> + <artifactId>wiremock</artifactId> + <version>${wiremock.version}</version> + <classifier>standalone</classifier> + <type>jar</type> + <overWrite>true</overWrite> + <outputDirectory>${maven.output.build.path}</outputDirectory> + </artifactItem> + </artifactItems> + </configuration> + </execution> + </executions> + </plugin> </plugins> </build> + <profiles> + <!-- Integration testing the CLI --> + <profile> + <id>cli-test</id> + <build> + <plugins> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>exec-maven-plugin</artifactId> + <version>1.3</version> + <executions> + <execution> + <configuration> + <executable>python</executable> + <workingDirectory>src/test/python</workingDirectory> + <!-- tests common to both interactive and non-interactive use cases --> + <arguments> + <argument>test_common.py</argument> + </arguments> + <environmentVariables> + <PYTHONPATH>../../main/python:$PYTHONPATH</PYTHONPATH> + <CLI_JAR>${project.build.directory}/${project.build.finalName}.jar</CLI_JAR> + <WIREMOCK_JAR>${project.build.directory}/dependency/wiremock-${wiremock.version}-standalone.jar</WIREMOCK_JAR> + </environmentVariables> + </configuration> + <id>python-test-common</id> + <phase>integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + </execution> + <execution> + <configuration> + <executable>python</executable> + <workingDirectory>src/test/python</workingDirectory> + <!-- interactive use cases --> + <arguments> + <argument>test_interactive.py</argument> + </arguments> + <environmentVariables> + <PYTHONPATH>../../main/python:$PYTHONPATH</PYTHONPATH> + <CLI_JAR>${project.build.directory}/${project.build.finalName}.jar</CLI_JAR> + <WIREMOCK_JAR>${project.build.directory}/dependency/wiremock-${wiremock.version}-standalone.jar</WIREMOCK_JAR> + </environmentVariables> + </configuration> + <id>python-test-interactive</id> + <phase>integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + </execution> + <execution> + <configuration> + <executable>python</executable> + <workingDirectory>src/test/python</workingDirectory> + <!-- non-interactive use cases --> + <arguments> + <argument>test_noninteractive.py</argument> + </arguments> + <environmentVariables> + <PYTHONPATH>../../main/python:$PYTHONPATH</PYTHONPATH> + <CLI_JAR>${project.build.directory}/${project.build.finalName}.jar</CLI_JAR> + <WIREMOCK_JAR>${project.build.directory}/dependency/wiremock-${wiremock.version}-standalone.jar</WIREMOCK_JAR> + </environmentVariables> + </configuration> + <id>python-test-noninteractive</id> + <phase>integration-test</phase> + <goals> + <goal>exec</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + </profile> + </profiles> </project> http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/.gitignore ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/.gitignore b/components/org.apache.stratos.cli/src/test/python/.gitignore new file mode 100644 index 0000000..9ef57cb --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/.gitignore @@ -0,0 +1,20 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +*.pyc http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/__files/body_cookie.json ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/__files/body_cookie.json b/components/org.apache.stratos.cli/src/test/python/__files/body_cookie.json new file mode 100644 index 0000000..33924ae --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/__files/body_cookie.json @@ -0,0 +1 @@ +{"Success":{ "sessionId": "BD425955D0F64102B3C67B39D0C946F0"}} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_create.json ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_create.json b/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_create.json new file mode 100644 index 0000000..8ab5eb1 --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_create.json @@ -0,0 +1 @@ +{"stratosAdminResponse":{"message":"Successfully added new tenant with domain tenant.com"}} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_deactivate.json ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_deactivate.json b/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_deactivate.json new file mode 100644 index 0000000..d323d70 --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_deactivate.json @@ -0,0 +1 @@ +{"stratosAdminResponse":{"message":"Successfully deactivated tenant tenant.com"}} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_list.json ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_list.json b/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_list.json new file mode 100644 index 0000000..5952ccb --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/__files/body_tenant_list.json @@ -0,0 +1 @@ +{"tenantInfoBean":[{"active":true,"createdDate":"2014-05-09T05:40:11Z","email":"[email protected]","tenantDomain":"tenant.com","tenantId":1}]} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/__init__.py ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/__init__.py b/components/org.apache.stratos.cli/src/test/python/__init__.py new file mode 100644 index 0000000..314303d --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/__init__.py @@ -0,0 +1,19 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/mappings/cookie.json ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/mappings/cookie.json b/components/org.apache.stratos.cli/src/test/python/mappings/cookie.json new file mode 100644 index 0000000..31336ba --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/mappings/cookie.json @@ -0,0 +1,18 @@ +{ + "request" : { + "url" : "/stratos/admin/cookie", + "method" : "GET" + }, + "response" : { + "status" : 200, + "bodyFileName" : "body_cookie.json", + "headers" : { + "Set-Cookie" : "JSESSIONID=BD425955D0F64102B3C67B39D0C946F0; Path=/stratos/; Secure; HttpOnly", + "Date" : "Fri, 09 May 2014 05:40:05 GMT", + "WWW-Authenticate" : "Basic", + "Content-Type" : "application/json", + "Content-Length" : "62", + "Server" : "WSO2 Carbon Server" + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/mappings/tenant-create.json ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/mappings/tenant-create.json b/components/org.apache.stratos.cli/src/test/python/mappings/tenant-create.json new file mode 100644 index 0000000..3f3ce05 --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/mappings/tenant-create.json @@ -0,0 +1,19 @@ +{ + "request" : { + "url" : "/stratos/admin/tenant", + "method" : "POST", + "bodyPatterns" : [ { + "equalTo" : "{\"admin\":\"tenant1\",\"firstname\":\"John\",\"lastname\":\"Doe\",\"adminPassword\":\"secret\",\"tenantDomain\":\"tenant.com\",\"email\":\"[email protected]\",\"active\":false,\"tenantId\":0}" + } ] + }, + "response" : { + "status" : 200, + "bodyFileName" : "body_tenant_create.json", + "headers" : { + "Date" : "Fri, 09 May 2014 05:40:12 GMT", + "Content-Type" : "application/json", + "Transfer-Encoding" : "chunked", + "Server" : "WSO2 Carbon Server" + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/mappings/tenant-deactivate.json ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/mappings/tenant-deactivate.json b/components/org.apache.stratos.cli/src/test/python/mappings/tenant-deactivate.json new file mode 100644 index 0000000..4691f6b --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/mappings/tenant-deactivate.json @@ -0,0 +1,16 @@ +{ + "request" : { + "url" : "/stratos/admin/tenant/deactivate/tenant.com", + "method" : "POST" + }, + "response" : { + "status" : 200, + "bodyFileName" : "body_tenant_deactivate.json", + "headers" : { + "Date" : "Sat, 10 May 2014 10:07:14 GMT", + "Content-Type" : "application/json", + "Transfer-Encoding" : "chunked", + "Server" : "WSO2 Carbon Server" + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/mappings/tenant-list.json ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/mappings/tenant-list.json b/components/org.apache.stratos.cli/src/test/python/mappings/tenant-list.json new file mode 100644 index 0000000..36588cd --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/mappings/tenant-list.json @@ -0,0 +1,16 @@ +{ + "request" : { + "url" : "/stratos/admin/tenant/list", + "method" : "GET" + }, + "response" : { + "status" : 200, + "bodyFileName" : "body_tenant_list.json", + "headers" : { + "Date" : "Fri, 09 May 2014 05:45:15 GMT", + "Content-Type" : "application/json", + "Transfer-Encoding" : "chunked", + "Server" : "WSO2 Carbon Server" + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/test_common.py ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/test_common.py b/components/org.apache.stratos.cli/src/test/python/test_common.py new file mode 100755 index 0000000..407a178 --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/test_common.py @@ -0,0 +1,99 @@ +#!/usr/bin/env python +# ---------------------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +import unittest +import pexpect +import os +import signal +import subprocess +import urllib +import urllib2 +import json +from wiremock import WiremockClient + +class TestCommon(unittest.TestCase): + + cli_cmd = "java -jar " + os.environ["CLI_JAR"] + + @classmethod + def setUpClass(cls): + TestCommon.wiremock = WiremockClient() + TestCommon.wiremock.start() + + @classmethod + def tearDownClass(cls): + TestCommon.wiremock.stop() + + def setUp(self): + # unset these environment variables + if 'STRATOS_USERNAME' in os.environ: del os.environ["STRATOS_USERNAME"] # unset env var + if 'STRATOS_PASSWORD' in os.environ: del os.environ["STRATOS_PASSWORD"] # unset env var + + def tearDown(self): + TestCommon.wiremock.reset() + + def test_error_if_stratos_url_not_set(self): + if 'STRATOS_URL' in os.environ: del os.environ["STRATOS_URL"] # unset env var + child = pexpect.spawn(TestCommon.cli_cmd) + child.expect ('Could not find required "STRATOS_URL" variable in your environment.') + child.expect (pexpect.EOF) + + def test_error_if_port_not_provided_in_stratos_url(self): + os.environ["STRATOS_URL"] = "https://localhost" # no port + child = pexpect.spawn(TestCommon.cli_cmd) + child.expect ('The "STRATOS_URL" variable in your environment is not a valid URL. You have provided "https://localhost"') + child.expect ('Please provide the Stratos Controller URL as follows') + child.expect ('https://<host>:<port>') + child.expect (pexpect.EOF) + + def test_error_if_context_path_is_provided_in_stratos_url(self): + os.environ["STRATOS_URL"] = "https://localhost:9443/somecontext/" # context path + child = pexpect.spawn(TestCommon.cli_cmd) + child.expect ('The "STRATOS_URL" variable in your environment is not a valid URL. You have provided "https://localhost:9443/somecontext/"') + child.expect ('Please provide the Stratos Controller URL as follows') + child.expect ('https://<host>:<port>') + child.expect (pexpect.EOF) + + def test_error_if_non_https_scheme_is_provided_in_stratos_url(self): + os.environ["STRATOS_URL"] = "http://localhost:9443" # http scheme + child = pexpect.spawn(TestCommon.cli_cmd) + child.expect ('The "STRATOS_URL" variable in your environment is not a valid URL. You have provided "http://localhost:9443"') + child.expect ('Please provide the Stratos Controller URL as follows') + child.expect ('https://<host>:<port>') + child.expect (pexpect.EOF) + + def test_error_if_invalid_format_is_given_for_stratos_url(self): + # we need to ensure the url is valid and not that it just has 2 colons and 3 or less slashes! + os.environ["STRATOS_URL"] = ":://" + child = pexpect.spawn(TestCommon.cli_cmd) + child.expect ('The "STRATOS_URL" variable in your environment is not a valid URL. You have provided ":://"') + child.expect ('Please provide the Stratos Controller URL as follows') + child.expect ('https://<host>:<port>') + child.expect (pexpect.EOF) + +if __name__ == '__main__': + try: + unittest.main() + # handle CTRL-C + except KeyboardInterrupt: + # shut down wiremock + TestCommon.wiremock.stop() + exit(1) http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/test_interactive.py ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/test_interactive.py b/components/org.apache.stratos.cli/src/test/python/test_interactive.py new file mode 100755 index 0000000..cf1bb3e --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/test_interactive.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python +# ---------------------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +import unittest +import pexpect +import os +import signal +import subprocess +import urllib +import urllib2 +import json +from wiremock import WiremockClient + +class TestInteractive(unittest.TestCase): + + cli_cmd = "java -jar " + os.environ["CLI_JAR"] + + @classmethod + def setUpClass(cls): + TestInteractive.wiremock = WiremockClient() + TestInteractive.wiremock.start() + + @classmethod + def tearDownClass(cls): + TestInteractive.wiremock.stop() + + def setUp(self): + # set default STRATOS_URL + os.environ["STRATOS_URL"] = "https://localhost:9443" + # ensure other env vars not set + if 'STRATOS_USERNAME' in os.environ: del os.environ["STRATOS_USERNAME"] # unset env var + if 'STRATOS_PASSWORD' in os.environ: del os.environ["STRATOS_PASSWORD"] # unset env var + + def tearDown(self): + TestInteractive.wiremock.reset() + + def test_interactive_mode_username_and_password_sent_to_server(self): + child = pexpect.spawn(TestInteractive.cli_cmd) + child.expect ('Username: ') + child.sendline ('1234') + child.expect ('Password: ') + child.sendline ('abcd') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "1234:abcd") + + def test_interactive_mode_standard_username_parameter_provided(self): + child = pexpect.spawn(TestInteractive.cli_cmd + " -username xxx", timeout=10) + child.expect ('Username: xxx') + child.expect ('Password: ') + child.sendline ('zzz') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "xxx:zzz") + + def test_interactive_mode_short_username_parameter_provided(self): + child = pexpect.spawn(TestInteractive.cli_cmd + " -u xxx", timeout=10) + child.expect ('Username: xxx') + child.expect ('Password: ') + child.sendline ('zzz') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "xxx:zzz") + + def test_interactive_mode_long_username_parameter_provided(self): + child = pexpect.spawn(TestInteractive.cli_cmd + " --username xxx", timeout=10) + child.expect ('Username: xxx') + child.expect ('Password: ') + child.sendline ('zzz') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "xxx:zzz") + + def test_interactive_mode_username_env_var_provided(self): + os.environ["STRATOS_USERNAME"] = "yyy" + # ensure other env vars not set + child = pexpect.spawn(TestInteractive.cli_cmd, timeout=10) + child.expect ('Username: yyy') + child.expect ('Password: ') + child.sendline ('zzz') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "yyy:zzz") + + def test_interactive_mode_standard_password_parameter_provided(self): + child = pexpect.spawn(TestInteractive.cli_cmd + " -password xxx", timeout=10) + child.expect ('Username: ') + child.sendline ('1234') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "1234:xxx") + + def test_interactive_mode_list_tenants(self): + child = pexpect.spawn(TestInteractive.cli_cmd, timeout=10) + child.expect ('Username: ') + child.sendline ('1234') + child.expect ('\r\nPassword: ') # TODO - why do we need \r\n? + child.sendline ('zzz') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('list-tenants') + child.expect ('Available Tenants') + # in the table below, + characters have been replaced with . + # because the + is a special regex character + child.expect ('.------------.-----------.-----------------.--------.----------------------.') + child.expect ('| Domain | Tenant ID | Email | State | Created Date |') + child.expect ('.------------.-----------.-----------------.--------.----------------------.') + child.expect ('| tenant.com | 1 | [email protected] | Active | 2014-05-09T05:40:11Z |') + child.expect ('.------------.-----------.-----------------.--------.----------------------.') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "1234:zzz") + self.assertEqual(self.wiremock.get_cookie_req_count(), 1) + self.assertEqual(self.wiremock.get_tenant_list_req_count(), 1) + + def test_interactive_mode_create_tenant(self): + child = pexpect.spawn(TestInteractive.cli_cmd, timeout=10) + child.expect ('Username: ') + child.sendline ('1234') + child.expect ('\r\nPassword: ') # TODO - why do we need \r\n? + child.sendline ('zzz') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('create-tenant --username tenant1 --password secret --first-name John --last-name Doe --domain-name tenant.com --email [email protected]') + child.expect ('Tenant added successfully') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "1234:zzz") + self.assertEqual(self.wiremock.get_cookie_req_count(), 1) + self.assertEqual(self.wiremock.tenant_create_req_count(), 1) + + def test_interactive_mode_deactivate_tenant(self): + child = pexpect.spawn(TestInteractive.cli_cmd, timeout=10) + child.expect ('Username: ') + child.sendline ('1234') + child.expect ('\r\nPassword: ') # TODO - why do we need \r\n? + child.sendline ('zzz') + child.expect ('Successfully Authenticated.') + child.expect ('stratos> ') + child.sendline ('deactivate-tenant tenant.com') + child.expect ('You have succesfully deactivate tenant.com tenant') + child.sendline ('exit') + child.expect (pexpect.EOF) + # CLI sends GET request to mock server url /stratos/admin/coookie + self.assertEqual(self.wiremock.get_cookie_auth_header(), "1234:zzz") + self.assertEqual(self.wiremock.get_cookie_req_count(), 1) + self.assertEqual(self.wiremock.tenant_deactivate_req_count(), 1) + + +if __name__ == '__main__': + try: + unittest.main() + # handle CTRL-C + except KeyboardInterrupt: + # shut down wiremock + TestInteractive.wiremock.stop() + exit(1) http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/test_noninteractive.py ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/test_noninteractive.py b/components/org.apache.stratos.cli/src/test/python/test_noninteractive.py new file mode 100755 index 0000000..8379165 --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/test_noninteractive.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +# ---------------------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +import unittest +import pexpect +import os +import signal +import subprocess +import urllib +import urllib2 +import json +from wiremock import WiremockClient + +class TestNonInteractive(unittest.TestCase): + + cli_cmd = "java -jar " + os.environ["CLI_JAR"] + + @classmethod + def setUpClass(cls): + TestNonInteractive.wiremock = WiremockClient() + TestNonInteractive.wiremock.start() + + @classmethod + def tearDownClass(cls): + TestNonInteractive.wiremock.stop() + + def setUp(self): + # set default STRATOS_URL + os.environ["STRATOS_URL"] = "https://localhost:9443" + # ensure other env vars not set + if 'STRATOS_USERNAME' in os.environ: del os.environ["STRATOS_USERNAME"] # unset env var + if 'STRATOS_PASSWORD' in os.environ: del os.environ["STRATOS_PASSWORD"] # unset env var + + def tearDown(self): + TestNonInteractive.wiremock.reset() + + def test_noninteractive_mode_list_tenants(self): + child = pexpect.spawn(TestNonInteractive.cli_cmd + " -username admin -password admin list-tenants", timeout=10) + child.expect ('Available Tenants') + # in the table below, + characters have been replaced with . + # because the + is a special regex character + child.expect ('.------------.-----------.-----------------.--------.----------------------.') + child.expect ('| Domain | Tenant ID | Email | State | Created Date |') + child.expect ('.------------.-----------.-----------------.--------.----------------------.') + child.expect ('| tenant.com | 1 | [email protected] | Active | 2014-05-09T05:40:11Z |') + child.expect ('.------------.-----------.-----------------.--------.----------------------.') + child.sendline ('exit') + child.expect (pexpect.EOF) + # verify /stratos/admin/tenant/list was called + self.assertEqual(self.wiremock.get_tenant_list_req_count(), 1) + + def test_noninteractive_mode_create_tenant(self): + command = "create-tenant -u tenant1 -p secret -f John -l Doe -d tenant.com -e [email protected]" + child = pexpect.spawn(TestNonInteractive.cli_cmd + " -u adminuser -p adminpass " + command, timeout=10) + child.expect ('Username: adminuser') + child.expect ('Tenant added successfully') + child.sendline ('exit') + child.expect (pexpect.EOF) + # verify POST /stratos/admin/tenant/list was called + self.assertEqual(self.wiremock.tenant_create_req_count(), 1) + +if __name__ == '__main__': + try: + unittest.main() + # handle CTRL-C + except KeyboardInterrupt: + # shut down wiremock + TestNonInteractive.wiremock.stop() + exit(1) http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/cb3a22e8/components/org.apache.stratos.cli/src/test/python/wiremock.py ---------------------------------------------------------------------- diff --git a/components/org.apache.stratos.cli/src/test/python/wiremock.py b/components/org.apache.stratos.cli/src/test/python/wiremock.py new file mode 100755 index 0000000..aa81e7f --- /dev/null +++ b/components/org.apache.stratos.cli/src/test/python/wiremock.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python +# ---------------------------------------------------------------------------- +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you 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. +# + +import os +import signal +import subprocess +import urllib +import urllib2 +import json +import base64 + +class WiremockClient(): + + reset_url = 'http://localhost:8080/__admin/mappings/reset' + + find_url = 'http://localhost:8080/__admin/requests/find' + + count_url = 'http://localhost:8080/__admin/requests/count' + + cookies_req_json = '{ "method": "GET", "url": "/stratos/admin/cookie" }' + + tenant_list_req_json = '{ "method": "GET", "url": "/stratos/admin/tenant/list" }' + + tenant_create_req_json = '{ "method": "POST", "url": "/stratos/admin/tenant" }' + + tenant_deactivate_req_json = '{ "method": "POST", "url": "/stratos/admin/tenant/deactivate/tenant.com" }' + + wiremock = "java -jar " + os.environ["WIREMOCK_JAR"] + " --https-port 9443" + + def start(self): + # execute wiremock and return handle so it can be torn down + # Note: the requests that wiremock handles and the response it will return + # for a request can be found in the 'mapping' directory + self.wiremock_process = subprocess.Popen(self.wiremock.split(), + stdout=subprocess.PIPE, + preexec_fn=os.setsid) + + def __del__(self): + self.stop() + + def stop(self): + # kill wiremock process + os.killpg(self.wiremock_process.pid, signal.SIGTERM) + + def reset(self): + # ignore errors when resetting + try: + req = urllib2.Request(WiremockClient.reset_url, data="") + urllib2.urlopen(req) + except: + pass + + def get_cookie_requests_and_responses(self): + # send GET request to mock server url /stratos/admin/coookie + req = urllib2.Request(WiremockClient.find_url) + req.add_header('Content-Type', 'application/json') + response = urllib2.urlopen(req, WiremockClient.cookies_req_json) + return json.load(response) + + def get_cookie_auth_header(self): + data = self.get_cookie_requests_and_responses() + encoded_username_password = data["requests"][0]["headers"]["Authorization"] + return base64.b64decode(encoded_username_password.split(" ")[1]) + + # lots of repeated code below - TODO refactor to method + def get_cookie_req_count(self): + req = urllib2.Request(WiremockClient.count_url) + req.add_header('Content-Type', 'application/json') + response = urllib2.urlopen(req, WiremockClient.cookies_req_json) + return json.load(response)["count"] + + def get_tenant_list_req_count(self): + req = urllib2.Request(WiremockClient.count_url) + req.add_header('Content-Type', 'application/json') + response = urllib2.urlopen(req, WiremockClient.tenant_list_req_json) + return json.load(response)["count"] + + def tenant_create_req_count(self): + req = urllib2.Request(WiremockClient.count_url) + req.add_header('Content-Type', 'application/json') + response = urllib2.urlopen(req, WiremockClient.tenant_create_req_json) + return json.load(response)["count"] + + def tenant_deactivate_req_count(self): + req = urllib2.Request(WiremockClient.count_url) + req.add_header('Content-Type', 'application/json') + response = urllib2.urlopen(req, WiremockClient.tenant_deactivate_req_json) + return json.load(response)["count"]
