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
Binary file added Architecture1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from alpine:latest

RUN apk add --no-cache python3-dev \
&& pip3 install --upgrade pip

WORKDIR /app
COPY . /app

RUN pip3 --no-cache-dir install -r requirements.txt

RUN pylint main.py
RUN pytest test_cases.py

EXPOSE 5000

ENTRYPOINT ["python3"]
CMD ["main.py"]
69 changes: 16 additions & 53 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,58 +1,21 @@
# Clock Exercise
Function clock_angle() accepts 2 parameters as json

We are interested in running code of course, but even more in your development process and understanding of Software Development Lifecycle Management.
Input:
Sample JSON:
{
"hrs":3,
"mins":0
}
Accessing Function:
1. curl -X POST "https://us-central1-ind-coe.cloudfunctions.net/clock_repository" -H "Content-Type:application/json" -d '{"hrs":10,"mins":20}'

**Fork this repo, then get to work.** Remember that this is a DevOps team, so make sure your repo reflects that. Spend however much time you feel is reasonable. It doesn’t matter if the project is ‘done’, nothing ever is. **When you’re ready push your changes back to Github and put in a pull request back to the base repo.**
2. https://us-central1-ind-coe.cloudfunctions.net/clock_repository?hrs=10&mins=10

This exercise is not meant to take an excessive amount of time. It is an opportunity for you to demonstrate your skills without the stress of an interview. If you start to run out of time, it’s ok to leave an imaginary team member a TODO list that details all the things you didn’t quite have time to do in order for your solution to go to prod.

If you need clarification, or would like to request additional information, pease reach out to the interviewer by email.
Output:
return string
e.g. 'Angle -> 90.0'

## Scenario

You have just joined a DevOps team. This team lives by DevOps principles and you want to let them know you mean business! This particular team is developing a product that is deployed in a Google Cloud Project.

This sprint, the team has been asked to work on a new feature that depends on being able to calculate the angle between the hands on a clock face. They’ve asked you to write some code to help out with that. This is an IOT project, and they have sensors emitting times at a pretty low frequency (about 10 a minute), and for some reason they need to be processed and stored as angles.

You may need to make some assupmtions, that's OK, just document what they are and move on.

The team loves innovation, so you can use whatever languages and technologies you like to complete this. Approach this problem as if your code will go to production. Whilst we don’t expect the code to be perfect, we are not looking for a hacked together script.

Your solution should offer the rest of the team a way to submit a time and receive an angle in return or store it somewhere. They are little fuzzy on the best way to get this low frequency data to your service, so if you can offer them any hints on that, they’d be really happy.

## How to proceed

**Fork this repo, then get to work.** Remember that this is a DevOps team, so make sure your repo reflects that. Spend however much time you feel is reasonable. It doesn’t matter if the project is ‘done’, nothing ever is. **When you’re ready push your changes back to Github and put in a pull request back to the base repo.**

Be sure to add in instructions for how to deploy your solution, and document things in a way that the rest of the team can pick this up and run with it. Remember you have all the tools in the GCP arsenal at your disposal.

We are looking for you to demonstrate your abilities in software practices and DevOps, including reusability, portability, reliability, ease of maintenance etc.

Think about how this will actually be deployed and maintained in the future as you build on it and expand it. You don’t have to implement deployment practices if you don’t have the time or resources, its ok to just document those.

---

## Product Backlog Item (Sprint Story)

Here is the story that is in the backlog.

As with all stories, the team may have been optimistic with how much can be done in the time permitted. It's ok to meet some of the acceptance criteria by documenting what you would do in the next sprint! Prioritize your time and make sure you have some technical content to deliver.

### Description:-

As a team<br>
We need a serivce that we can send a time value to and have it return or store an angle value<br>
So that we can use it in downstream processing

### Detail:-

We need to calculate the angle between the hands on a clock face. For example input 03:00 would yield 90 degrees.

