Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Compiled source #
###################
*.com
*.class
*.dll
*.exe
*.o
*.so
*.pyc
.idea/*
venv/*
__pycache__/*

# Packages #
############
# it's better to unpack these files and commit the raw source
# git has its own built in compression methods
*.7z
*.dmg
*.gz
*.iso
*.jar
*.rar
*.tar
*.zip

# Logs and databases #
######################
*.log
*.sql
*.sqlite

# OS generated files #
######################
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
Desktop.in
23 changes: 17 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,20 @@ We need to calculate the angle between the hands on a clock face. For example in

### Acceptance Criteria:-

1) Code to perform the calculation
1) How will you deploy this solution (in code or as a todo list if time is limited). i.e. how and where will this run?
1) How will you manage any infrastructure needed?
1) Delivered as a feature branch in the repo fork
1) Bonus points for a working deployed solution in GCP that you can demo at the "sprint review" (ie interview)
1) Any DevOps/Cicd components that would support this feature in a production setting
1) Code to perform the calculation<br>
Code can found in the repo along with required tests and environment setup.
1) How will you deploy this solution (in code or as a todo list if time is limited). i.e. how and where will this run?<br>
To deploy this solution I have used GCP Cloud Functions. As our data is coming from sensors at low frequency and as the compute needed is pretty low, as far as I think there is no need of dedicated instance.
The deployed solution can be tested by hitting this url,<br>
https://us-central1-get-ride-1568029178700.cloudfunctions.net/cal_angle?time=23:00<br>
with appropiate time param<br>
Currently I have used the core computation code in a script and deployed the same, but for the purpose of maintenance, my repo can made into a GCP cloud repo which can be used as a backend to the service.

1) How will you manage any infrastructure needed?<br>
As the solution is deployed as GCP Cloud Function, scalibility is taken care by GCP. Also the cost is pretty low, as first 2 million requests are free of cost.
1) Delivered as a feature branch in the repo fork<br>
Already have raised a PR against the upstream branch
1) Bonus points for a working deployed solution in GCP that you can demo at the "sprint review" (ie interview)<br>
Solution is ready and can be tested by browser
1) Any DevOps/Cicd components that would support this feature in a production setting<br>
At the current scale, no other DeveOps/Cicd components are required
1 change: 1 addition & 0 deletions app.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
runtime: python37
3 changes: 3 additions & 0 deletions constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
DEGREES_PER_HOUR = 30
DEGREES_PER_MIN = 6

46 changes: 46 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from flask import Flask, jsonify
import datetime
from constants import DEGREES_PER_HOUR, DEGREES_PER_MIN

app = Flask(__name__)

@app.route('/cal_angle/<string:time>', methods=['GET'])
def return_angle(time):
"""
A function which takes time '03:00' as input and returns the clockwise angle between hands of clock as response
To calculate angle, the method used is as follows
Angle per hour = 30(360/12)
Angle per min = 6(360/60)
Angle covered by hour hand = 30 * hour
Angle covered by minute hand = 6 * minute
"""
if not check_valid_time(time):
return jsonify({'response': 'The format for time is not valid, format should be of type "03:00"'})
hour, minute = [int(i) for i in time.split(':')]
# Converting hour to range to 1-12
hour = (hour-12) if hour > 12 else hour
# Per hour rotation is 30 degrees
hour_hand_angle = hour * DEGREES_PER_HOUR if hour != 12 else 0
# Per minute rotation is 6 degrees
minute_hand_angle = minute * DEGREES_PER_MIN if minute != 60 else 0
# Calculating final angle
angle = abs(hour_hand_angle - minute_hand_angle)
# Return as response
return jsonify({'response': angle})


def check_valid_time(s):
"""
To check the validity of the passed argument to return_angle function
"""
try:
datetime.datetime.strptime(s, "%H:%M")
return True
except Exception:
return False



if __name__ == "__main__":
app.run(host='127.0.0.1', port=8000, debug=True)

1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Flask==1.1.2
Empty file added tests/__init__.py
Empty file.
35 changes: 35 additions & 0 deletions tests/main_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import unittest

from main import app, return_angle, check_valid_time

class TestClocks(unittest.TestCase):

def setUp(self):
self.app_context = app.app_context()
self.app_context.push()

def test_return_angle(self):
"""Test cases for return_angle function"""

response = return_angle("03:00").get_json()
expected_response = {'response': 90}

exception_response = return_angle("24:00").get_json()
expected_exception_response = {'response': 'The format for time is not valid, '
'format should be of type "03:00"'}

self.assertEqual(response['response'], expected_response['response'])
self.assertEqual(exception_response['response'], expected_exception_response['response'])

def test_check_valid_time(self):
"""Test case for check_valid_time function"""
valid_response = check_valid_time("04:00")
invalid_response = check_valid_time("24:00")

self.assertTrue(valid_response)
self.assertFalse(invalid_response)


if __name__ == "__main__":
unittest.main()