IGNITE-13903: Add tox, docker-compose and travis integration

This closes #1
diff --git a/.asf.yaml b/.asf.yaml
new file mode 100644
index 0000000..2fca9c0
--- /dev/null
+++ b/.asf.yaml
@@ -0,0 +1,34 @@
+# 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.
+
+github:
+  description: "Apache Ignite Python Thin Client"
+  homepage: https://ignite.apache.org/
+  labels:
+    - ignite
+    - python
+  features:
+    wiki: false
+    issues: false
+    projects: false
+  enabled_merge_buttons:
+    squash:  true
+    merge:   false
+    rebase:  false
+notifications:
+  commits:      commits@ignite.apache.org
+  issues:       notifications@ignite.apache.org
+  pullrequests: notifications@ignite.apache.org
+  jira_options: link label worklog
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..d9268c3
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+.eggs
+.pytest_cache
+.tox
+pyignite.egg-info
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..230a9f1
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,34 @@
+# 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.
+
+sudo: required
+services:
+  - docker
+
+env:
+  COMPOSE_VERSION: 1.27.4
+
+before_install:
+ - curl -L https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose
+ - chmod +x docker-compose
+ - sudo mv docker-compose /usr/local/bin
+
+language: python
+python:
+  - "3.6"
+  - "3.7"
+  - "3.8"
+install: pip install tox-travis
+script: tox
\ No newline at end of file
diff --git a/README.md b/README.md
index 22732ce..26b9a6a 100644
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 
 ## Prerequisites
 
-- Python 3.4 or above (3.6 is tested),
+- Python 3.4 or above (3.6, 3.7 and 3.8 are tested),
 - Access to Apache Ignite node, local or remote. The current thin client
   version was tested on Apache Ignite 2.7.0 (binary client protocol 1.2.0).
 
@@ -19,8 +19,7 @@
 If you want to run tests, examples or build documentation, clone
 the whole repository:
 ```
-$ git clone git@github.com:apache/ignite.git
-$ cd ignite/modules/platforms/python
+$ git clone git@github.com:apache/ignite-python-thin-client.git
 $ pip install -e .
 ```
 
@@ -64,12 +63,32 @@
 installed, and Apache Ignite node is running on localhost:10800.
 
 ## Testing
-Run
+*NB!* All tests require Apache Ignite node running on localhost:10800. For the convenience, `docker-compose.yml` is present.
+So installing `docker` and `docker-compose` is recommended. Also, it is recommended installing `pyignite` in development
+mode. You can do that using following command:
 ```
-$ cd ignite/modules/platforms/python
-$ python setup.py pytest
+$ pip install -e .
+```
+### Run without ssl
+```
+$ docker-compose down && docker-compose up -d ignite
+$ pytest
+```
+### Run with examples
+```
+$ docker-compose down && docker-compose up -d ignite
+$ pytest --examples
+```
+### Run with ssl and not encrypted key
+```
+$ docker-compose down && docker-compose up -d ignite
+$ pytest --use-ssl=True --ssl-certfile=./tests/config/ssl/client_full.pem
+```
+### Run with ssl and password-protected key
+```
+$ docker-compose down && docker-compose up -d ignite
+$ pytest --use-ssl=True --ssl-certfile=./tests/config/ssl/client_with_pass_full.pem --ssl-keyfile-password=654321
 ```
 