### 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
Deploying Method:
The code automatically push changes to Google cloud function.
Google cloud "Source repositroy" has Trigger build on "Google Build" which deploys code to Cloud function "clock_angle".
25 changes: 25 additions & 0 deletions cloudbuild.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
steps:
-
name: gcr.io/cloud-builders/docker
args:
- build
- '-t'
- 'gcr.io/ind-coe/ar-clock:$COMMIT_SHA'
- .
-
name: gcr.io/cloud-builders/docker
args:
- push
- 'gcr.io/ind-coe/ar-clock:$COMMIT_SHA'
-
name: gcr.io/cloud-builders/gcloud
args:
- functions
- deploy
- clock_angle
- '--runtime'
- python37
- '--trigger-http'
- '--allow-unauthenticated'
- '--source=https://source.developers.google.com/projects/ind-coe/repos/ar_cloud_clock/moveable-aliases/master/paths/'
dir: 'functions/autodeploy'
41 changes: 41 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
"""
_author_ = Arpit Rawal
"""
def clock_angle(request):
"""
1. Function calculates angle clock hands
of hours and mins
2. Responds to any HTTP request.
Args:
request (flask.Request): HTTP request object.
Returns:
The response text will be string in form Angle ->90
"""
request_json = request.get_json()
request_args = request.args
if request.args and 'hrs' in request.args:
hrs = int(request.args.get('hrs'))
mins = int(request.args.get('mins'))
elif request_json and 'hrs' in request_json:
hrs = int(request_json['hrs'])
mins = int(request_json['mins'])
elif request_args and 'hrs' in request_args:
hrs = int(request_args['hrs'])
mins = int(request_args['mins'])
else:
ans_str = "Cannot compute due to some error"

if (0 <= int(hrs) <= 12 and 0 <= int(mins) <= 59):
degree_per_min = 6
degree_per_hour = 30
degree_intern = 0.5

if hrs == 12:
hrs = 0

angle_between = abs(hrs*degree_per_hour - mins*degree_per_min + mins*degree_intern)
ans_str = "Angle ->{0}".format(str(angle_between))

else:
ans_str = "Invalid Input, cannot compute, Try Again"
return ans_str
3 changes: 3 additions & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Flask==1.1.2
pylint==2.5.0
pytest==5.4.1
111 changes: 111 additions & 0 deletions test_cases.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# -*- coding: utf-8 -*-
"""
Created on Mon Apr 27 17:08:37 2020

@author: arawal
Function to unitesting of http function
"""



import os
import sys
import unittest

from unittest.mock import Mock
from flask import Flask

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))


import main


app = Flask(__name__)

class MyTestClass(unittest.TestCase):
"""
Class to implment TestCases for Clock Angle function in main
"""
# initialization logic for the test suite declared in the test module
# code that is executed before all tests in one test run
@classmethod
def setUpClass(cls):
pass

# clean up logic for the test suite declared in the test module
# code that is executed after all tests in one test run
@classmethod
def tearDownClass(cls):
pass

# initialization logic
# code that is executed before each test
def setUp(self):
# creates a test client
self.app = app.test_client()
# propagate the exceptions to the test client
self.app.testing = True

# clean up logic
# code that is executed after each test
def tearDown(self):
pass

# Tesing angle between the codes
def test_h3m0(self):
"""
Testing at 3 hrs 0 mins - Angle = 90
"""
hrs = 3
mins = 0
data = {'hrs': hrs, 'mins': mins}
req = Mock(get_json=Mock(return_value=data), args=data)

# Call tested function
angle1 = float(main.clock_angle(req).split('Angle ->')[1])
self.assertEqual(angle1, 90.0)

def test_2m45(self):
"""
Testing at 2 hrs 45 mins - Angle = 187.5
"""
hrs = 2
mins = 45
data = {'hrs': hrs, 'mins': mins}
req = Mock(get_json=Mock(return_value=data), args=data)

# Call tested function
angle1 = float(main.clock_angle(req).split('Angle ->')[1])
self.assertEqual(angle1, 187.5)

def test_h8m15(self):
"""
Testing at 8 hrs 15 mins - Angle = 157.5
"""
hrs = 8
mins = 15
data = {'hrs': hrs, 'mins': mins}
req = Mock(get_json=Mock(return_value=data), args=data)

# Call tested function
angle1 = float(main.clock_angle(req).split('Angle ->')[1])
self.assertEqual(angle1, 157.5)

def test_h6m0(self):
"""
Testing at 6 hrs 0 mins - Angle = 180
"""
hrs = 6
mins = 0
data = {'hrs': hrs, 'mins': mins}
req = Mock(get_json=Mock(return_value=data), args=data)

# Call tested function
angle1 = float(main.clock_angle(req).split('Angle ->')[1])
self.assertEqual(angle1, 180)


# runs the unit tests in the module
if __name__ == '__main__':
unittest.main()