test: integration link spec
- spec_helper (spec-kemal setup) - spec_helper (micreate migration) - create_test_link + get_test_link + delete_test_link helpers - fix test env variables
This commit is contained in:
@@ -0,0 +1,3 @@
|
||||
PORT=4001
|
||||
DATABASE_URL=sqlite3://./sqlite/data.test.db?journal_mode=wal&synchronous=normal&foreign_keys=true
|
||||
APP_URL=http://localhost:4001
|
||||
+16
-4
@@ -10,11 +10,11 @@ shards:
|
||||
|
||||
db:
|
||||
git: https://github.com/crystal-lang/crystal-db.git
|
||||
version: 0.13.1
|
||||
version: 0.11.0
|
||||
|
||||
dotenv:
|
||||
git: https://github.com/gdotdesign/cr-dotenv.git
|
||||
version: 0.6.0
|
||||
version: 1.0.0
|
||||
|
||||
exception_page:
|
||||
git: https://github.com/crystal-loot/exception_page.git
|
||||
@@ -24,15 +24,27 @@ shards:
|
||||
git: https://github.com/kemalcr/kemal.git
|
||||
version: 1.5.0
|
||||
|
||||
micrate:
|
||||
git: https://github.com/amberframework/micrate.git
|
||||
version: 0.15.1
|
||||
|
||||
mysql:
|
||||
git: https://github.com/crystal-lang/crystal-mysql.git
|
||||
version: 0.14.0
|
||||
|
||||
pg:
|
||||
git: https://github.com/will/crystal-pg.git
|
||||
version: 0.26.0
|
||||
|
||||
radix:
|
||||
git: https://github.com/luislavena/radix.git
|
||||
version: 0.4.1
|
||||
|
||||
spec-kemal:
|
||||
git: https://github.com/kemalcr/spec-kemal.git
|
||||
version: 0.5.0
|
||||
version: 1.0.0
|
||||
|
||||
sqlite3:
|
||||
git: https://github.com/crystal-lang/crystal-sqlite3.git
|
||||
version: 0.21.0
|
||||
version: 0.19.0
|
||||
|
||||
|
||||
@@ -5,8 +5,10 @@ authors:
|
||||
- Juan Rodriguez <sjdonado@icloud.com>
|
||||
|
||||
targets:
|
||||
pa:
|
||||
main: src/url-shortener.cr
|
||||
url-shortener:
|
||||
main: url-shortener.cr
|
||||
cli:
|
||||
main: scripts/cli.cr
|
||||
|
||||
dependencies:
|
||||
kemal:
|
||||
@@ -21,6 +23,9 @@ development_dependencies:
|
||||
github: gdotdesign/cr-dotenv
|
||||
spec-kemal:
|
||||
github: kemalcr/spec-kemal
|
||||
micrate:
|
||||
github: amberframework/micrate
|
||||
version: 0.15.1
|
||||
|
||||
crystal: '>= 1.12.1'
|
||||
|
||||
|
||||
@@ -0,0 +1,226 @@
|
||||
require "../spec_helper"
|
||||
require "../../app/models/*"
|
||||
|
||||
API_KEY = Random::Secure.urlsafe_base64()
|
||||
|
||||
describe App::Controllers::Link do
|
||||
describe "Create" do
|
||||
it "should create link" do
|
||||
test_user = create_test_user()
|
||||
|
||||
payload = {"url" => "https://kagi.com"}
|
||||
post(
|
||||
"/api/links",
|
||||
headers: HTTP::Headers{"Content-Type" => "application/json", "X-Api-Key" => test_user.api_key.to_s},
|
||||
body: payload.to_json
|
||||
)
|
||||
|
||||
parsed_response = Hash(String, Hash(String, String | Int64)).from_json(response.body)
|
||||
parsed_response["data"]["origin"].should eq(payload["url"])
|
||||
end
|
||||
|
||||
it "should return 400 - url required field" do
|
||||
test_user = create_test_user()
|
||||
|
||||
payload = {"test" => "https://kagi.com"}
|
||||
post(
|
||||
"/api/links",
|
||||
headers: HTTP::Headers{"Content-Type" => "application/json", "X-Api-Key" => test_user.api_key.to_s},
|
||||
body: payload.to_json
|
||||
)
|
||||
|
||||
expected = {"error" => "url: Required field"}.to_json
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
|
||||
it "should return 400 - invalid url" do
|
||||
test_user = create_test_user()
|
||||
|
||||
payload = {"url" => "test" }
|
||||
post(
|
||||
"/api/links",
|
||||
headers: HTTP::Headers{"Content-Type" => "application/json", "X-Api-Key" => test_user.api_key.to_s},
|
||||
body: payload.to_json
|
||||
)
|
||||
|
||||
expected = {"errors" => {"url" => ["is invalid"]}}.to_json
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
|
||||
it "should return 401 - missing api key" do
|
||||
payload = {"url" => "https://kagi.com"}
|
||||
post("/api/links", headers: HTTP::Headers{"Content-Type" => "application/json"}, body: payload.to_json)
|
||||
|
||||
expected = {"error" => "Unauthorized"}.to_json
|
||||
response.status_code.should eq(401)
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Index" do
|
||||
it "should redirect to origin domain" do
|
||||
link = "https://kagi.com"
|
||||
test_user = create_test_user()
|
||||
|
||||
test_link = create_test_link(test_user, link)
|
||||
serialized_link = App::Serializers::Link.new(test_link)
|
||||
|
||||
get(serialized_link.refer, headers: HTTP::Headers{"X-Api-Key" => test_user.api_key.to_s})
|
||||
|
||||
response.headers["Location"].should eq(link)
|
||||
end
|
||||
|
||||
it "should increase click counter after redirect" do
|
||||
link = "https://kagi.com"
|
||||
test_user = create_test_user()
|
||||
|
||||
test_link = create_test_link(test_user, link)
|
||||
serialized_link = App::Serializers::Link.new(test_link)
|
||||
|
||||
get(serialized_link.refer, headers: HTTP::Headers{"X-Api-Key" => test_user.api_key.to_s})
|
||||
|
||||
updated_test_link = get_test_link(test_link.id)
|
||||
|
||||
response.headers["Location"].should eq(link)
|
||||
updated_test_link.click_counter.should eq(1)
|
||||
end
|
||||
|
||||
it "should return 404 - link does not exist" do
|
||||
link = "https://kagi.com"
|
||||
test_user = create_test_user()
|
||||
|
||||
test_link = create_test_link(test_user, link)
|
||||
serialized_link = App::Serializers::Link.new(test_link)
|
||||
|
||||
delete_test_link(test_link.id)
|
||||
|
||||
get(serialized_link.refer, headers: HTTP::Headers{"X-Api-Key" => test_user.api_key.to_s})
|
||||
|
||||
expected = {"error" => "Not Found"}.to_json
|
||||
response.status_code.should eq(404)
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
describe "All" do
|
||||
it "should return all links" do
|
||||
links = ["https://google.com", "google.com", "google.com.co"]
|
||||
test_user = create_test_user()
|
||||
|
||||
links.each do |link|
|
||||
create_test_link(test_user, link)
|
||||
end
|
||||
|
||||
get("/api/links", headers: HTTP::Headers{"X-Api-Key" => test_user.api_key.to_s})
|
||||
|
||||
parsed_response = Hash(String, Array(Hash(String, String | Int64))).from_json(response.body)
|
||||
parsed_response["data"][0]["origin"].should eq(links[0])
|
||||
parsed_response["data"][1]["origin"].should eq(links[1])
|
||||
parsed_response["data"][2]["origin"].should eq(links[2])
|
||||
end
|
||||
|
||||
it "should return owned links only" do
|
||||
links = ["https://google.com", "google.com", "google.com.co", "kagi.com"]
|
||||
test_user = create_test_user()
|
||||
|
||||
links[0..2].each do |link|
|
||||
create_test_link(test_user, link)
|
||||
end
|
||||
|
||||
test_other_user = create_test_user()
|
||||
create_test_link(test_other_user, links[3])
|
||||
|
||||
get("/api/links", headers: HTTP::Headers{"X-Api-Key" => test_user.api_key.to_s})
|
||||
|
||||
parsed_response = Hash(String, Array(Hash(String, String | Int64))).from_json(response.body)
|
||||
parsed_response["data"].size.should eq(3)
|
||||
parsed_response["data"][0]["origin"].should eq(links[0])
|
||||
parsed_response["data"][1]["origin"].should eq(links[1])
|
||||
parsed_response["data"][2]["origin"].should eq(links[2])
|
||||
end
|
||||
|
||||
it "should return 401 - missing api key" do
|
||||
get "/api/links"
|
||||
|
||||
expected = {"error" => "Unauthorized"}.to_json
|
||||
response.status_code.should eq(401)
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Update" do
|
||||
it "should update link url" do
|
||||
link = "https://kagi.com"
|
||||
test_user = create_test_user()
|
||||
test_link = create_test_link(test_user, link)
|
||||
|
||||
payload = {"url" => "https://kagi.com.co"}
|
||||
put(
|
||||
"/api/links/#{test_link.id}",
|
||||
headers: HTTP::Headers{"Content-Type" => "application/json", "X-Api-Key" => test_user.api_key.to_s},
|
||||
body: payload.to_json
|
||||
)
|
||||
|
||||
parsed_response = Hash(String, Hash(String, String | Int64)).from_json(response.body)
|
||||
parsed_response["data"]["origin"].should eq(payload["url"])
|
||||
end
|
||||
|
||||
it "should return 404 - link does not exist" do
|
||||
test_user = create_test_user()
|
||||
|
||||
payload = {"url" => "https://kagi.com.co"}
|
||||
put(
|
||||
"/api/links/1",
|
||||
headers: HTTP::Headers{"Content-Type" => "application/json", "X-Api-Key" => test_user.api_key.to_s},
|
||||
body: payload.to_json
|
||||
)
|
||||
|
||||
expected = {"error" => "Not Found"}.to_json
|
||||
response.status_code.should eq(404)
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
|
||||
it "should return 401 - missing api key" do
|
||||
payload = {"url" => "https://kagi.com.co"}
|
||||
put(
|
||||
"/api/links/1",
|
||||
headers: HTTP::Headers{"Content-Type" => "application/json"},
|
||||
body: payload.to_json
|
||||
)
|
||||
|
||||
expected = {"error" => "Unauthorized"}.to_json
|
||||
response.status_code.should eq(401)
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
end
|
||||
|
||||
describe "Delete" do
|
||||
it "should delete link url" do
|
||||
link = "https://kagi.com"
|
||||
test_user = create_test_user()
|
||||
test_link = create_test_link(test_user, link)
|
||||
|
||||
delete("/api/links/#{test_link.id}", headers: HTTP::Headers{"X-Api-Key" => test_user.api_key.to_s})
|
||||
|
||||
response.status_code.should eq(204)
|
||||
end
|
||||
|
||||
it "should return 404 - link does not exist" do
|
||||
test_user = create_test_user()
|
||||
|
||||
delete("/api/links/1", headers: HTTP::Headers{"X-Api-Key" => test_user.api_key.to_s})
|
||||
|
||||
expected = {"error" => "Not Found"}.to_json
|
||||
response.status_code.should eq(404)
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
|
||||
it "should return 401 - missing api key" do
|
||||
delete "/api/links/1"
|
||||
|
||||
expected = {"error" => "Unauthorized"}.to_json
|
||||
response.status_code.should eq(401)
|
||||
response.body.should eq(expected)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,9 +0,0 @@
|
||||
require "./spec_helper"
|
||||
|
||||
describe Url::Shortener do
|
||||
# TODO: Write tests
|
||||
|
||||
it "works" do
|
||||
false.should eq(true)
|
||||
end
|
||||
end
|
||||
+48
-2
@@ -1,2 +1,48 @@
|
||||
require "spec"
|
||||
require "../src/pa"
|
||||
require "uuid"
|
||||
|
||||
require "spec-kemal"
|
||||
require "micrate"
|
||||
|
||||
require "../url-shortener"
|
||||
|
||||
Spec.before_suite do
|
||||
Micrate::DB.connection_url = ENV["DATABASE_URL"]
|
||||
Micrate::Cli.run_up
|
||||
end
|
||||
|
||||
def create_test_user
|
||||
user = App::Models::User.new
|
||||
user.id = UUID.v4.to_s
|
||||
user.name = "Tester"
|
||||
user.api_key = Random::Secure.urlsafe_base64()
|
||||
|
||||
changeset = App::Lib::Database.insert(user)
|
||||
if !changeset.valid?
|
||||
raise "Test user creation failed"
|
||||
end
|
||||
|
||||
user
|
||||
end
|
||||
|
||||
def create_test_link(user, url)
|
||||
link = App::Models::Link.new
|
||||
link.id = UUID.v4.to_s
|
||||
link.url = url
|
||||
link.slug = Random::Secure.urlsafe_base64(4)
|
||||
link.user = user
|
||||
|
||||
changeset = App::Lib::Database.insert(link)
|
||||
if !changeset.valid?
|
||||
raise "Test link creation failed"
|
||||
end
|
||||
|
||||
link
|
||||
end
|
||||
|
||||
def get_test_link(link_id)
|
||||
App::Lib::Database.get!(App::Models::Link, link_id)
|
||||
end
|
||||
|
||||
def delete_test_link(link_id)
|
||||
App::Lib::Database.raw_exec("DELETE FROM links WHERE id = (?)", link_id) # tempfix: Database.delete does not work
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user