txdb 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +202 -0
  3. data/README.md +39 -0
  4. data/lib/txdb.rb +32 -0
  5. data/lib/txdb/app.rb +36 -0
  6. data/lib/txdb/backends.rb +19 -0
  7. data/lib/txdb/backends/globalize.rb +10 -0
  8. data/lib/txdb/backends/globalize/backend.rb +19 -0
  9. data/lib/txdb/backends/globalize/helpers.rb +19 -0
  10. data/lib/txdb/backends/globalize/reader.rb +63 -0
  11. data/lib/txdb/backends/globalize/writer.rb +39 -0
  12. data/lib/txdb/config.rb +52 -0
  13. data/lib/txdb/connection_string.rb +18 -0
  14. data/lib/txdb/database.rb +40 -0
  15. data/lib/txdb/downloader.rb +32 -0
  16. data/lib/txdb/handlers.rb +6 -0
  17. data/lib/txdb/handlers/hook_handler.rb +59 -0
  18. data/lib/txdb/handlers/triggers.rb +9 -0
  19. data/lib/txdb/handlers/triggers/handler.rb +50 -0
  20. data/lib/txdb/handlers/triggers/pull_handler.rb +34 -0
  21. data/lib/txdb/handlers/triggers/push_handler.rb +19 -0
  22. data/lib/txdb/response.rb +11 -0
  23. data/lib/txdb/response_helpers.rb +26 -0
  24. data/lib/txdb/table.rb +36 -0
  25. data/lib/txdb/transifex_project.rb +17 -0
  26. data/lib/txdb/tx_resource.rb +52 -0
  27. data/lib/txdb/uploader.rb +33 -0
  28. data/lib/txdb/version.rb +3 -0
  29. data/spec/backends/globalize/helpers_spec.rb +17 -0
  30. data/spec/backends/globalize/reader_spec.rb +25 -0
  31. data/spec/backends/globalize/writer_spec.rb +53 -0
  32. data/spec/backends_spec.rb +30 -0
  33. data/spec/config_spec.rb +71 -0
  34. data/spec/connection_string_spec.rb +24 -0
  35. data/spec/database_spec.rb +33 -0
  36. data/spec/downloader_spec.rb +36 -0
  37. data/spec/handlers/hook_handler_spec.rb +73 -0
  38. data/spec/handlers/triggers/pull_handler_spec.rb +58 -0
  39. data/spec/handlers/triggers/push_handler_spec.rb +49 -0
  40. data/spec/spec_helper.rb +20 -0
  41. data/spec/spec_helpers/env_helpers.rb +13 -0
  42. data/spec/spec_helpers/globalize_db.rb +60 -0
  43. data/spec/spec_helpers/test_backend.rb +28 -0
  44. data/spec/spec_helpers/test_db.rb +76 -0
  45. data/spec/table_spec.rb +58 -0
  46. data/spec/test.sqlite3 +0 -0
  47. data/spec/transifex_project_spec.rb +15 -0
  48. data/spec/tx_resource_spec.rb +17 -0
  49. data/spec/uploader_spec.rb +36 -0
  50. data/txdb.gemspec +22 -0
  51. metadata +134 -0
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'spec_helpers/test_backend'
3
+ require 'spec_helpers/test_db'
4
+ require 'uri'
5
+ require 'yaml'
6
+
7
+ include Txdb::Handlers::Triggers
8
+
9
+ describe PullHandler do
10
+ include Rack::Test::Methods
11
+
12
+ let(:database) { TestDb.database }
13
+ let(:table) { database.tables.first }
14
+ let(:project) { database.transifex_project }
15
+
16
+ def app
17
+ Txdb::Triggers
18
+ end
19
+
20
+ before(:each) do
21
+ allow(Txdb::Config).to receive(:databases).and_return([database])
22
+ end
23
+
24
+ let(:params) do
25
+ { 'database' => database.database, 'table' => table.name }
26
+ end
27
+
28
+ it 'downloads the table for each locale' do
29
+ locales = [{ 'language_code' => 'es' }, { 'language_code' => 'ja' }]
30
+ content = { 'phrase' => 'trans' }
31
+ expect(database.transifex_api).to receive(:get_languages).and_return(locales)
32
+ allow(database.transifex_api).to receive(:download).and_return(YAML.dump(content))
33
+
34
+ expect { patch('/pull', params) }.to(
35
+ change { Txdb::TestBackend.writes.size }.from(0).to(2)
36
+ )
37
+
38
+ expect(last_response.status).to eq(200)
39
+ expect(last_response.body).to eq('{}')
40
+
41
+ expect(Txdb::TestBackend.writes).to include(
42
+ locale: 'es', table: table.name, content: content
43
+ )
44
+
45
+ expect(Txdb::TestBackend.writes).to include(
46
+ locale: 'ja', table: table.name, content: content
47
+ )
48
+ end
49
+
50
+ it 'reports errors' do
51
+ expect(database.transifex_api).to receive(:get_languages).and_raise('jelly beans')
52
+ patch '/pull', params
53
+ expect(last_response.status).to eq(500)
54
+ expect(JSON.parse(last_response.body)).to eq(
55
+ [{ 'error' => 'Internal server error: jelly beans' }]
56
+ )
57
+ end
58
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+ require 'spec_helpers/test_backend'
3
+ require 'spec_helpers/test_db'
4
+ require 'uri'
5
+ require 'yaml'
6
+
7
+ include Txdb::Handlers::Triggers
8
+
9
+ describe PushHandler do
10
+ include Rack::Test::Methods
11
+
12
+ let(:database) { TestDb.database }
13
+ let(:table) { database.tables.first }
14
+ let(:project) { database.transifex_project }
15
+
16
+ def app
17
+ Txdb::Triggers
18
+ end
19
+
20
+ before(:each) do
21
+ allow(Txdb::Config).to receive(:databases).and_return([database])
22
+ end
23
+
24
+ let(:params) do
25
+ { 'database' => database.database, 'table' => table.name }
26
+ end
27
+
28
+ it 'uploads the table' do
29
+ expect(database.transifex_api).to receive(:create_or_update)
30
+
31
+ expect { patch('/push', params) }.to(
32
+ change { Txdb::TestBackend.reads.size }.from(0).to(1)
33
+ )
34
+
35
+ expect(last_response.status).to eq(200)
36
+ expect(last_response.body).to eq('{}')
37
+
38
+ expect(Txdb::TestBackend.reads).to include(table: table.name)
39
+ end
40
+
41
+ it 'reports errors' do
42
+ expect(database.transifex_api).to receive(:create_or_update).and_raise('jelly beans')
43
+ patch '/push', params
44
+ expect(last_response.status).to eq(500)
45
+ expect(JSON.parse(last_response.body)).to eq(
46
+ [{ 'error' => 'Internal server error: jelly beans' }]
47
+ )
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ require 'pry-byebug'
2
+ require 'rack/test'
3
+ require 'rake'
4
+ require 'rspec'
5
+ require 'sequel'
6
+ require 'sqlite3'
7
+ require 'txdb'
8
+
9
+ require 'spec_helpers/env_helpers'
10
+ require 'spec_helpers/test_backend'
11
+
12
+ RSpec.configure do |config|
13
+ config.before(:each) do
14
+ Txdb::TestBackend.reset
15
+ end
16
+
17
+ config.include(EnvHelpers)
18
+ end
19
+
20
+ Txdb::Backends.register('test-backend', Txdb::TestBackend)
@@ -0,0 +1,13 @@
1
+ module EnvHelpers
2
+ def with_env(env)
3
+ # ENV can't be duped, so use select instead to make a copy
4
+ old_env = ENV.select { true }
5
+ env.each_pair { |k, v| ENV[k] = v }
6
+ yield
7
+ ensure
8
+ # reset back to old vars
9
+ env.each_pair { |k, _| ENV[k] = old_env[k] }
10
+ end
11
+ end
12
+
13
+ EnvHelpers.extend(EnvHelpers)
@@ -0,0 +1,60 @@
1
+ require 'spec_helpers/test_db'
2
+
3
+ class GlobalizeDb < TestDb
4
+ class << self
5
+ def database
6
+ @database ||= Txdb::Database.new(
7
+ raw_config[:databases].first.merge(
8
+ backend: Txdb::Backends.get('globalize'),
9
+ tables: [{
10
+ name: 'widget_translations',
11
+ source_lang: 'en',
12
+ columns: %w(name)
13
+ }]
14
+ )
15
+ )
16
+ end
17
+
18
+ def setup_db
19
+ db.create_table(:widgets) do
20
+ primary_key :id
21
+ string :name
22
+ end
23
+
24
+ db.create_table(:widget_translations) do
25
+ primary_key :id
26
+ integer :widget_id
27
+ string :locale
28
+ string :name
29
+ end
30
+ end
31
+
32
+ def widgets
33
+ db[:widgets]
34
+ end
35
+
36
+ def widget_translations
37
+ db[:widget_translations]
38
+ end
39
+
40
+ def widget_translations_table
41
+ database.tables.find do |table|
42
+ table.name == 'widget_translations'
43
+ end
44
+ end
45
+ end
46
+ end
47
+
48
+ RSpec.shared_context(:globalize) do
49
+ let(:widgets) { GlobalizeDb.widgets }
50
+ let(:widget_translations) { GlobalizeDb.widget_translations }
51
+ let(:widget_translations_table) { GlobalizeDb.widget_translations_table }
52
+ let(:database) { GlobalizeDb.database }
53
+ end
54
+
55
+ RSpec.configure do |config|
56
+ config.around(:each) do |example|
57
+ GlobalizeDb.reset_db if example.metadata[:globalize_db]
58
+ example.run
59
+ end
60
+ end
@@ -0,0 +1,28 @@
1
+ module Txdb
2
+ class TestBackend
3
+ class << self
4
+ def reads
5
+ @reads ||= []
6
+ end
7
+
8
+ def writes
9
+ @writes ||= []
10
+ end
11
+
12
+ def reset
13
+ @reads = nil
14
+ @writes = nil
15
+ end
16
+
17
+ def read_content_from(table)
18
+ reads << { table: table.name }
19
+ {}
20
+ end
21
+
22
+ def write_content_to(table, content, locale)
23
+ writes << { table: table.name, content: content, locale: locale }
24
+ nil
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,76 @@
1
+ require 'spec_helpers/env_helpers'
2
+ require 'spec_helpers/test_backend'
3
+ require 'yaml'
4
+
5
+ class TestDb
6
+ class << self
7
+ def db
8
+ @db ||= database.db
9
+ end
10
+
11
+ def database
12
+ @database ||= Txdb::Database.new(raw_config[:databases].first)
13
+ end
14
+
15
+ def db_path
16
+ File.join(File.dirname(__FILE__), '../test.sqlite3')
17
+ end
18
+
19
+ def raw_config
20
+ @config ||= deep_freeze({
21
+ databases: [{
22
+ adapter: 'sqlite',
23
+ backend: 'test-backend',
24
+ username: 'username',
25
+ password: 'password',
26
+ database: 'spec/test.sqlite3',
27
+ transifex: {
28
+ organization: 'myorg',
29
+ project_slug: 'myproject',
30
+ username: 'username',
31
+ password: 'password',
32
+ webhook_secret: '123abc'
33
+ },
34
+ tables: [{
35
+ name: 'my_table',
36
+ source_lang: 'en',
37
+ columns: %w(my_column)
38
+ }]
39
+ }]
40
+ })
41
+ end
42
+
43
+ def reset_db
44
+ db.tables.each { |t| db.drop_table(t) }
45
+ setup_db
46
+ end
47
+
48
+ def setup_db
49
+ # no-op
50
+ end
51
+
52
+ private
53
+
54
+ def deep_freeze(obj)
55
+ case obj
56
+ when Hash
57
+ obj.each_with_object({}) do |(k, v), ret|
58
+ ret[k] = deep_freeze(v)
59
+ end.freeze
60
+
61
+ when Array
62
+ obj.map { |elem| deep_freeze(elem) }.freeze
63
+
64
+ else
65
+ obj
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ RSpec.configure do |config|
72
+ config.around(:each) do |example|
73
+ TestDb.reset_db if example.metadata[:test_db]
74
+ example.run
75
+ end
76
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'spec_helpers/test_db'
3
+ require 'yaml'
4
+
5
+ include Txdb
6
+
7
+ describe Table, test_db: true do
8
+ let(:database) { TestDb.database }
9
+ let(:table) { database.tables.first }
10
+
11
+ describe '#db' do
12
+ it 'returns a dataset primed to select from the table' do
13
+ expect(table.db).to be_a(Sequel::Dataset)
14
+ expect(table.db.sql).to eq('SELECT * FROM `my_table`')
15
+ end
16
+ end
17
+
18
+ describe '#resource' do
19
+ it 'creates a TxResource from the table' do
20
+ resource = table.resource
21
+ expect(resource).to be_a(Txdb::TxResource)
22
+ expect(resource.project_slug).to eq('myproject')
23
+ expect(resource.resource_slug).to eq(
24
+ Txgh::Utils.slugify("#{database.database}-#{table.name}")
25
+ )
26
+ expect(resource.source_file).to eq(table.name)
27
+ expect(resource.source_lang).to eq('en')
28
+ end
29
+ end
30
+
31
+ describe '#read_content' do
32
+ let(:content) { { foo: 'bar' } }
33
+
34
+ it 'dumps the content in YAML format' do
35
+ expect(database.backend).to(
36
+ receive(:read_content_from).and_return(content)
37
+ )
38
+
39
+ expect(table.read_content).to eq(YAML.dump(content))
40
+ end
41
+ end
42
+
43
+ describe '#write_content' do
44
+ let(:content) { { foo: 'bar' } }
45
+ let(:locale) { 'es' }
46
+
47
+ it 'parses and writes the content to the database' do
48
+ expect(database.backend).to(
49
+ receive(:write_content_to) do |_, cont, loc|
50
+ expect(cont).to eq(content)
51
+ expect(loc).to eq(locale)
52
+ end
53
+ )
54
+
55
+ table.write_content(YAML.dump(content), locale)
56
+ end
57
+ end
58
+ end
data/spec/test.sqlite3 ADDED
Binary file
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+ require 'spec_helpers/test_db'
3
+
4
+ include Txdb
5
+
6
+ describe TransifexProject, test_db: true do
7
+ let(:database) { TestDb.database }
8
+ let(:project) { database.transifex_project }
9
+
10
+ describe '#api' do
11
+ it 'returns a transifex api instance' do
12
+ expect(project.api).to be_a(Txgh::TransifexApi)
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec_helper'
2
+ require 'spec_helpers/test_db'
3
+
4
+ include Txdb
5
+
6
+ describe TxResource, test_db: true do
7
+ let(:database) { TestDb.database }
8
+ let(:table) { database.tables.first }
9
+ let(:resource) { table.resource }
10
+
11
+ it 'proxies methods to the underlying Txgh::TxResource' do
12
+ expect(resource.project_slug).to eq('myproject')
13
+ expect(resource.resource_slug).to(
14
+ eq(Txgh::Utils.slugify("#{database.database}-#{table.name}"))
15
+ )
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'spec_helpers/test_db'
3
+ require 'spec_helpers/test_backend'
4
+
5
+ include Txdb
6
+
7
+ describe Uploader, test_db: true do
8
+ let(:database) { Txdb::Config.databases.first }
9
+ let(:uploader) { Uploader.new(database) }
10
+ let(:transifex_api) { double(:transifex_api) }
11
+
12
+ before(:each) do
13
+ allow(database.transifex_project).to(
14
+ receive(:api).and_return(transifex_api)
15
+ )
16
+ end
17
+
18
+ describe '#upload' do
19
+ it 'reads phrases from the database and uploads them to Transifex' do
20
+ expect(transifex_api).to receive(:create_or_update) do |resource, content|
21
+ expect(resource.project_slug).to eq('myproject')
22
+ expect(resource.resource_slug).to(
23
+ eq(Txgh::Utils.slugify("#{database.database}-#{database.tables.first.name}"))
24
+ )
25
+ end
26
+
27
+ expect { uploader.upload }.to(
28
+ change { TestBackend.reads.size }.from(0).to(1)
29
+ )
30
+
31
+ expect(TestBackend.reads.first).to eq(
32
+ table: database.tables.first.name
33
+ )
34
+ end
35
+ end
36
+ end