Skip to content

Commit

Permalink
First version with unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
HydrelioxGitHub committed Dec 11, 2016
1 parent e8fa749 commit 1063066
Show file tree
Hide file tree
Showing 10 changed files with 710 additions and 0 deletions.
154 changes: 154 additions & 0 deletions pyiss/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
from datetime import datetime
import requests
from voluptuous import Schema, Required, All, Any, Length, Range


class ISS:
"""
"""

API_URL = "http://api.open-notify.org/"
API_CURRENT_LOCATION = "iss-now.json"
API_PASS_TIMES = "iss-pass.json"
API_PEOPLE = "astros.json"

def __init__(self):
return

def people_in_space(self):
"""
:return: Return a dict with number of people in space right now and
their name and their craft
:rtype: dict
"""
data = requests.get(self.API_URL + self.API_PEOPLE)

if data.status_code is 200:
return data.json()
else:
raise Exception("Error server n {}".format(
data.status_code))

def current_location(self):
"""
:return: A dict with latitude and longitude of ISS
:rtype: dict
"""
data = requests.get(self.API_URL + self.API_CURRENT_LOCATION)

if data.status_code is 200:
return data.json()['iss_position']
else:
raise Exception("Error server n {}".format(
data.status_code))

def pass_times(self, latitude, longitude, altitude=None, number=None):
"""
:param latitude: latitude in degrees of location you want iss pass
above
:type latitude: float
:param longitude: longitude in degrees of location you want iss pass
above
:type longitude: float
:param altitude: altitude in meters of location you want iss pass
above, default is 100 when not given
:type altitude: float
:param number: number of next pass above the location, default is 5
if not given. Min is 1, max is 100
:type number: int
:return: a list of the next pass of the ISS with the risetime and
the duration
:rtype: list
"""

# Check input
schema = Schema({
Required('lat'): All(Any(int, float), Range(min=-80, max=80)),
Required('long'): All(Any(int, float), Range(min=-180, max=180)),
'alt': Any(None, All(Any(int, float), Range(min=0, max=10000))),
'number': Any(None, All(int, Range(min=1, max=100)))
})
schema({'lat' : latitude, 'long': longitude, 'alt' : altitude, 'number': number})

#Build request
payload = {'lat': latitude, 'lon': longitude}

if altitude is not None:
payload['alt'] = altitude

if number is not None:
payload['n'] = number

data = requests.get(self.API_URL + self.API_PASS_TIMES,
params=payload)

#Check error
if data.status_code is 200:
return data.json()['response']
else:
raise Exception("Error server n {}".format(
data.status_code))

def number_of_people_in_space(self):
"""
:return: The number of people in space right now
:rtype: int
"""
return self.people_in_space()['number']

def next_rise(self, latitude, longitude, altitude=None):
"""
:param latitude: latitude in degrees of location you want iss pass
above
:type latitude: float
:param longitude: longitude in degrees of location you want iss pass
above
:type longitude: float
:param altitude: altitude in meters of location you want iss pass
above, default is 100 when not given
:type altitude: float
:return: Return the next date when ISS will be over 10 degree above the
horizon
:rtype: datetime
"""
rise = self.pass_times(latitude, longitude, altitude,
2)
timestamp = rise[0]['risetime']

return datetime.fromtimestamp(timestamp)

def is_ISS_above(self, latitude, longitude, altitude=None):
"""
:param latitude: latitude in degrees of location you want iss pass
above
:type latitude: float
:param longitude: longitude in degrees of location you want iss pass
above
:type longitude: float
:param altitude: altitude in meters of location you want iss pass
above, default is 100 when not given
:type altitude: float
:return: True if the ISS is above the location, False if not
:rtype: bool
"""
test = self.pass_times(latitude, longitude, altitude, 2)
# 2 results where asked so if API return only 1, that mean ISS is
# above the location
return len(test) is 1


if __name__ == '__main__':
iss = ISS()
# print (type(iss.people_in_space()))
# print(iss.current_location())
# print (type(iss.pass_times(5, 8)))
#print(iss.pass_times(1,1))
# print (iss.number_of_people_in_space())
# print (iss.seconds_before_next_rise(-50.2322, 76.5668))
# print (iss.is_ISS_above(4,71,7 ))
print(iss.next_rise(2, 5, 6).timestamp())
Empty file added pyiss/tests/__init__.py
Empty file.
54 changes: 54 additions & 0 deletions pyiss/tests/test_current_location.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
from unittest import TestCase
from httmock import all_requests, HTTMock, response
import pyiss


