From 1d14839ee3c83b75f6ec65d1d0429309ebaad5a6 Mon Sep 17 00:00:00 2001 From: Eli <9064062+snood1205@users.noreply.github.com> Date: Thu, 6 Mar 2025 17:47:16 -0500 Subject: [PATCH] Testing --- .github/workflows/rspec.yml | 37 ++++++++++++++++++ .gitignore | 1 + .rspec | 1 + .rubocop.yml | 4 ++ Gemfile | 23 ++++++++++-- Gemfile.lock | 75 +++++++++++++++++++++++++++++++++++++ setup.sql | 6 +-- spec/app_spec.rb | 18 +++++++++ spec/factories/api_key.rb | 13 +++++++ spec/factories/domain.rb | 12 ++++++ spec/factories/request.rb | 8 ++++ spec/spec_helper.rb | 63 +++++++++++++++++++++++++++++++ src/app.rb | 5 +-- 13 files changed, 256 insertions(+), 10 deletions(-) create mode 100644 .github/workflows/rspec.yml create mode 100644 .rspec create mode 100644 spec/app_spec.rb create mode 100644 spec/factories/api_key.rb create mode 100644 spec/factories/domain.rb create mode 100644 spec/factories/request.rb create mode 100644 spec/spec_helper.rb diff --git a/.github/workflows/rspec.yml b/.github/workflows/rspec.yml new file mode 100644 index 0000000..658d334 --- /dev/null +++ b/.github/workflows/rspec.yml @@ -0,0 +1,37 @@ +name: Run RSpec tests +on: + push: + pull_request: + + +jobs: + run-rspec-tests: + services: + postgres: + image: postgres:15 + env: + POSTGRES_DB: test_db + POSTGRES_USER: test_user + POSTGRES_PASSWORD: test_password + ports: + - 5432:5432 + + runs-on: ubuntu-latest + + env: + RACK_ENV: test + DB_NAME: test_db + DB_USER: test_user + DB_PASSWORD: test_password + DB_HOST: postgres + + steps: + - uses: actions/checkout@v4 + - name: Set up Ruby + uses: ruby/setup-ruby@v1 + with: + bundler-cache: true + - name: Install deps + run: bundle install + - name: Run specs + run: bundle exec rspec diff --git a/.gitignore b/.gitignore index c100aa7..c836770 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.env .env* *.log diff --git a/.rspec b/.rspec new file mode 100644 index 0000000..c99d2e7 --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--require spec_helper diff --git a/.rubocop.yml b/.rubocop.yml index 04e448a..12cefcc 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,7 @@ +plugins: + - rubocop-rspec + - rubocop-factory_bot + AllCops: NewCops: enable TargetRubyVersion: 3.4 diff --git a/Gemfile b/Gemfile index db0679d..f137d51 100644 --- a/Gemfile +++ b/Gemfile @@ -5,11 +5,26 @@ source 'https://rubygems.org' ruby file: '.ruby-version' gem 'dotenv' +gem 'logger', '~> 1.6' gem 'pg' -gem 'rubocop', '~> 1.72', group: :development -gem 'sinatra' - gem 'puma', '~> 6.6' gem 'rackup', '~> 2.2' +gem 'sinatra' -gem 'logger', '~> 1.6' +group :development do + gem 'rubocop', '~> 1.72', require: false + gem 'rubocop-factory_bot', require: false + gem 'rubocop-rspec', require: false +end + +group :development, :test do + gem 'pry' +end + +group :test do + gem 'activerecord' + gem 'database_cleaner' + gem 'factory_bot' + gem 'rack-test' + gem 'rspec' +end diff --git a/Gemfile.lock b/Gemfile.lock index 6cc6ece..dfa20f7 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,13 +1,51 @@ GEM remote: https://rubygems.org/ specs: + activemodel (8.0.1) + activesupport (= 8.0.1) + activerecord (8.0.1) + activemodel (= 8.0.1) + activesupport (= 8.0.1) + timeout (>= 0.4.0) + activesupport (8.0.1) + base64 + benchmark (>= 0.3) + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb + i18n (>= 1.6, < 2) + logger (>= 1.4.2) + minitest (>= 5.1) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + uri (>= 0.13.1) ast (2.4.2) base64 (0.2.0) + benchmark (0.4.0) + bigdecimal (3.1.9) + coderay (1.1.3) + concurrent-ruby (1.3.5) + connection_pool (2.5.0) + database_cleaner (2.1.0) + database_cleaner-active_record (>= 2, < 3) + database_cleaner-active_record (2.2.0) + activerecord (>= 5.a) + database_cleaner-core (~> 2.0.0) + database_cleaner-core (2.0.1) + diff-lcs (1.6.0) dotenv (3.1.7) + drb (2.2.1) + factory_bot (6.5.1) + activesupport (>= 6.1.0) + i18n (1.14.7) + concurrent-ruby (~> 1.0) json (2.10.1) language_server-protocol (3.17.0.4) lint_roller (1.1.0) logger (1.6.6) + method_source (1.1.0) + minitest (5.25.4) mustermann (3.0.3) ruby2_keywords (~> 0.0.1) nio4r (2.7.4) @@ -16,6 +54,9 @@ GEM ast (~> 2.4.1) racc pg (1.5.9) + pry (0.15.2) + coderay (~> 1.1) + method_source (~> 1.0) puma (6.6.0) nio4r (~> 2.0) racc (1.8.1) @@ -27,10 +68,25 @@ GEM rack-session (2.1.0) base64 (>= 0.1.0) rack (>= 3.0.0) + rack-test (2.2.0) + rack (>= 1.3) rackup (2.2.1) rack (>= 3) rainbow (3.1.1) regexp_parser (2.10.0) + rspec (3.13.0) + rspec-core (~> 3.13.0) + rspec-expectations (~> 3.13.0) + rspec-mocks (~> 3.13.0) + rspec-core (3.13.3) + rspec-support (~> 3.13.0) + rspec-expectations (3.13.3) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-mocks (3.13.2) + diff-lcs (>= 1.2.0, < 2.0) + rspec-support (~> 3.13.0) + rspec-support (3.13.2) rubocop (1.73.2) json (~> 2.3) language_server-protocol (~> 3.17.0.2) @@ -44,8 +100,15 @@ GEM unicode-display_width (>= 2.4.0, < 4.0) rubocop-ast (1.38.1) parser (>= 3.3.1.0) + rubocop-factory_bot (2.27.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) + rubocop-rspec (3.5.0) + lint_roller (~> 1.1) + rubocop (~> 1.72, >= 1.72.1) ruby-progressbar (1.13.0) ruby2_keywords (0.0.5) + securerandom (0.4.1) sinatra (4.1.1) logger (>= 1.6.0) mustermann (~> 3.0) @@ -54,21 +117,33 @@ GEM rack-session (>= 2.0.0, < 3) tilt (~> 2.0) tilt (2.6.0) + timeout (0.4.3) + tzinfo (2.0.6) + concurrent-ruby (~> 1.0) unicode-display_width (3.1.4) unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) + uri (1.0.3) PLATFORMS arm64-darwin-24 ruby DEPENDENCIES + activerecord + database_cleaner dotenv + factory_bot logger (~> 1.6) pg + pry puma (~> 6.6) + rack-test rackup (~> 2.2) + rspec rubocop (~> 1.72) + rubocop-factory_bot + rubocop-rspec sinatra RUBY VERSION diff --git a/setup.sql b/setup.sql index 69a7de8..cb2daed 100644 --- a/setup.sql +++ b/setup.sql @@ -1,7 +1,7 @@ CREATE TABLE domains ( id SERIAL PRIMARY KEY, - domain VARCHAR(255) UNIQUE NOT NULL, creation_date TIMESTAMPTZ NOT NULL, + domain VARCHAR(255) UNIQUE NOT NULL, expiration_date TIMESTAMPTZ NOT NULL ); @@ -9,10 +9,10 @@ CREATE INDEX idx_domains_domain ON domains(domain); CREATE TABLE api_keys ( id SERIAL PRIMARY KEY, + api_key TEXT NOT NULL UNIQUE, email TEXT NOT NULL UNIQUE, - validation_code TEXT, email_verified BOOLEAN DEFAULT FALSE, - api_key TEXT NOT NULL UNIQUE + validation_code TEXT ); CREATE INDEX idx_api_keys_api_key ON api_keys(api_key); diff --git a/spec/app_spec.rb b/spec/app_spec.rb new file mode 100644 index 0000000..931954d --- /dev/null +++ b/spec/app_spec.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe App do + let(:api_key) { create(:api_key) } + let(:domain) { create(:domain) } + + describe 'GET /get-info' do + context 'when the request is valid' do + before { get '/get-info', { domain: domain.domain, api_key: api_key.api_key } } + + it { expect(last_response.status).to eq 200 } + it { expect(JSON.parse(last_response.body)['creation_date']).to eq domain.creation_date } + it { expect(JSON.parse(last_response.body)['expiration_date']).to eq domain.expiration_date } + end + end +end diff --git a/spec/factories/api_key.rb b/spec/factories/api_key.rb new file mode 100644 index 0000000..ebbdd74 --- /dev/null +++ b/spec/factories/api_key.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :api_key do + api_key { 'abcdef01-2345-6789-0abc-def012345678' } + email { 'test@example.com' } + validation_code { 'ABC123' } + email_verified { true } + trait :unverified do + email_verified { false } + end + end +end diff --git a/spec/factories/domain.rb b/spec/factories/domain.rb new file mode 100644 index 0000000..d24eb0e --- /dev/null +++ b/spec/factories/domain.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :domain do + domain { 'gitgetgot.dev' } + creation_date { DateTime.now - 365 } + expiration_date { creation_date + 730 } + trait :expired do + expiration_date { creation_date + 364 } + end + end +end diff --git a/spec/factories/request.rb b/spec/factories/request.rb new file mode 100644 index 0000000..f1774d6 --- /dev/null +++ b/spec/factories/request.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +FactoryBot.define do + factory :request do + api_key { association(:api_key) } + time { DateTime.now } + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..0aa0ffe --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,63 @@ +# frozen_string_literal: true + +ENV['RACK_ENV'] = 'test' + +require_relative '../src/app' + +require 'active_record' +require 'database_cleaner/active_record' +require 'dotenv' +require 'factory_bot' +require 'json' +require 'pry' +require 'rack/test' +require 'rspec' + +Dotenv.load '.env.test' + +ActiveRecord::Base.establish_connection \ + adapter: 'postgresql', + database: ENV.fetch('DB_NAME'), + username: ENV.fetch('DB_USER'), + password: ENV.fetch('DB_PASSWORD', ''), + host: ENV.fetch('DB_HOST', 'localhost') + +class ApiKey < ActiveRecord::Base; end +class Domain < ActiveRecord::Base; end +class Request < ActiveRecord::Base; end + +module Rack::Test::Methods + def build_rack_mock_session + Rack::MockSession.new app, 'whois.gitgetgot.dev' + end +end + +RSpec.configure do |config| + config.include Rack::Test::Methods + config.include FactoryBot::Syntax::Methods + + def app + App + end + + config.before :suite do + FactoryBot.find_definitions + DatabaseCleaner[:active_record].strategy = :truncation + DatabaseCleaner[:active_record].clean_with(:truncation) + end + + config.around do |ex| + DatabaseCleaner[:active_record].cleaning { ex.run } + end + + config.expect_with :rspec do |expectations| + expectations.include_chain_clauses_in_custom_matcher_descriptions = true + end + config.mock_with :rspec do |mocks| + mocks.verify_partial_doubles = true + end + config.shared_context_metadata_behavior = :apply_to_host_groups + config.warnings = true + config.order = :random + Kernel.srand config.seed +end diff --git a/src/app.rb b/src/app.rb index 9a982b3..6da87f0 100644 --- a/src/app.rb +++ b/src/app.rb @@ -1,8 +1,8 @@ # frozen_string_literal: true -require 'sinatra/base' -require 'pg' require 'dotenv/load' +require 'pg' +require 'sinatra/base' require_relative 'clients/authentication_client' require_relative 'clients/db_client' require_relative 'clients/whois_client' @@ -28,7 +28,6 @@ class App < Sinatra::Base set :host_authorization, { permitted_hosts: %w[whois.gitgetgot.dev localhost 127.0.0.1] } end - before { puts "Request Host: #{request.host}" } get '/get-info' do handle_errors do