-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
337 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,20 +1,93 @@ | ||
# lib/tasks/readyset.rake | ||
require 'colorize' | ||
require 'erb' | ||
require 'progressbar' | ||
require 'terminal-table' | ||
|
||
namespace :readyset do | ||
desc 'Creates caches for all of the supported queries on ReadySet' | ||
task cache_supported_queries: :environment do | ||
Readyset::Query.cache_all_supported! | ||
desc 'Prints a list of all the queries that ReadySet has proxied' | ||
task proxied_queries: :environment do | ||
Rails.application.eager_load! | ||
|
||
rows = Readyset::Query::ProxiedQuery.all.map do |q| | ||
[q.id, q.text, q.supported, q.count] | ||
end | ||
table = Terminal::Table.new(headings: [:id, :text, :supported, :count], rows: rows) | ||
|
||
puts table | ||
end | ||
|
||
desc 'Drops all the caches on ReadySet' | ||
task drop_all_caches: :environment do | ||
Readyset::Query.drop_all_caches! | ||
namespace :proxied_queries do | ||
desc 'Creates caches for all of the supported queries on ReadySet' | ||
task cache_all_supported: :environment do | ||
Rails.application.eager_load! | ||
|
||
Readyset::Query::ProxiedQuery.cache_all_supported! | ||
end | ||
|
||
desc 'Clears the list of proxied queries on ReadySet' | ||
task drop_all: :environment do | ||
Rails.application.eager_load! | ||
|
||
Readyset.raw_query('DROP ALL PROXIED QUERIES') | ||
end | ||
end | ||
|
||
desc 'Prints a list of all the cached queries on ReadySet' | ||
task all_caches: :environment do | ||
Readyset::Query.all_cached.each do |query| | ||
puts query.inspect | ||
task caches: :environment do | ||
Rails.application.eager_load! | ||
|
||
rows = Readyset::Query::CachedQuery.all.map do |q| | ||
[q.id, q.name, q.text, q.always, q.count] | ||
end | ||
table = Terminal::Table.new(headings: [:id, :name, :text, :always, :count], rows: rows) | ||
|
||
puts table | ||
end | ||
|
||
namespace :caches do | ||
desc 'Drops the cache with the given name' | ||
task :drop, [:name] => :environment do |_, args| | ||
Rails.application.eager_load! | ||
|
||
if args.first | ||
Readyset.drop_cache!(args.first) | ||
else | ||
puts 'A cache name must be passed to this task' | ||
end | ||
end | ||
|
||
desc 'Drops all the caches on ReadySet' | ||
task drop_all: :environment do | ||
Rails.application.eager_load! | ||
|
||
Readyset::Query::CachedQuery.drop_all! | ||
end | ||
|
||
desc 'Dumps the set of caches that currently exist on ReadySet to a file' | ||
task dump: :environment do | ||
Rails.application.eager_load! | ||
end | ||
end | ||
|
||
desc 'Prints status information about ReadySet' | ||
task status: :environment do | ||
Rails.application.eager_load! | ||
|
||
rows = Readyset.raw_query('SHOW READYSET STATUS'). | ||
map { |result| [result['name'], result['value']] } | ||
table = Terminal::Table.new(rows: rows) | ||
|
||
puts table | ||
end | ||
|
||
desc 'Prints information about the tables known to ReadySet' | ||
task tables: :environment do | ||
Rails.application.eager_load! | ||
|
||
rows = Readyset.raw_query('SHOW READYSET TABLES'). | ||
map { |result| [result['table'], result['status'], result['description']] } | ||
table = Terminal::Table.new(headings: [:table, :status, :description], rows: rows) | ||
|
||
puts table | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
require 'colorize' | ||
require 'rake' | ||
require 'spec_helper' | ||
|
||
load './lib/tasks/readyset.rake' | ||
|
||
RSpec.describe 'readyset.rake' do | ||
before do | ||
Rake::Task.define_task(:environment) | ||
end | ||
|
||
describe 'readyset' do | ||
describe 'caches' do | ||
it 'prints a table with the caches that currently exist on ReadySet' do | ||
build_and_create_cache(:cached_query) | ||
|
||
expected_message = <<~TABLE | ||
+--------------------+--------------------+---------------------------------+--------+-------+ | ||
| id | name | text | always | count | | ||
+--------------------+--------------------+---------------------------------+--------+-------+ | ||
| q_4f3fb9ad8f73bc0c | q_4f3fb9ad8f73bc0c | SELECT | false | 0 | | ||
| | | "public"."cats"."breed" | | | | ||
| | | FROM | | | | ||
| | | "public"."cats" | | | | ||
| | | WHERE | | | | ||
| | | ("public"."cats"."name" = $1) | | | | ||
+--------------------+--------------------+---------------------------------+--------+-------+ | ||
TABLE | ||
expect { Rake::Task['readyset:caches'].execute }.to output(expected_message).to_stdout | ||
end | ||
|
||
describe 'drop' do | ||
context 'when given a cache name as an argument' do | ||
it 'removes the cache with the given name' do | ||
cache = build_and_create_cache(:cached_query) | ||
|
||
Rake::Task['readyset:caches:drop'].execute([cache.id]) | ||
|
||
caches = Readyset::Query::CachedQuery.all | ||
expect(caches.size).to eq(0) | ||
end | ||
end | ||
|
||
context 'when given no arguments' do | ||
it 'prints an error message' do | ||
expect { Rake::Task['readyset:caches:drop'].execute }. | ||
to output("A cache name must be passed to this task\n").to_stdout | ||
end | ||
end | ||
end | ||
|
||
describe 'drop_all' do | ||
it 'removes the cache with the given name' do | ||
build_and_create_cache(:cached_query) | ||
build_and_create_cache(:cached_query_2) | ||
|
||
Rake::Task['readyset:caches:drop_all'].execute | ||
|
||
caches = Readyset::Query::CachedQuery.all | ||
expect(caches.size).to eq(0) | ||
end | ||
end | ||
|
||
describe 'dump' do | ||
it 'dumps the current set of caches to a migration file' do | ||
cache_1 = build_and_create_cache(:cached_query) | ||
cache_2 = build_and_create_cache(:cached_query_2) | ||
|
||
Rake::Task['readyset:caches:dump'].execute | ||
|
||
load './spec/internal/db/readyset_caches.rb' | ||
subclasses = Readyset::Caches.subclasses | ||
expect(subclasses.size).to eq(1) | ||
|
||
caches = subclasses.first.caches.to_a | ||
caches.sort_by!(&:id) | ||
|
||
expect(caches.first.always).to eq(cache_1.always) | ||
expect(caches.first.text).to eq(cache_1.text) | ||
expect(caches.second.always).to eq(cache_2.always) | ||
expect(caches.second.text).to eq(cache_2.text) | ||
end | ||
end | ||
|
||
describe 'migrate' do | ||
after(:each) do | ||
if File.exist?('./spec/internal/db/readyset_caches.rb') | ||
File.delete('./spec/internal/db/readyset_caches.rb') | ||
end | ||
end | ||
|
||
context "when the migration file contains caches that don't exist on ReadySet" do | ||
it "creates the caches in the migration file that don't exist on ReadySet" do | ||
# Setup | ||
cache_to_create = build(:cached_query_2) | ||
generate_migration_file([build(:cached_query), cache_to_create]) | ||
|
||
allow(Readyset::Query::CachedQuery).to receive(:all).and_return([build(:cached_query)]) | ||
allow(Readyset).to receive(:create_cache!).with(id: cache_to_create.id) | ||
allow(STDIN).to receive(:gets).and_return("y\n") | ||
|
||
# Execute | ||
Rake::Task['readyset:caches:migrate'].execute | ||
|
||
# Verify | ||
expect(Readyset).to have_received(:create_cache!).with(id: cache_to_create.id) | ||
end | ||
|
||
it 'prints the expected output' do | ||
# Setup | ||
cache_to_create = build(:cached_query_2) | ||
generate_migration_file([build(:cached_query), cache_to_create]) | ||
|
||
allow(Readyset::Query::CachedQuery).to receive(:all).and_return([build(:cached_query)]) | ||
allow(Readyset).to receive(:create_cache!).with(id: cache_to_create.id) | ||
allow(STDIN).to receive(:gets).and_return("y\n") | ||
|
||
# Execute + Verify | ||
expected_message = "#{'Dropping'.red} 0 caches and #{'creating'.green} 1 caches. " \ | ||
'Continue? (y/n) ' | ||
expect { Rake::Task['readyset:caches:migrate'].execute }.to output(expected_message). | ||
to_stdout | ||
end | ||
end | ||
|
||
context "when ReadySet has caches that don't exist in the migration file" do | ||
it 'drops the caches that exist on ReadySet that are not in the migration file' do | ||
# Setup | ||
generate_migration_file([build(:cached_query)]) | ||
|
||
cache_to_drop = build(:cached_query_2) | ||
allow(Readyset::Query::CachedQuery).to receive(:all). | ||
and_return([build(:cached_query), cache_to_drop]) | ||
allow(Readyset).to receive(:drop_cache!).with(name_or_id: cache_to_drop.id) | ||
allow(STDIN).to receive(:gets).and_return("y\n") | ||
|
||
# Execute | ||
Rake::Task['readyset:caches:migrate'].execute | ||
|
||
# Verify | ||
expect(Readyset).to have_received(:drop_cache!).with(name_or_id: cache_to_drop.id) | ||
end | ||
|
||
it 'prints the expected output' do | ||
# Setup | ||
generate_migration_file([build(:cached_query)]) | ||
|
||
cache_to_drop = build(:cached_query_2) | ||
allow(Readyset::Query::CachedQuery).to receive(:all). | ||
and_return([build(:cached_query), cache_to_drop]) | ||
allow(Readyset).to receive(:drop_cache!).with(name_or_id: cache_to_drop.id) | ||
allow(STDIN).to receive(:gets).and_return("y\n") | ||
|
||
# Execute + Verify | ||
expected_message = "#{'Dropping'.red} 1 caches and #{'creating'.green} 0 caches. " \ | ||
'Continue? (y/n) ' | ||
expect { Rake::Task['readyset:caches:migrate'].execute }.to output(expected_message). | ||
to_stdout | ||
end | ||
end | ||
|
||
def generate_migration_file(caches) | ||
allow(Readyset::Query::CachedQuery).to receive(:all).and_return(caches) | ||
Rake::Task['readyset:caches:dump'].execute | ||
allow(Readyset::Query::CachedQuery).to receive(:all).and_call_original | ||
end | ||
end | ||
end | ||
|
||
describe 'proxied_queries' do | ||
it 'prints a table with the queries that ReadySet has proxied' do | ||
build_and_execute_proxied_query(:proxied_query) | ||
|
||
expected_message = Regexp.new <<~TABLE | ||
\\+--------------------\\+------------------------\\+-----------\\+-------\\+ | ||
\\| id \\| text \\| supported \\| count \\| | ||
\\+--------------------\\+------------------------\\+-----------\\+-------\\+ | ||
\\| q_4f3fb9ad8f73bc0c \\| SELECT \\| pending \\| \\d+[ ]*\\| | ||
\\| \\| "cats"\\."breed" \\| \\| [ ]*\\| | ||
\\| \\| FROM \\| \\| [ ]*\\| | ||
\\| \\| "cats" \\| \\| [ ]*\\| | ||
\\| \\| WHERE \\| \\| [ ]*\\| | ||
\\| \\| \\("cats"\\."name" = \\$1\\) \\| \\| [ ]*\\| | ||
\\+--------------------\\+------------------------\\+-----------\\+-------\\+ | ||
TABLE | ||
expect { Rake::Task['readyset:proxied_queries'].execute }.to output(expected_message). | ||
to_stdout | ||
end | ||
|
||
describe 'cache_all_supported' do | ||
it 'creates caches for all queries proxied by ReadySet that are supported to be cached' do | ||
build_and_execute_proxied_query(:proxied_query) | ||
build_and_execute_proxied_query(:unsupported_proxied_query) | ||
|
||
eventually do | ||
Readyset::Query::ProxiedQuery.all.all? { |query| query.supported != :pending } | ||
end | ||
|
||
Rake::Task['readyset:proxied_queries:cache_all_supported'].execute | ||
|
||
expect(Readyset::Query::CachedQuery.all).to eq([build(:cached_query)]) | ||
end | ||
end | ||
|
||
describe 'drop_all' do | ||
it 'clears the list of proxied queries on ReadySet' do | ||
build_and_execute_proxied_query(:proxied_query) | ||
build_and_execute_proxied_query(:proxied_query_2) | ||
|
||
Rake::Task['readyset:proxied_queries:drop_all'].execute | ||
|
||
proxied = Readyset::Query::ProxiedQuery.all | ||
expect(proxied).to be_empty | ||
end | ||
end | ||
end | ||
|
||
describe 'status' do | ||
it "prints a table that shows ReadySet's status" do | ||
expected_message = Regexp.new <<~TABLE | ||
\\+----------------------------\\+------------------------\\+ | ||
\\| Database Connection \\| Connected[ ]*\\| | ||
\\| Connection Count \\| \\d+[ ]*\\| | ||
\\| Snapshot Status \\| Completed[ ]*\\| | ||
\\| Maximum Replication Offset \\| \\([0-9A-F]{1,8}\\/[0-9A-F]{1,8}, [0-9A-F]{1,8}\\/[0-9A-F]{1,8}\\) \\| | ||
\\| Minimum Replication Offset \\| \\([0-9A-F]{1,8}\\/[0-9A-F]{1,8}, [0-9A-F]{1,8}\\/[0-9A-F]{1,8}\\) \\| | ||
\\| Last started Controller \\| \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}[ ]*\\| | ||
\\| Last completed snapshot \\| \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}[ ]*\\| | ||
\\| Last started replication \\| \\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}[ ]*\\| | ||
\\+----------------------------\\+------------------------\\+ | ||
TABLE | ||
expect { Rake::Task['readyset:status'].execute }.to output(expected_message). | ||
to_stdout | ||
end | ||
end | ||
|
||
describe 'tables' do | ||
it 'prints a table that shows the tables known to ReadySet' do | ||
expected_message = Regexp.new <<~TABLE | ||
\\+---------------------------------\\+-------------\\+-------------\\+ | ||
\\| table \\| status \\| description \\| | ||
\\+---------------------------------\\+-------------\\+-------------\\+ | ||
(\\| "public"\\."[\\w]*"[ ]*\\| Snapshotted \\| \\|\n?)* | ||
\\+---------------------------------\\+-------------\\+-------------\\+ | ||
TABLE | ||
|
||
expect { Rake::Task['readyset:tables'].execute }.to output(expected_message). | ||
to_stdout | ||
end | ||
end | ||
end | ||
end |
Oops, something went wrong.