Compare commits

..

65 Commits

Author SHA1 Message Date
bucky 5631ae386f include rackup 2023-10-13 21:28:47 -07:00
bucky c31c556df5 removed falcon and it's dependencies, because it wasn't working right.
use puma for now
2023-10-13 21:27:25 -07:00
bucky 5fae0c4fa9 Merge pull request 'rspec-coverage' (#22) from rspec-coverage into master
Reviewed-on: #22
2023-10-12 23:49:48 -07:00
bucky 144731062b added URL validation to webpage part 2023-10-12 23:42:52 -07:00
bucky 72f3e03edd added tests for invalid URL entries
+ URL that returns a 404
+ URL where the domain does not resolve with DNS
+ URL that is not properly formatted
2023-10-12 23:42:04 -07:00
bucky b08693e866 remove the puts, don't print out the test result 2023-10-12 23:41:38 -07:00
bucky ae2360a480 include the proper status code 2023-10-12 23:31:15 -07:00
bucky 213265a5d0 added test for submitting with the wrong content type header 2023-10-12 23:30:47 -07:00
bucky dfb6b23e70 run simplecov for rspec tests 2023-10-12 23:12:14 -07:00
bucky c81a7a6160 added rescue for urls that don't resolve 2023-10-12 19:03:03 -07:00
bucky bbb710a5e1 added test for bad TLD, better named 404 url test 2023-10-12 19:02:38 -07:00
bucky 7eaa8eacf8 added rescue for OpenURI HTTPErrors 2023-10-12 18:26:13 -07:00
bucky d78e361c29 added test for validating a url is accessible 2023-10-12 18:25:38 -07:00
bucky 1ae6c02472 rescue BadURIError for invalid URL format 2023-10-12 18:20:56 -07:00
bucky 11206854ad added test for an invalid url 2023-10-12 18:20:35 -07:00
bucky 33089e6fbd build HTML output with cucumber and rspec files in root dir 2023-10-12 16:25:22 -07:00
bucky 5cec47efcc Merge pull request 'create-json' (#21) from create-json into master
Reviewed-on: #21
2023-10-12 14:36:38 -07:00
bucky cabb4daded split up the nil? and empty? cases, because they are different
situations
2023-10-12 14:27:31 -07:00
bucky 1e61a76ded added 2 more tests for empty and missing url data posting to links 2023-10-12 14:27:02 -07:00
bucky ac3e9f14cd added links route for API interactions 2023-10-12 11:42:43 -07:00
bucky 5ee9351362 added db initialization to make sure the db exists and is up to date
before tests
2023-10-12 11:42:14 -07:00
bucky 2964e06639 added before and after actions
+ before initializes the db
+ after cleans the db
2023-10-12 11:40:15 -07:00
bucky d1a0fc0222 change request to use the /links path, to fit more into a RESTful API
format

+ also renamed the test to better describe the behavior
2023-10-12 11:32:00 -07:00
bucky 4a82174526 implemented API create endpoint
+ added plugins to read json and access the header to parse the request
  for an API request
+ fixed logic where url param is nil
+ refactored the new code to a variable to be reused easier
+ if CONTENT_TYPE header is application/json, reply with json
- there could be more refactoring (maybe separating it to a different
  endpoint) to handle other scenarios, we'll work on that later
2023-10-11 19:21:43 -07:00
bucky 3ae20255f6 DRY it out a little 2023-10-11 19:21:21 -07:00
bucky f69c53bf29 removed unnecessary variable 2023-10-11 19:20:07 -07:00
bucky 7d6c098047 added more to the spec test for creating a new link 2023-10-11 19:18:47 -07:00
bucky 3421e18f21 added more logic for running tests without killing the whole pipeline, and outputting rspec results 2023-10-11 12:05:33 -07:00
bucky 0dec27a01c added rspec step in tests stage, adjusted should clause 2023-10-11 11:04:08 -07:00
bucky c45cf6ab51 started building out rspec specs for API functionality 2023-10-11 11:01:46 -07:00
bucky e50667b392 split homepage out into homepage and submit feature sets 2023-10-10 17:29:23 -07:00
bucky d4db64f404 Merge pull request 'cucumber-jenkins' (#20) from cucumber-jenkins into master
Reviewed-on: #20
2023-10-10 17:22:55 -07:00
bucky 05858078d1 added unstable scenario 2023-10-10 17:20:25 -07:00
bucky f75f0378bf separate out success and failure tasks 2023-10-10 17:16:24 -07:00
bucky c3d2fb32e2 added icon for message 2023-10-10 17:11:05 -07:00
bucky 1fe30fc7e7 removed jenkins cucumber section, use the html formatter instead
also added more info to the success message
2023-10-10 17:05:33 -07:00
bucky 43cc151138 moved stuff around a little more 2023-10-10 14:50:01 -07:00
bucky 1fee4f276d maybe put both files in the same report 2023-10-10 14:47:09 -07:00
bucky 0b17f36fde added more test results, just exploring 2023-10-10 14:43:11 -07:00
bucky aca92fdae1 cleaned up message a bit for success 2023-10-10 14:32:54 -07:00
bucky c7bf62062a wrap it 2023-10-10 14:28:41 -07:00
bucky b853ca6fe4 trying to make the message cleaner, and print the env to take a look at other options 2023-10-10 14:25:59 -07:00
bucky d5919fc82a got it working with vars, now try the URLs 2023-10-10 14:23:44 -07:00
bucky e2395989f4 try normal quotes 2023-10-10 14:22:30 -07:00
bucky e93868a483 try DB_NAME since the others are failing 2023-10-10 14:19:59 -07:00
bucky 7f6fc24872 maybe this one will work 2023-10-10 14:17:48 -07:00
bucky 776ec0d30d trying different env vars 2023-10-10 14:10:50 -07:00
bucky 6861740d00 bots can't be easily used with incoming webhooks, but let's try some URLs 2023-10-10 14:05:18 -07:00
bucky 77e72d18e1 use the bot's endpoint 2023-10-10 13:50:48 -07:00
bucky 1792d94082 extra , syntax error in jenkins file 2023-10-10 13:30:40 -07:00
bucky 16d17bcadb added icon 2023-10-10 13:27:40 -07:00
bucky f5d1361d59 swapped text/message 2023-10-10 13:10:19 -07:00
bucky c4932dd6cc message to mattermost example 2023-10-10 13:02:31 -07:00
bucky 031a30ed5f send slack message to mattermost for cucumber results 2023-10-10 10:52:14 -07:00
bucky cc1fe1c3b7 Merge pull request 'cucumber-jenkins' (#19) from cucumber-jenkins into master
Reviewed-on: #19
2023-10-10 09:44:14 -07:00
bucky 72e1cee9d5 split features into 2 separate feature files 2023-10-09 20:19:34 -07:00
bucky a90ff753b1 use cucumber plugin 2023-10-09 18:52:48 -07:00
bucky b6010cd431 remove the config in there 2023-10-09 18:37:46 -07:00
bucky 33bfb23405 add a setting for it 2023-10-09 18:35:50 -07:00
bucky ad4f8492d4 add jenkins cucumber functionality 2023-10-09 18:30:50 -07:00
bucky e6cc0959a4 Merge pull request 'invalid-urls' (#18) from invalid-urls into master
Reviewed-on: #18
2023-10-07 21:13:53 -07:00
bucky 5bce31baf2 refactored missing link scenario to make more sense
+ 404 code, stay on the current page, and load the form
+ also simplified the logic for the create action if the link doesn't
  already exist
2023-10-07 21:11:12 -07:00
bucky c7fee27623 update for missing link scenario
+ if the link isn't found, don't redirect it, keep it on the same page
+ it should have a status code of 404
+ it should have the form fields as well

+ added page status check
2023-10-07 21:10:16 -07:00
bucky f8499a79c2 check if the link exists, redirects home if it doesn't 2023-10-07 13:38:10 -07:00
bucky b97ee3f3bb use the correct clause format since staying on site 2023-10-07 13:37:51 -07:00
9 changed files with 281 additions and 108 deletions
+4 -1
View File
@@ -2,7 +2,6 @@
source "https://rubygems.org"
gem "falcon", "~> 0.42.3"
gem "roda", "~> 3.72"
@@ -27,3 +26,7 @@ group :test do
gem "simplecov"
end
gem "puma", "~> 6.4"
gem "rackup", "~> 2.1"
+9 -64
View File
@@ -3,30 +3,7 @@ GEM
specs:
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
async (2.6.4)
console (~> 1.10)
fiber-annotation
io-event (~> 1.1)
timers (~> 4.1)
async-container (0.16.12)
async
async-io
async-http (0.60.2)
async (>= 1.25)
async-io (>= 1.28)
async-pool (>= 0.2)
protocol-http (~> 0.24.0)
protocol-http1 (~> 0.15.0)
protocol-http2 (~> 0.15.0)
traces (>= 0.10.0)
async-http-cache (0.4.3)
async-http (~> 0.56)
async-io (1.36.0)
async
async-pool (0.4.0)
async (>= 1.25)
bigdecimal (3.1.4)
build-environment (1.13.0)
builder (3.2.4)
capybara (3.39.2)
addressable
@@ -37,9 +14,6 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
console (1.23.2)
fiber-annotation
fiber-local
cucumber (9.0.2)
builder (~> 3.2, >= 3.2.4)
cucumber-ci-environment (~> 9.2, >= 9.2.0)
@@ -67,51 +41,25 @@ GEM
diff-lcs (1.5.0)
docile (1.4.0)
erubi (1.12.0)
falcon (0.42.3)
async
async-container (~> 0.16.0)
async-http (~> 0.57)
async-http-cache (~> 0.4.0)
async-io (~> 1.22)
build-environment (~> 1.13)
bundler
localhost (~> 1.1)
openssl (~> 3.0)
process-metrics (~> 0.2.0)
protocol-rack (~> 0.1)
samovar (~> 2.1)
ffi (1.16.2)
fiber-annotation (0.2.0)
fiber-local (1.0.0)
io-event (1.3.2)
localhost (1.1.10)
mapping (1.1.1)
matrix (0.4.2)
mini_mime (1.1.5)
mini_portile2 (2.8.4)
multi_test (1.1.0)
nio4r (2.5.9)
nokogiri (1.15.4)
mini_portile2 (~> 2.8.2)
racc (~> 1.4)
openssl (3.2.0)
process-metrics (0.2.1)
console (~> 1.8)
samovar (~> 2.1)
protocol-hpack (1.4.2)
protocol-http (0.24.7)
protocol-http1 (0.15.1)
protocol-http (~> 0.22)
protocol-http2 (0.15.1)
protocol-hpack (~> 1.4)
protocol-http (~> 0.18)
protocol-rack (0.2.6)
protocol-http (~> 0.23)
rack (>= 1.0)
public_suffix (5.0.3)
puma (6.4.0)
nio4r (~> 2.0)
racc (1.7.1)
rack (3.0.8)
rack-test (2.1.0)
rack (>= 1.3)
rackup (2.1.0)
rack (>= 3)
webrick (~> 1.8)
regexp_parser (2.8.1)
rexml (3.2.6)
roda (3.72.0)
@@ -130,9 +78,6 @@ GEM
rspec-support (~> 3.12.0)
rspec-support (3.12.1)
rubyzip (2.3.2)
samovar (2.2.0)
console (~> 1.0)
mapping (~> 1.0)
selenium-webdriver (4.13.1)
rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 3.0)
@@ -150,8 +95,7 @@ GEM
sys-uname (1.2.3)
ffi (~> 1.1)
tilt (2.3.0)
timers (4.3.5)
traces (0.11.1)
webrick (1.8.1)
websocket (1.2.10)
xpath (3.2.0)
nokogiri (~> 1.8)
@@ -163,7 +107,8 @@ DEPENDENCIES
capybara (~> 3.39)
cucumber (~> 9.0)
erubi (~> 1.12)
falcon (~> 0.42.3)
puma (~> 6.4)
rackup (~> 2.1)
roda (~> 3.72)
rspec (~> 3.12)
selenium-webdriver (~> 4.13)
Vendored
+20 -4
View File
@@ -25,7 +25,12 @@ pipeline {
}
stage('Run tests') {
steps {
sh 'cucumber'
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
sh 'cucumber features --format html --out cucumber.html'
}
catchError(buildResult: 'UNSTABLE', stageResult: 'FAILURE') {
sh 'rspec spec --format html --out spec.html'
}
}
}
stage('Report results') {
@@ -35,11 +40,22 @@ pipeline {
allowMissing: false,
alwaysLinkToLastBuild: false,
keepAll: true,
reportDir: 'coverage',
reportFiles: 'index.html',
reportDir: '.',
reportFiles: 'cucumber.html, spec.html, coverage/index.html',
reportName: 'Test Results',
reportTitles: 'Test Coverage'])
reportTitles: 'Cucumber Results, RSpec Results, Test Coverage'])
}
}
}
post {
success {
mattermostSend channel: 'git-messages', color: 'good', message: "[${JOB_NAME}](${JOB_URL}) [#${BUILD_NUMBER}](${BUILD_URL}) ([Gitea](${GIT_URL}))", text: 'Build Finished Successfully'
}
unstable {
mattermostSend channel: 'git-messages', color: 'warning', message: "[${JOB_NAME}](${JOB_URL}) [#${BUILD_NUMBER}](${BUILD_URL}) ([Gitea](${GIT_URL}))", text: "Build Unstable"
}
failure {
mattermostSend channel: 'git-messages', color: 'danger', message: "[${JOB_NAME}](${JOB_URL}) [#${BUILD_NUMBER}](${BUILD_URL}) ([Gitea](${GIT_URL}))", text: "Build Failed"
}
}
}
+67 -5
View File
@@ -2,11 +2,14 @@ require 'roda'
require 'securerandom'
require 'json'
require 'sequel'
require 'open-uri'
class App < Roda
plugin :sessions, secret: ENV.delete('APP_SESSION_SECRET')
plugin :render, escape: true
plugin :flash
plugin :json_parser
plugin :request_headers
DB = Sequel.sqlite("db/#{ENV['DB_NAME']}")
links = DB[:links]
@@ -18,24 +21,83 @@ class App < Roda
end
r.get String do | url_code |
link = links.filter(:code => url_code).first[:url]
r.redirect link
link = links.filter(:code => url_code)
r.redirect link.first[:url] unless link.first.nil?
@message = "Link #{url_code} doesn't exist"
response.status = 404
view :home
end
r.post "create" do
url = r.params['url']
if url.empty?
if url.nil? or url.empty?
flash['message'] = "Please enter a valid URL";
r.redirect '/'
end
if nil == links.filter(:url => url).first
begin
OpenURI.open_uri(url)
rescue URI::BadURIError
flash['message'] = "Invalid URL"
r.redirect '/'
rescue OpenURI::HTTPError
flash['message'] = "URL not found"
r.redirect '/'
rescue SocketError => e
flash['message'] = "URL does not resolve"
r.redirect '/'
end
if links.filter(:url => url).first.nil?
code = SecureRandom.urlsafe_base64 4
links.insert(url: url, code: code)
@message = "Link created"
end
code = links.filter(:url => url).first[:code]
@message ||= "Link exists"
@new_link = 'http://' + request.env['HTTP_HOST'] + '/' + links.filter(:url => url).first[:code]
@new_link = 'http://' + request.env['HTTP_HOST'] + '/' + code
view :create
end
r.on "links" do
r.post do
if 'application/json' != r.headers['CONTENT_TYPE']
response.status = 400
return {message: "not a valid json request"}.to_json
end
url = r.params['url']
if url.nil?
response.status = 400
return {message: "missing url parameter"}.to_json
end
if url.empty?
response.status = 400
return {message: "invalid url parameter"}.to_json
end
begin
OpenURI.open_uri(url)
rescue URI::BadURIError
response.status = 400
return {message: "invalid url parameter"}.to_json
rescue OpenURI::HTTPError
response.status = 400
return {message: "url not found"}.to_json
rescue SocketError => e
response.status = 400
return {message: "url does not resolve"}.to_json
end
if links.filter(:url => url).first.nil?
code = SecureRandom.urlsafe_base64 4
links.insert(url: url, code: code)
end
code = links.filter(:url => url).first[:code]
@new_link = 'http://' + request.env['HTTP_HOST'] + '/' + code
return {url: url, code: code, link: @new_link}.to_json
end
end
end
end
-34
View File
@@ -10,37 +10,3 @@ Feature: Homepage
And I should see the message "Enter a URL"
And I should see a form field "url"
And I should see a "Submit" button
Scenario: Submitting the form without entering a URL
Given I visit the "/" page
When I click the "Submit" button
Then I should be on "/" page
And I should see the message "Please enter a valid URL"
@db-test
Scenario: Submitting the form with a correct URL
Given I visit the "/" page
When I type "http://google.com" in the "url" field
And I click the "Submit" button
Then I should be on "/create" page
And I should see the message "Link created"
@db-test
Scenario: Submitting the form with an existing URL
Given I visit the "/" page
And A link already exists with the url "http://google.com"
When I type "http://google.com" in the "url" field
And I click the "Submit" button
Then I should be on "/create" page
And I should see the message "Link exists"
@db-test
Scenario: Accessing the URL based on the shortcode
Given A link already exists with the url "https://google.com" and code "aaaaaa"
When I visit the "/aaaaaa" location
Then I should be redirected to "https://google.com"
Scenario: Accessing a nonexistent URL code
Given I visit the "/aaaaaa" location
Then I should be redirected to "/"
And I should see the message "Link aaaaaa doesn't exist"
+9
View File
@@ -3,6 +3,7 @@ Before('@db-test') do
@links = Sequel.sqlite("db/#{ENV['DB_NAME']}")[:links]
end
# GIVEN
Given('I visit the {string} page') do |string|
@@ -17,6 +18,7 @@ Given('A link already exists with the url {string} and code {string}') do |url,
@links.insert(url: url, code: code)
end
# WHEN
When('I click the {string} button') do |string|
@@ -31,6 +33,7 @@ When('I visit the {string} location') do |string|
visit string
end
# THEN
Then('I should see text {string}') do |string|
@@ -58,6 +61,12 @@ Then('I should be redirected to {string}') do |string|
location = actual.index(string)
location.should equal(0)
end
Then('The status code should be {int}') do |code|
page.status_code.should eq(code)
end
# AFTER
After('@db-test') do
+52
View File
@@ -0,0 +1,52 @@
# features/submit.feature
Feature: Submit
Submitting URL's on the homepage
Scenario: Submitting the form without entering a URL
Given I visit the "/" page
When I click the "Submit" button
Then I should be on "/" page
And I should see the message "Please enter a valid URL"
@db-test
Scenario: Submitting the form with a correct URL
Given I visit the "/" page
When I type "http://google.com" in the "url" field
And I click the "Submit" button
Then I should be on "/create" page
And I should see the message "Link created"
@db-test
Scenario: Submitting the form with an existing URL
Given I visit the "/" page
And A link already exists with the url "http://google.com"
When I type "http://google.com" in the "url" field
And I click the "Submit" button
Then I should be on "/create" page
And I should see the message "Link exists"
@db-test
Scenario: Submitting the form with a URL that is 404
Given I visit the "/" page
When I type "http://google.com/example" in the "url" field
And I click the "Submit" button
Then I should be on "/" page
And I should see the message "URL not found"
@db-test
Scenario: Submitting the form with a URL that does not resolve
Given I visit the "/" page
When I type "http://bad.tld" in the "url" field
And I click the "Submit" button
Then I should be on "/" page
And I should see the message "URL does not resolve"
@db-test
Scenario: Submitting the form with an invalid URL
Given I visit the "/" page
When I type "not-an-url" in the "url" field
And I click the "Submit" button
Then I should be on "/" page
And I should see the message "Invalid URL"
+19
View File
@@ -0,0 +1,19 @@
# features/visit.feature
Feature: Visit
Accessing a URL from it's link code
@db-test
Scenario: Accessing the URL based on the shortcode
Given A link already exists with the url "https://google.com" and code "aaaaaa"
When I visit the "/aaaaaa" location
Then I should be redirected to "https://google.com"
Scenario: Accessing a nonexistent URL code
Given I visit the "/aaaaaa" location
Then I should be on "/aaaaaa" page
And The status code should be 404
And I should see the message "Link aaaaaa doesn't exist"
And I should see a form field "url"
And I should see a "Submit" button
+101
View File
@@ -0,0 +1,101 @@
require 'simplecov'
SimpleCov.start
require_relative '../.env'
ENV["DB_NAME"] = "test_#{ENV["DB_NAME"]}"
require_relative '../app'
require 'rubygems'
require 'roda'
require 'sequel'
require 'rspec'
require 'rack/test'
# DB initialization
Sequel.extension :migration
Sequel.sqlite("db/#{ENV['DB_NAME']}") do |db|
Sequel::Migrator.apply(db, "db/migrations")
end
def app
App
end
describe "Submit API request to create new link" do
include Rack::Test::Methods
before :each do
@links = Sequel.sqlite("db/#{ENV['DB_NAME']}")[:links]
end
after :each do
@links.delete
end
it "should return link data in json format when a valid url is submitted" do
data = {
url: 'http://google.com'
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
expect(last_response).to be_ok
response_json = JSON.parse(last_response.body)
expect(response_json['url']).to eq(data[:url])
expect(response_json['code']).not_to eq(nil)
expect(response_json['link']).to include(response_json['code'])
end
it "should return with a 400 status and 'invalid url parameter' message when an empty url is submitted" do
data = {
url: ''
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('invalid url parameter')
end
it "should return with a 400 status and 'missing url parameter' message when an empty url is submitted" do
data = {
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('missing url parameter')
end
it "should return with a 400 status and 'invalid url parameter' message when an invalid url is submitted" do
data = {
url: 'not-an-url'
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('invalid url parameter')
end
it "should return with a 400 status and 'url not found' message when a 404 url is submitted" do
data = {
url: 'http://google.com/example'
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('url not found')
end
it "should return with a 400 status and 'url not found' message when a URL with no DNS is submitted" do
data = {
url: 'http://bad.tld'
}
post('/links', data.to_json, "CONTENT_TYPE" => "application/json")
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('url does not resolve')
end
it "should return with a 400 status and 'not a valid json request' message when a request is made with the wrong content type header" do
data = {
url: 'http://google.com'
}
post('/links', data.to_json)
expect(last_response.status).to eq(400)
response_json = JSON.parse(last_response.body)
expect(response_json['message']).to eq('not a valid json request')
end
end