-*NB!* All tests require Apache Ignite node running on localhost:10800.
 If you need to change the connection parameters, see the documentation on
 [testing](https://apache-ignite-binary-protocol-client.readthedocs.io/en/latest/readme.html#testing).
diff --git a/docker-compose.yml b/docker-compose.yml
new file mode 100644
index 0000000..2517d25
--- /dev/null
+++ b/docker-compose.yml
@@ -0,0 +1,34 @@
+# 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.
+
+services:
+  ignite:
+    image: apacheignite/ignite:latest
+    ports:
+      - 10800:10800
+    restart: always
+    network_mode: host
+
+  ignite-ssl:
+    image: apacheignite/ignite:latest
+    ports:
+      - 10800:10800
+    restart: always
+    network_mode: host
+    volumes:
+    - ./tests/config:/config
+    environment:
+      CONFIG_URI: /config/ssl.xml
+      PYTHON_TEST_CONFIG_PATH: /config
diff --git a/tests/config/ssl.xml b/tests/config/ssl.xml
index d9d406f..8d74cbb 100644
--- a/tests/config/ssl.xml
+++ b/tests/config/ssl.xml
@@ -32,12 +32,10 @@
     </bean>
   
     <bean id="test.cfg" class="org.apache.ignite.configuration.IgniteConfiguration">
-        <property name="localHost" value="127.0.0.1"/>
         <property name="connectorConfiguration"><null/></property>
 
         <property name="clientConnectorConfiguration">
             <bean class="org.apache.ignite.configuration.ClientConnectorConfiguration">
-                <property name="host" value="127.0.0.1"/>
                 <property name="portRange" value="10"/>
                 <property name="sslEnabled" value="true"/>
                 <property name="useIgniteSslContextFactory" value="false"/>
diff --git a/tests/config/ssl/README.txt b/tests/config/ssl/README.txt
index eca07ea..da169fa 100644
--- a/tests/config/ssl/README.txt
+++ b/tests/config/ssl/README.txt
@@ -1,3 +1,3 @@
 These files generated using script
-`$IGNITE_SRC/modules/platforms/cpp/thin-client-test/config/ssl/generate_certificates.sh`
+`./tests/config/ssl/generate_certificates.sh`
 To update them just run script and move files to this folder.
\ No newline at end of file
diff --git a/tests/config/ssl/generate_certificates.sh b/tests/config/ssl/generate_certificates.sh
new file mode 100755
index 0000000..e4f41e2
--- /dev/null
+++ b/tests/config/ssl/generate_certificates.sh
@@ -0,0 +1,127 @@
+#!/bin/bash
+#
+# 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.
+#
+
+OSSL=$(command -v openssl11)
+
+if [ -z "$OSSL" ]
+then
+    OSSL=$(command -v openssl)
+fi
+
+echo "Using following openssl: $OSSL"
+
+function generate_ca {
+    CA_KEY="$1.key"
+    CA_CRT="$1.crt"
+    OU="$2"
+
+    # Generating CA private key and self-signed certificate
+    $OSSL req \
+        -newkey rsa:2048 -nodes -sha256 -keyout $CA_KEY \
+        -subj "/C=US/ST=Massachusetts/L=Wakefield/CN=ignite.apache.org/O=The Apache Software Foundation/OU=$OU/emailAddress=dev@ignite.apache.org" \
+        -x509 -days 3650 -out $CA_CRT
+}
+
+function generate_client_key_and_crt {
+    CA_KEY="$1.key"
+    CA_CRT="$1.crt"
+    CA_SRL="$1.srl"
+    CLIENT_KEY="$2.key"
+    CLIENT_CSR="$2.scr"
+    CLIENT_CRT="$2.crt"
+    OU="$3"
+
+    # Generating client private key and certificate signature request to be used for certificate signing
+    $OSSL req \
+        -newkey rsa:2048 -nodes -sha256 -keyout $CLIENT_KEY \
+        -subj "/C=US/ST=Massachusetts/L=Wakefield/CN=ignite.apache.org/O=The Apache Software Foundation/OU=$OU/emailAddress=dev@ignite.apache.org" \
+        -out $CLIENT_CSR
+
+    # Signing client cerificate
+    $OSSL x509 -req \
+        -in $CLIENT_CSR -CA $CA_CRT -CAkey $CA_KEY -CAcreateserial \
+        -days 3650 -sha256 -out $CLIENT_CRT
+
+    # Cleaning up.
+    rm -f $CLIENT_CSR
+
+    # Protecting key with the password if required
+    if [ "$4" == "1" ]; then
+      openssl rsa -aes256 -in $CLIENT_KEY -passout pass:654321 -out $CLIENT_KEY
+    fi
+}
+
+function generate_jks {
+    CA_CRT="$1.crt"
+    CA_JKS="$1.jks"
+    SERVER_KEY="$2.key"
+    SERVER_CRT="$2.crt"
+    SERVER_PEM="$2.pem"
+    SERVER_P12="$2.pkcs12"
+    SERVER_JKS="$2.jks"
+
+    rm -f $CA_JKS $SERVER_JKS
+
+    cat $SERVER_KEY $SERVER_CRT > $SERVER_PEM
+
+    $OSSL pkcs12 -export -passout pass:123456 -out $SERVER_P12 -in $SERVER_PEM
+    
+    keytool -import -v -trustcacerts \
+        -file $CA_CRT -alias certificateauthority -noprompt \
+        -keystore $CA_JKS -deststorepass 123456
+
+    keytool -v -importkeystore \
+        -srckeystore $SERVER_P12 -srcstoretype PKCS12 -srcstorepass 123456 \
+        -destkeystore $SERVER_JKS -deststoretype JKS -deststorepass 123456
+
+    rm -f $SERVER_P12 $SERVER_PEM
+}
+
+CA='ca'
+CLIENT='client'
+CLIENT_WITH_PASS='client_with_pass'
+SERVER='server'
+CA_UNKNOWN='ca_unknown'
+CLIENT_UNKNOWN='client_unknown'
+
+generate_ca $CA 'Apache Ignite CA'
+generate_client_key_and_crt $CA $CLIENT 'Apache Ignite Client Test'
+generate_client_key_and_crt $CA $CLIENT_WITH_PASS 'Apache Ignite Client Test' 1
+generate_client_key_and_crt $CA $SERVER 'Apache Ignite Server Test'
+
+# We won't sign up any other certs so we do not need CA key or srl
+rm -f "$CA.key" "$CA.srl"
+
+generate_jks $CA $SERVER
+
+generate_ca $CA_UNKNOWN 'Unknown CA'
+generate_client_key_and_crt $CA_UNKNOWN $CLIENT_UNKNOWN 'Unknown Client'
+
+# We do not need this CA anymore
+rm -f $CA_UNKNOWN*
+
+# Re-naming everything as needed
+cat $CLIENT.key $CLIENT.crt > "$CLIENT"_full.pem
+cat $CLIENT_WITH_PASS.key $CLIENT_WITH_PASS.crt > "$CLIENT_WITH_PASS"_full.pem
+cat $CLIENT_UNKNOWN.key $CLIENT_UNKNOWN.crt > $CLIENT_UNKNOWN.pem
+mv $CA.jks trust.jks
+mv $CA.crt ca.pem
+
+rm -f $CLIENT.crt $CLIENT.key $CLIENT_WITH_PASS.key $CLIENT_WITH_PASS.crt $CLIENT_UNKNOWN.key $CLIENT_UNKNOWN.crt $SERVER_KEY $SERVER_CRT
+
+
diff --git a/tests/conftest.py b/tests/conftest.py
index f7e2e1f..8ebd5b8 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -98,6 +98,18 @@
     cache_destroy(client, cache_name)
 
 
+@pytest.fixture
+def examples(request):
+    return request.config.getoption("--examples")
+
+
+@pytest.fixture(autouse=True)
+def run_examples(request, examples):
+    if request.node.get_closest_marker('examples'):
+        if not examples:
+            pytest.skip('skipped examples: --examples is not passed')
+
+
 def pytest_addoption(parser):
     parser.addoption(
         '--ignite-host',
@@ -225,3 +237,9 @@
             if type(param) is not list:
                 param = [param]
             metafunc.parametrize(param_name, param, scope='session')
+
+
+def pytest_configure(config):
+    config.addinivalue_line(
+        "markers", "examples: mark test to run only if --examples are set"
+    )
diff --git a/tests/test_examples.py b/tests/test_examples.py
index 4665d8c..046eb6d 100644
--- a/tests/test_examples.py
+++ b/tests/test_examples.py
@@ -39,13 +39,7 @@
     ]).returncode
 
 