class TestCurrent_location(TestCase):
def setUp(self):
"""
Instantiate the Http Request Mock, the ISS class call and the json response
"""

#Json response
self.json_current_location = {"timestamp": 1481410143, "message": "success", "iss_position": {"latitude": "6.8272", "longitude": "-160.2689"}}

#HTTP Mock
@all_requests
def correct_response(url, request):
headers = {'content-type': 'application/json',
'Set-Cookie': 'foo=bar;'}
return response(200, self.json_current_location, headers, None, 5,
request)
self.http_correct = correct_response

@all_requests
def wrong_response(url, request):
headers = {'content-type': 'application/json',
'Set-Cookie': 'foo=bar;'}
return response(403, self.json_current_location, headers, None, 5,
request)
self.http_wrong = wrong_response

self.iss = pyiss.ISS()

def test_current_location_json_return(self):
"""
Test that the function return the right dict answer
"""
with HTTMock(self.http_correct):
response = self.iss.current_location()
location = {"latitude": "6.8272", "longitude": "-160.2689"}
self.assertDictEqual(response, location)

def test_current_location_error_server(self):
"""
Test that the function raise an exception if the server response is not correct
"""
with HTTMock(self.http_wrong):
self.assertRaises(Exception, self.iss.current_location )
133 changes: 133 additions & 0 deletions pyiss/tests/test_is_ISS_above.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
from unittest import TestCase
from httmock import all_requests, HTTMock, response
import pyiss


class TestIs_ISS_above(TestCase):
def setUp(self):
"""
Instantiate the Http Request Mock, the ISS class call and the json response
"""

# Json response
self.json_is_ISS_above_false = {
"message": "success",
"request": {
"altitude": 100,
"datetime": 1481418788,
"latitude": 15.0,
"longitude": 20.0,
"passes": 5
},
"response": [
{
"duration": 348,
"risetime": 1481448840
},
{
"duration": 634,
"risetime": 1481454465
}
]
}

self.json_is_ISS_above_true = {
"message": "success",
"request": {
"altitude": 100,
"datetime": 1481418788,
"latitude": 15.0,
"longitude": 20.0,
"passes": 5
},
"response": [
{
"duration": 348,
"risetime": 1481448840
}
]
}

# HTTP Mock
@all_requests
def true_response(url, request):
headers = {'content-type': 'application/json',
'Set-Cookie': 'foo=bar;'}
return response(200, self.json_is_ISS_above_true, headers, None, 5,
request)

self.http_true = true_response

@all_requests
def false_response(url, request):
headers = {'content-type': 'application/json',
'Set-Cookie': 'foo=bar;'}
return response(200, self.json_is_ISS_above_false, headers, None,
5,
request)

self.http_false = false_response

@all_requests
def wrong_response(url, request):
headers = {'content-type': 'application/json',
'Set-Cookie': 'foo=bar;'}
return response(403, self.json_is_ISS_above, headers, None, 5,
request)

self.http_wrong = wrong_response

self.iss = pyiss.ISS()

def test_is_ISS_above_true(self):
"""
Test that json match a true answer
"""
with HTTMock(self.http_true):
response = self.iss.is_ISS_above(20, 15)

self.assertTrue(response)

def test_is_ISS_above_false(self):
"""
Test that json match a false answer
"""
with HTTMock(self.http_false):
response = self.iss.is_ISS_above(20, 15)

self.assertFalse(response)

def test_is_ISS_above_error_server(self):
"""
Test that the function raise an exception if the server response is not correct
"""
with HTTMock(self.http_wrong):
self.assertRaises(Exception, self.iss.is_ISS_above, 15, 20)

def test_is_ISS_above_input_bound(self):
"""
Test that input raise exception using voluptuous
Each set of data test a boundary
"""
with HTTMock(self.http_true):
data = [[-80.1, 1, 1], [80.1, 1, 1], [1, -180.1, 1],
[1, 180.1, 1], [1, 1, -1], [1, 1, 10000.1]]
for value in data:
self.assertRaises(Exception, self.iss.is_ISS_above, value[0],
value[1], value[2])

data = [[-80, 1, 1], [80, 1, 1], [1, -180, 1],
[1, 180, 1], [1, 1, 0], [1, 1, 10000]]
for value in data:
self.assertTrue(self.iss.is_ISS_above(value[0],
value[1], value[2]))
Loading

0 comments on commit 1063066

Please sign in to comment.