diff options
| -rw-r--r-- | .github/stale.yml | 19 | ||||
| -rw-r--r-- | README.md | 101 | ||||
| -rw-r--r-- | server-rack.rb | 45 | ||||
| -rw-r--r-- | test.rb | 58 |
4 files changed, 222 insertions, 1 deletions
diff --git a/.github/stale.yml b/.github/stale.yml new file mode 100644 index 0000000..b17326f --- /dev/null +++ b/.github/stale.yml @@ -0,0 +1,19 @@ +pulls: + # Number of days of inactivity before a PR becomes stale + daysUntilStale: 1 + # Number of days of inactivity before a stale PR is closed + daysUntilClose: 7 + # PRs with these labels will never be considered stale + exemptLabels: + - Error + - Keep + # Label to use when marking an issue as stale + staleLabel: Stale + # Comment to post when marking an issue as stale. Set to `false` to disable + markComment: > + This pull request has been awaiting review for 24 hours. If you are a reviewer, please + complete your review as soon as possible. If you are unable to do so, please find someone + else to cover for you! If this should be kept open for other reason, assign the label `Keep` + and stale won't comment on it again. Otherwise in a week this candidate review will be closed. + # Comment to post when closing a stale issue. Set to `false` to disable + closeComment: false @@ -1 +1,100 @@ -Readme
\ No newline at end of file +# Coding Exercise: Data Storage API + +Implement a small HTTP service to store objects organized by repository. +Clients of this service should be able to GET, PUT, and DELETE objects. + +## Expectations + +We ask that you spend no more than 2 hours on this exercise. We value your time and don't want to set unreasonable expectations on how long you should work on this exercise. + +We ask you complete this exercise so you have an opportunity to build a service in your own time rather than an in-person interview, coding on a whiteboard. + +## General Requirements + +* The service should de-duplicate data objects by repository. +* The service should listen on port `8282`. +* The included tests should pass without modification. +* The service must implement the API as described below. +* The data can be persisted in memory, on disk, or wherever you like. +* Do not include any extra dependencies. + +## Suggestions + +* Your code will be read by humans, so organize it sensibly. +* Use this repository to store your work. Committing just the final solution is *ok* but we'd love to see your incremental progress. We suggest taking a look at [GitHub flow](https://guides.github.com/introduction/flow/) to structure your commits. +* [Submit a pull request](https://help.github.com/articles/creating-a-pull-request/) once you are happy with your work. + +## API + +### Upload an Object + +``` +PUT /data/{repository} +``` + +#### Response + +``` +Status: 201 Created +{ + "oid": "2845f5a412dbdfacf95193f296dd0f5b2a16920da5a7ffa4c5832f223b03de96", + "size": 1234 +} +``` + +### Download an Object + +``` +GET /data/{repository}/{objectID} +``` + +#### Response + +``` +Status: 200 OK +{object data} +``` + +Objects that are not on the server will return a `404 Not Found`. + +### Delete an Object + +``` +DELETE /data/{repository}/{objectID} +``` + +#### Response + +``` +Status: 200 OK +``` + +## Getting started and Testing +In server-rack.rb you'll find a naive first draft of the answer to the exercise written for you. Please improve this draft so that it passes the test written in test.rb. You might need to install rack: + +``` +gem install rack rack-test +``` + +You can test that this works by running: + +``` +ruby test.rb +``` + +Once you have a good version of `server-rack.rb` please submit that file in a pull request. + +Behind the scenes we add the following `.travis.yml` file to your code: + +``` +language: ruby +rvm: + - 2.4.4 +before_script: + - cd ./ruby + - gem install rack rack-test +script: + - ruby test.rb +``` + +So please don't move tests or add in dependencies. diff --git a/server-rack.rb b/server-rack.rb new file mode 100644 index 0000000..b73f4da --- /dev/null +++ b/server-rack.rb @@ -0,0 +1,45 @@ +#!/usr/bin/env ruby +# Usage: +# +# $ ruby rack-server.rb +require 'rack' +require 'json' + +class DataStorageServer + # You may initialize any variables you want to use across requests here + def initialize + @storage = {} + end + + # Download an Object + # + # GET /data/{repository}/{objectID} + # Response + # + # Status: 200 OK + # {object data} + # Objects that are not on the server will return a 404 Not Found. + def get(path) + ['200', {}, ["hello from get #{path}"]] + end + + + def call(env) + path = env['PATH_INFO'] + case env['REQUEST_METHOD'] + when 'GET' + get(path) + end + end +end + +# This starts the server if the script is invoked from the command line. No +# modifications needed here. +if __FILE__ == $0 + app = Rack::Builder.new do + use Rack::Reloader + run DataStorageServer.new + end.to_app + + Rack::Server.start(app: app, Port: 8282) +end
\ No newline at end of file @@ -0,0 +1,58 @@ +require 'minitest/autorun' +require 'rack/test' +require_relative './server-rack' + +class DataStorageServerTest < Minitest::Test + include Rack::Test::Methods + + def app + DataStorageServer.new + end + + def test_put + put '/data/foo', 'some object' + res = JSON.parse(last_response.body) + + assert_equal 201, last_response.status + assert_equal 11, res["size"] + assert res["oid"].is_a?(String) + assert res["oid"].length > 0 + end + + def test_get + put '/data/foo', 'some object' + res1 = JSON.parse(last_response.body) + + put '/data/foo', 'other object' + res2 = JSON.parse(last_response.body) + + refute_equal res1["oid"], res2["oid"] + + get "/data/foo/#{res1["oid"]}" + assert_equal 'some object', last_response.body + + get "/data/foo/#{res2["oid"]}" + assert_equal 'other object', last_response.body + end + + def test_get_not_found + get '/data/foo/noooope' + assert_equal 404, last_response.status + end + + def test_delete + put '/data/foo', 'some object' + res = JSON.parse(last_response.body) + + delete "/data/foo/#{res["oid"]}" + assert_equal 200, last_response.status + + get "/data/foo/#{res["oid"]}" + assert_equal 404, last_response.status + end + + def test_delete_nonexistant_object + delete "/data/foo/nooope" + assert_equal 404, last_response.status + end +end
\ No newline at end of file |