-@pytest.mark.skipif(
-    condition=not pytest.config.option.examples,
-    reason=(
-        'If you wish to test examples, invoke pytest with '
-        '`--examples` option.'
-    ),
-)
+@pytest.mark.examples
 def test_examples():
     for script in glob.glob1('../examples', '*.py'):
         if script not in SKIP_LIST:
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..6e70234
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,85 @@
+# 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.
+
+[tox]
+skipsdist = True
+envlist = py{36,37,38}-{no-ssl,ssl,ssl-password}-docker
+
+[travis]
+python =
+  3.6: py36-{no-ssl,ssl,ssl-password}-docker
+  3.7: py37-{no-ssl,ssl,ssl-password}-docker
+  3.8: py38-{no-ssl,ssl,ssl-password}-docker
+
+[testenv]
+passenv = TEAMCITY_VERSION
+envdir = {homedir}/.virtualenvs/pyignite-{envname}
+deps =
+    -r ./requirements/install.txt
+    -r ./requirements/tests.txt
+recreate = True
+usedevelop = True
+allowlist_externals = docker-compose
+commands =
+    pytest {env:PYTESTARGS:} {posargs}
+
+[no-ssl]
+setenv:
+    PYTEST_ADDOPTS = --examples
+
+[ssl]
+setenv:
+    PYTEST_ADDOPTS = --examples --use-ssl=True --ssl-certfile={toxinidir}/tests/config/ssl/client_full.pem
+
+[ssl-password]
+setenv:
+    PYTEST_ADDOPTS = --examples --use-ssl=True --ssl-certfile={toxinidir}/tests/config/ssl/client_with_pass_full.pem --ssl-keyfile-password=654321
+
+[docker]
+commands_pre =
+    docker-compose down
+    docker-compose up -d ignite
+commands_post =
+    docker-compose down
+
+[docker-ssl]
+commands_pre =
+    docker-compose down
+    docker-compose up -d ignite-ssl
+commands_post = {[docker]commands_post}
+
+[testenv:py{36,37,38}-no-ssl]
+setenv: {[no-ssl]setenv}
+
+[testenv:py{36,37,38}-no-ssl-docker]
+commands_pre = {[docker]commands_pre}
+setenv: {[no-ssl]setenv}
+commands_post = {[docker]commands_post}
+
+[testenv:py{36,37,38}-ssl]
+setenv: {[ssl]setenv}
+
+[testenv:py{36,37,38}-ssl-docker]
+commands_pre = {[docker-ssl]commands_pre}
+setenv: {[ssl]setenv}
+commands_post = {[docker]commands_post}
+
+[testenv:py{36,37,38}-ssl-password]
+setenv: {[ssl-password]setenv}
+
+[testenv:py{36,37,38}-ssl-password-docker]
+commands_pre = {[docker-ssl]commands_pre}
+setenv: {[ssl-password]setenv}
+commands_post = {[docker]commands_post}