From e86f30eab818aa8375be57e77db58ced0873e766 Mon Sep 17 00:00:00 2001 From: thisisshi Date: Mon, 21 Jan 2019 19:52:36 -0500 Subject: [PATCH] add tests, fix copy --- tests/__init__.py | 0 tests/common.py | 19 ++++++ .../test_tesla_get_auth_with_email.yml | 36 ++++++++++ .../test_tesla_get_vehicle_details_by_id | 65 +++++++++++++++++++ .../cassettes/test_tesla_get_vehicles.yml | 29 +++++++++ tests/test_tesla.py | 53 +++++++++++++++ tests/test_tesla_vehicles.py | 23 +++++++ yauta/tesla.py | 13 +++- 8 files changed, 237 insertions(+), 1 deletion(-) create mode 100644 tests/__init__.py create mode 100644 tests/common.py create mode 100644 tests/fixtures/cassettes/test_tesla_get_auth_with_email.yml create mode 100644 tests/fixtures/cassettes/test_tesla_get_vehicle_details_by_id create mode 100644 tests/fixtures/cassettes/test_tesla_get_vehicles.yml diff --git a/tests/__init__.py b/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/common.py b/tests/common.py new file mode 100644 index 0000000..ef3de8b --- /dev/null +++ b/tests/common.py @@ -0,0 +1,19 @@ +import vcr + +yauta_vcr = vcr.VCR( + serializer='yaml', + cassette_library_dir='tests/fixtures/cassettes', + record_mode='once', + match_on=['uri', 'method'], + filter_headers=[('Authorization', 'TESLA_ACCESS_TOKEN')], + filter_post_data_parameters=[ + ('client_id', 'TESLA_CLIENT_ID'), + ('client_secret', 'TESLA_CLIENT_SECRET'), + ('email', 'TESLA_EMAIL'), + ('password', 'TESLA_PASSWORD'), + ('pin', 'TESLA_PIN') + ] +) + + +__all__ = [yauta_vcr] diff --git a/tests/fixtures/cassettes/test_tesla_get_auth_with_email.yml b/tests/fixtures/cassettes/test_tesla_get_auth_with_email.yml new file mode 100644 index 0000000..20ccf9c --- /dev/null +++ b/tests/fixtures/cassettes/test_tesla_get_auth_with_email.yml @@ -0,0 +1,36 @@ +interactions: +- request: + body: grant_type=password&client_id=TESLA_CLIENT_ID&client_secret=TESLA_CLIENT_SECRET&email=TESLA_EMAIL&password=TESLA_PASSWORD + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Connection: [keep-alive] + Content-Length: ['220'] + Content-Type: [application/x-www-form-urlencoded] + User-Agent: [python-requests/2.21.0] + method: POST + uri: https://owner-api.teslamotors.com/oauth/token?grant_type=password + response: + body: + string: !!binary | + H4sIAAAAAAAAAzzNMW4EIQxA0btQb2FjDPZeZmSMUVaRkhUzRaJV7h6UIu0v/nslc4/zPK7P9/hI + 98QVVXSG+8DW0QOaj+g8zQSYabiq0ayM5EQUOtVzhkoximH2dEt/q+P6fsb+9bAVa9f4ej5WnMdj + KyQiAHBLK+Zub/96qWUK1G4aglIkaBqH5FnVTFsxwTYMoio3V2nOzOqubXToAH07vsKuGIdd6Y5c + BLForj+/AAAA//8DAFIqhPzpAAAA + headers: + Cache-Control: [no-store] + Connection: [keep-alive] + Content-Encoding: [gzip] + Content-Type: [application/json; charset=utf-8] + Date: ['Mon, 21 Jan 2019 23:55:26 GMT'] + ETag: [W/"0182cdce05699ddc0027d3b5f763fb57"] + Pragma: [no-cache] + Server: [nginx] + Transfer-Encoding: [chunked] + X-Content-Type-Options: [nosniff] + X-Frame-Options: [SAMEORIGIN, SAMEORIGIN] + X-Request-Id: [37c7d5bb-e5be-4fc7-b537-a3340c74d6f4] + X-Runtime: ['0.398629'] + X-XSS-Protection: [1; mode=block] + status: {code: 200, message: OK} +version: 1 diff --git a/tests/fixtures/cassettes/test_tesla_get_vehicle_details_by_id b/tests/fixtures/cassettes/test_tesla_get_vehicle_details_by_id new file mode 100644 index 0000000..ed34276 --- /dev/null +++ b/tests/fixtures/cassettes/test_tesla_get_vehicle_details_by_id @@ -0,0 +1,65 @@ +interactions: +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Authorization: [TESLA_ACCESS_TOKEN] + Connection: [keep-alive] + User-Agent: [python-requests/2.21.0] + method: GET + uri: https://owner-api.teslamotors.com/api/1/vehicles/xxxxxxxx/vehicle_data + response: + body: + string: !!binary | + H4sIAAAAAAAAAwIAAAD//3xXXXOrOBL9K1M8s14w4K83x7lO7q1kJhUnk5qd2VIpIBtVMGIFODeT + 2v++pyWBSRzviw1qqdUfp083754WdaXKWniLd09m3mIyT+LxeBrMJ/MgSIJk7HttLTQjWTKJZ3Hi + eweRy7QQZm0SzIPJNJnSsiy9hZf88SP6Fn5bzn+sg2QaR4nne5msq4K/sZLvcZF3lau6wbKqGqlK + lqpM1FheXoaJf3t5E/l3F5sL//7br0v/4iGa+t8voyf/fh1d+Zvo7sK/vL+59i9/Hz/5T9H8wl/e + rQN/9dvjxr9YRRf+6jqY+nerKPDXq+jOX19FoX91s773r2/wdH2Ln+/0dPMAVbf3eFrf4tj9Jrr2 + N0uc2Dys8LMKYn/zGK38h2i19B+egsB/uMXP4wO2PN3jafmIp+XddeQv13j912rz4N9+x9Pq8jaA + d6kqlPYWZVsUvteoF1HCyT+9cRRPtyIMx9v5VKTPMXbOk3kyjuNMPCeJ4NvQ+7fv1Q1vKFaqLGQp + sEmWDHk4yBSrW17UAksZo7idpIwu54UoM66ZKPlzIZCoRrc4wivJDkLXiDty53vPPH2pBW+YMbCz + 9uMqa6sMxmSMN92GNOd6J5gz8h1qmkboN5ZDFcBCyp2NnaQQB1F4i+mU7rSbNS93cAYBGUUwxelM + W61F2TAt/tMKwGQRz87J2J7//CC3zh6PWp+dYlEKvXtjPMsoHEkwCnq9hdzLhtUq9RbzL1btPSFS + 2xnZH2B7An3ylaRucM1A3V4WorbXo3IERzTGYTRC4TgDhxs0BfzzhkrphmVKIcAVJcuF2B030oI3 + aQ5MXMpalDu+g5JeP+n0FkO/G0WuMZeID+o042nT8oK5fOBgp0izKuc1lazFtr0fq7JQzXH/MW8Q + qVeBWhioOKiigXlw0amV5a7DE1mfqrIUKQUBcjyzDh4EZzj4VxsEUSrLAy9kZl6oSAAY9gleYTQb + JZHvbTlknanPcBnhPaPlw9YKDAk89tH+IGzeqvPGmCR/NqdD+56XlB1rEfmOcMvDsbZP5Kg15LeR + xKA27idbDFGnvEyFqXiXzz7DfQhVW6JKTTpKZEyUqt3lNkfgAVPE3R11moushbqjoYBeBoN7/V9s + ObWV7CbdW7Chs8NBkSTYv6+8RZjEszCcRtNkFsbgTC2r/tr+urYmBPRh7XgFBGLdt8z0mQkoYv8F + klC4qIJzxHXCWo7PStUh2EY+00iVZo3YVyDlpjHhGJvK2nLwNLi7RXngVZY1YGB2eotoFGIFHNAi + EgB1Jqn/UfIHhAl5Z+XH1a1WoMVM4L/+RLI4A5gONR57RA06RB/48lwhtoAUeZFJnCdrjNUEGX7g + snCGj2fkGqjuw2qY0Kpqm4GLY+KzitfEPmcipMVeIQUutDC60ao49imHWi13+Ze2mW7lDpP9xuDh + onE3Rck6iJ/Izp8yl54qPK5SLvdSa1CwNQFZdgbXe6rPc2k4j/JXWSFQzwWHaqvTqQRcDc6OYN1V + wE7N1HZQKqgTnLIFGRLPoQPIps3AEiC+2SyJMQ55hSp3bvUf0+loPImDGBVTYi8u+PJIJ1MpNmFK + q9uKOgwRC1DcS/+fXseOr7sa1HxsAXUuATs3O9iCqitBit2sdIYREJBdK7uCQ+Tfzfs4ZrlqUY2G + Gl02SOA6BrU91payoVlpL/+Za1hDckylDZHll0LTE2kLDa44eG8asj1IFSOgttXHs2vIziUZhncj + M+C+lSCLd0xoqKY0FVWDsfggdzbKbuqBqW52MbvQiOEDVsqXgUQzhC2V6DEu0M/oytQugX+3ssdo + XUS0ZmnRzAhO9rihhtliHDTTfB868ROVI4FwN8B6dyio4imXmB4ANgCQS1zd4nKQ24CjSFS0mUy1 + amtGV/c6UfFKy7+7NiJApxqFZn1ELLdEhyYw3oV1oirwYvFgCnpQxQgBEHhctf64vfmx8WmlSK+Z + wr2rAqQE++2wa9p2Bz2FwayP2K/KTNt1WzJzHgTe8ML0U4fOXOoMsldjEmHq61HkHBh87zUXos/Z + nSzNezjzBjDpB+vP8zq1jorrF1s+7BDhfkQie4PNA9mbmZEwf2QY8EqDCfc9MCjjDmH6+EXgjYNw + Nopno3A8Cn/JJvP5fEsfcJZOu3LoahfEm4GL6M9OE46Nc7UX+Gp5YSUy94zqsTehS5kW/XmiQmYa + 0xONY4LYFcaj59pHYq/0hRJg1exFJvmRFF07OekjtBkRxYAjt9JyWD0kMatMZbDVdIp4NpuMgkk0 + JWKEJTWB9WzUKut3Zf12Npixp8f8cPH0YtpIjUttm1dOPGK+sYgYxE9UNciGZS04xlCvSDFeTOn7 + oxstPEKLYU2GkQYfL7bc3r1PY2T3NeU2Vfg2mJm2TS2+kP8DAAD//wLrBAmC+img+h1JHahTUwAU + AnXPQYUuolqCZw5gzgWlDGh3BJqfYDkHmoaVgIVWXn45KBHizhLAVnwqzA/QEhwiBHJAHtCXiOiH + laQoYwm1tbUAAAAA//8DAFOQ9M3LEAAA + headers: + Cache-Control: ['max-age=0, private, must-revalidate'] + Connection: [keep-alive] + Content-Encoding: [gzip] + Content-Type: [application/json; charset=utf-8] + Date: ['Tue, 22 Jan 2019 00:36:15 GMT'] + ETag: [W/"6ba7c530630a75a5656e3c7b64f47abc"] + Server: [nginx] + Transfer-Encoding: [chunked] + X-Content-Type-Options: [nosniff] + X-Frame-Options: [SAMEORIGIN, SAMEORIGIN] + X-Request-Id: [fdca1f74-5600-4def-a89b-770d1cb46678] + X-Runtime: ['0.804233'] + X-TXID: [71491ff51dea744f913e1ead4e372072] + X-XSS-Protection: [1; mode=block] + status: {code: 200, message: OK} +version: 1 diff --git a/tests/fixtures/cassettes/test_tesla_get_vehicles.yml b/tests/fixtures/cassettes/test_tesla_get_vehicles.yml new file mode 100644 index 0000000..1129abb --- /dev/null +++ b/tests/fixtures/cassettes/test_tesla_get_vehicles.yml @@ -0,0 +1,29 @@ +interactions: +- request: + body: null + headers: + Accept: ['*/*'] + Accept-Encoding: ['gzip, deflate'] + Authorization: [TESLA_ACCESS_TOKEN] + Connection: [keep-alive] + User-Agent: [python-requests/2.21.0] + method: GET + uri: https://owner-api.teslamotors.com/api/1/vehicles + response: + body: {string: '{"response":[{"id":1234,"vehicle_id":1234,"vin":"1234","display_name":"Ghost","option_codes":"AD15,MDL3,PBSB,RENA,BT37,ID3W,RF3G,S3PB,DRLH,DV2W,W39B,APF0,COUS,BC3B,CH07,PC30,FC3P,FG31,GLFR,HL31,HM31,IL31,LTPB,MR31,FM3B,RS3H,SA3P,STCP,SC04,SU3C,T3CA,TW00,TM00,UT3P,WR00,AU3P,APH3,AF00,ZCST,MI00,CDM0","color":null,"tokens":["b74979f90e209a12","1c9886ecbbf0836e"],"state":"online","in_service":false,"id_s":"1234","calendar_enabled":true,"api_version":6,"backseat_token":null,"backseat_token_updated_at":null}],"count":1}'} + headers: + Cache-Control: ['max-age=0, private, must-revalidate'] + Connection: [keep-alive] + Content-Length: ['563'] + Content-Type: [application/json; charset=utf-8] + Date: ['Tue, 22 Jan 2019 00:11:05 GMT'] + ETag: [W/"80301a5d122271a36d6e18a95d133d22"] + Server: [nginx] + X-Content-Type-Options: [nosniff] + X-Frame-Options: [SAMEORIGIN, SAMEORIGIN] + X-Request-Id: [fa8b6a3f-a1b6-4b92-b228-4a1133761998] + X-Runtime: ['0.187736'] + X-TXID: [239d6a8d0fff87b08a90c008b800abd5] + X-XSS-Protection: [1; mode=block] + status: {code: 200, message: OK} +version: 1 diff --git a/tests/test_tesla.py b/tests/test_tesla.py index 2071d06..382d434 100644 --- a/tests/test_tesla.py +++ b/tests/test_tesla.py @@ -1 +1,54 @@ +import os + from unittest import TestCase + +from yauta.tesla import TeslaAPI +from yauta.vehicle import TeslaVehicle + +from .common import yauta_vcr + + +class TeslaTest(TestCase): + @yauta_vcr.use_cassette('test_tesla_get_auth_with_email.yml') + def test_get_tesla_auth(self): + email = os.environ.get('TESLA_EMAIL') + password = os.environ.get('TESLA_PASSWORD') + client_id = os.environ.get('TESLA_CLIENT_ID') + client_secret = os.environ.get('TESLA_CLIENT_SECRET') + t = TeslaAPI( + email=email, + password=password, + client_id=client_id, + client_secret=client_secret + ) + + t.initialize() + self.assertTrue(t.headers['Authorization']) + + def test_initialize_tesla_with_access_token(self): + t = TeslaAPI( + email='xxxxxxx', + password='xxxxxxx', + client_id='xxxxxxxx', + client_secret='xxxxxxxx' + ) + t.initialize('XXXXXXXXXXX') + self.assertTrue(t.access_token) + self.assertEqual(t.access_token, 'XXXXXXXXXXX') + self.assertTrue(t.headers['Authorization']) + self.assertEqual(t.headers['Authorization'], 'Bearer XXXXXXXXXXX') + + @yauta_vcr.use_cassette('test_tesla_get_vehicles.yml') + def test_get_tesla_vehicles(self): + access_token = os.environ.get('TESLA_ACCESS_TOKEN', 'xxxxxxxx') + t = TeslaAPI( + email='xxxxxxx', + password='xxxxxxx', + client_id='xxxxxxxx', + client_secret='xxxxxxxx' + ) + t.initialize(access_token=access_token) + vehicles = t.get_vehicles() + self.assertEqual(len(vehicles), 1) + + self.assertTrue(isinstance(vehicles[0], TeslaVehicle)) diff --git a/tests/test_tesla_vehicles.py b/tests/test_tesla_vehicles.py index 2071d06..e425df5 100644 --- a/tests/test_tesla_vehicles.py +++ b/tests/test_tesla_vehicles.py @@ -1 +1,24 @@ +import os from unittest import TestCase + +from yauta.tesla import TeslaAPI +from yauta.vehicle import TeslaVehicle + +from .common import yauta_vcr + + +class TeslaVehicleTest(TestCase): + @yauta_vcr.use_cassette('test_tesla_get_vehicle_details_by_id') + def test_get_tesla_vehicle_details_by_id(self): + vehicle_id = os.environ.get('TESLA_VEHICLE_ID', 'xxxxxxxx') + access_token = os.environ.get('TESLA_ACCESS_TOKEN', 'xxxxxxxx') + t = TeslaAPI( + email='xxxxxxxx', + password='xxxxxxxx', + client_id='xxxxxxxx', + client_secret='xxxxxxxx' + ) + t.initialize(access_token=access_token) + vehicle = TeslaVehicle(vehicle_id, t) + data = vehicle.get_vehicle_data() + self.assertTrue(data) diff --git a/yauta/tesla.py b/yauta/tesla.py index 20e19c1..46550ae 100644 --- a/yauta/tesla.py +++ b/yauta/tesla.py @@ -25,6 +25,16 @@ def __init__(self, client_id, client_secret, email, password): ) self.mount('https://', HTTPAdapter(max_retries=retries)) + def __copy__(self): + return type(self)( + self.prefix_url, + self.client_id, + self.client_secret, + self.email, + self.password, + self.headers + ) + def initialize(self, access_token=None): try: self.headers.update(self._get_access_token(access_token)) @@ -59,6 +69,7 @@ def _get_access_token(self, access_token=None): resp = self.post(oauth_url, data=payload) resp.raise_for_status() access_token = resp.json()['access_token'] + self.access_token = access_token return {'Authorization': 'Bearer %s' % access_token} def get_vehicles(self): @@ -73,5 +84,5 @@ def get_vehicles(self): """ vehicles_url = '/api/1/vehicles' vehicles = self.get(vehicles_url).json()['response'] - vehicle_list = [TeslaVehicle(v['id'], self) for v in vehicles] + vehicle_list = [TeslaVehicle(v['id'], self) for v in vehicles] # noqa return vehicle_list