nulogy_message_bus_producer 1.0.2

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 (74) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +35 -0
  3. data/Rakefile +22 -0
  4. data/db/migrate/20200611150212_create_public_subscriptions_and_events_tables.rb +25 -0
  5. data/lib/nulogy_message_bus_producer.rb +112 -0
  6. data/lib/nulogy_message_bus_producer/application_record.rb +6 -0
  7. data/lib/nulogy_message_bus_producer/base_public_subscription.rb +13 -0
  8. data/lib/nulogy_message_bus_producer/engine.rb +6 -0
  9. data/lib/nulogy_message_bus_producer/postgres_public_subscriptions.rb +102 -0
  10. data/lib/nulogy_message_bus_producer/public_subscription.rb +27 -0
  11. data/lib/nulogy_message_bus_producer/public_subscription_event.rb +13 -0
  12. data/lib/nulogy_message_bus_producer/subscriber_graphql_schema_validator.rb +45 -0
  13. data/lib/nulogy_message_bus_producer/version.rb +3 -0
  14. data/spec/dummy/Rakefile +6 -0
  15. data/spec/dummy/app/assets/config/manifest.js +4 -0
  16. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  17. data/spec/dummy/app/assets/javascripts/cable.js +13 -0
  18. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  19. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  20. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  21. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  22. data/spec/dummy/app/controllers/dummy_controller.rb +17 -0
  23. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  24. data/spec/dummy/app/jobs/application_job.rb +2 -0
  25. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  26. data/spec/dummy/app/models/application_record.rb +3 -0
  27. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  28. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  29. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  30. data/spec/dummy/bin/bundle +3 -0
  31. data/spec/dummy/bin/rails +4 -0
  32. data/spec/dummy/bin/rake +4 -0
  33. data/spec/dummy/bin/setup +38 -0
  34. data/spec/dummy/bin/update +29 -0
  35. data/spec/dummy/bin/yarn +11 -0
  36. data/spec/dummy/config.ru +5 -0
  37. data/spec/dummy/config/application.rb +22 -0
  38. data/spec/dummy/config/boot.rb +5 -0
  39. data/spec/dummy/config/cable.yml +10 -0
  40. data/spec/dummy/config/database.yml +22 -0
  41. data/spec/dummy/config/environment.rb +5 -0
  42. data/spec/dummy/config/environments/development.rb +54 -0
  43. data/spec/dummy/config/environments/production.rb +91 -0
  44. data/spec/dummy/config/environments/test.rb +42 -0
  45. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  46. data/spec/dummy/config/initializers/assets.rb +14 -0
  47. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  48. data/spec/dummy/config/initializers/cookies_serializer.rb +5 -0
  49. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  50. data/spec/dummy/config/initializers/inflections.rb +16 -0
  51. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  52. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  53. data/spec/dummy/config/locales/en.yml +33 -0
  54. data/spec/dummy/config/puma.rb +56 -0
  55. data/spec/dummy/config/routes.rb +6 -0
  56. data/spec/dummy/config/secrets.yml +32 -0
  57. data/spec/dummy/config/spring.rb +6 -0
  58. data/spec/dummy/db/schema.rb +42 -0
  59. data/spec/dummy/log/development.log +1771 -0
  60. data/spec/dummy/log/test.log +14189 -0
  61. data/spec/dummy/package.json +5 -0
  62. data/spec/dummy/public/404.html +67 -0
  63. data/spec/dummy/public/422.html +67 -0
  64. data/spec/dummy/public/500.html +66 -0
  65. data/spec/dummy/public/apple-touch-icon-precomposed.png +0 -0
  66. data/spec/dummy/public/apple-touch-icon.png +0 -0
  67. data/spec/dummy/public/favicon.ico +0 -0
  68. data/spec/integration/lib/graphql_api/postgres_public_subscriptions_spec.rb +16 -0
  69. data/spec/integration/lib/graphql_api/validators/subscriber_graphql_schema_validator_spec.rb +76 -0
  70. data/spec/integration_spec_helper.rb +35 -0
  71. data/spec/spec_helper.rb +60 -0
  72. data/spec/unit/lib/graphql_api/models/public_subscription_spec.rb +56 -0
  73. data/spec/unit_spec_helper.rb +6 -0
  74. metadata +342 -0
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "dummy",
3
+ "private": true,
4
+ "dependencies": {}
5
+ }
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The page you were looking for doesn't exist (404)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/404.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The page you were looking for doesn't exist.</h1>
62
+ <p>You may have mistyped the address or the page may have moved.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>The change you wanted was rejected (422)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/422.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>The change you wanted was rejected.</h1>
62
+ <p>Maybe you tried to change something you didn't have access to.</p>
63
+ </div>
64
+ <p>If you are the application owner check the logs for more information.</p>
65
+ </div>
66
+ </body>
67
+ </html>
@@ -0,0 +1,66 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>We're sorry, but something went wrong (500)</title>
5
+ <meta name="viewport" content="width=device-width,initial-scale=1">
6
+ <style>
7
+ .rails-default-error-page {
8
+ background-color: #EFEFEF;
9
+ color: #2E2F30;
10
+ text-align: center;
11
+ font-family: arial, sans-serif;
12
+ margin: 0;
13
+ }
14
+
15
+ .rails-default-error-page div.dialog {
16
+ width: 95%;
17
+ max-width: 33em;
18
+ margin: 4em auto 0;
19
+ }
20
+
21
+ .rails-default-error-page div.dialog > div {
22
+ border: 1px solid #CCC;
23
+ border-right-color: #999;
24
+ border-left-color: #999;
25
+ border-bottom-color: #BBB;
26
+ border-top: #B00100 solid 4px;
27
+ border-top-left-radius: 9px;
28
+ border-top-right-radius: 9px;
29
+ background-color: white;
30
+ padding: 7px 12% 0;
31
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
32
+ }
33
+
34
+ .rails-default-error-page h1 {
35
+ font-size: 100%;
36
+ color: #730E15;
37
+ line-height: 1.5em;
38
+ }
39
+
40
+ .rails-default-error-page div.dialog > p {
41
+ margin: 0 0 1em;
42
+ padding: 1em;
43
+ background-color: #F7F7F7;
44
+ border: 1px solid #CCC;
45
+ border-right-color: #999;
46
+ border-left-color: #999;
47
+ border-bottom-color: #999;
48
+ border-bottom-left-radius: 4px;
49
+ border-bottom-right-radius: 4px;
50
+ border-top-color: #DADADA;
51
+ color: #666;
52
+ box-shadow: 0 3px 8px rgba(50, 50, 50, 0.17);
53
+ }
54
+ </style>
55
+ </head>
56
+
57
+ <body class="rails-default-error-page">
58
+ <!-- This file lives in public/500.html -->
59
+ <div class="dialog">
60
+ <div>
61
+ <h1>We're sorry, but something went wrong.</h1>
62
+ </div>
63
+ <p>If you are the application owner check the logs for more information.</p>
64
+ </div>
65
+ </body>
66
+ </html>
File without changes
File without changes
@@ -0,0 +1,16 @@
1
+ require "integration_spec_helper"
2
+
3
+ RSpec.describe NulogyMessageBusProducer::PostgresPublicSubscriptions do
4
+ context "when the class is not registered" do
5
+ it "raises" do
6
+ unregistered_schema = Class.new(GraphQL::Schema) do
7
+ use(NulogyMessageBusProducer::PostgresPublicSubscriptions)
8
+ end
9
+
10
+ expect do
11
+ # this find triggers the plugin to be loaded
12
+ unregistered_schema.find("something")
13
+ end.to raise_error(KeyError, /The schema registry did not contain an entry/)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,76 @@
1
+ require "integration_spec_helper"
2
+
3
+ RSpec.describe NulogyMessageBusProducer::SubscriberGraphqlSchemaValidator do
4
+ subject(:validator) { NulogyMessageBusProducer::SubscriberGraphqlSchemaValidator.new }
5
+
6
+ before do
7
+ NulogyMessageBusProducer.register_schema("test", "NulogyMessageBusProducer::Specs::TestSchema")
8
+ end
9
+
10
+ describe "#validate" do
11
+ context "when a valid query is present" do
12
+ it "return true" do
13
+ create_subscription(<<~QUERY)
14
+ query ($id: UUID!) {
15
+ foo (id: $id) {
16
+ id
17
+ }
18
+ }
19
+ QUERY
20
+
21
+ expect(validator.validate).to be(true)
22
+ end
23
+ end
24
+
25
+ context "when an invalid query is present" do
26
+ let(:subscription_with_error) do
27
+ subscription = create_subscription(<<~QUERY)
28
+ query ($id: UUID!) {
29
+ foo (id: $id) {
30
+ id
31
+ }
32
+ }
33
+ QUERY
34
+
35
+ subscription.query = <<~BAD_QUERY
36
+ query ($id: UUID!) {
37
+ foo (id: $id) {
38
+ a_field_that_does_not_exist
39
+ }
40
+ }
41
+ BAD_QUERY
42
+ subscription.save(validate: false)
43
+ subscription
44
+ end
45
+
46
+ it "returns false" do
47
+ subscription_with_error
48
+
49
+ expect(validator.validate).to be(false)
50
+ end
51
+
52
+ it "has errors" do
53
+ subscription_with_error
54
+
55
+ validator.validate
56
+
57
+ expect(validator.errors).to contain_exactly(
58
+ "Field 'a_field_that_does_not_exist' doesn't exist on type 'testObject' (id: #{subscription_with_error.id})"
59
+ )
60
+ end
61
+ end
62
+ end
63
+
64
+ def create_subscription(query, event_type = "testEvent", schema_key: "test")
65
+ NulogyMessageBusProducer::PublicSubscription.create_or_update(
66
+ query: query,
67
+ event_type: event_type,
68
+ schema_key: schema_key,
69
+
70
+ # not relavant, but needed for DB constraints
71
+ id: SecureRandom.uuid,
72
+ subscription_group_id: SecureRandom.uuid,
73
+ topic_name: SecureRandom.uuid
74
+ )
75
+ end
76
+ end
@@ -0,0 +1,35 @@
1
+ # Make all rspec configuration changes to this file.
2
+ # Leave automatically generated configuration files untouched to facilitate gem upgrades.
3
+
4
+ ENV["RAILS_ENV"] ||= "test"
5
+
6
+ require File.expand_path("dummy/config/environment.rb", __dir__)
7
+
8
+ require "rspec/rails"
9
+ require "active_record"
10
+
11
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].sort.each { |f| require f }
12
+
13
+ RSpec.configure do |config|
14
+ # Uncomment this line to see full backtraces for spec failures
15
+ # config.backtrace_exclusion_patterns = []
16
+
17
+ config.profile_examples = 0
18
+
19
+ # implements `use_transactional_fixtures = true`
20
+ config.before do
21
+ connection = ActiveRecord::Base.connection
22
+ connection.begin_transaction(joinable: false)
23
+ end
24
+
25
+ config.after do
26
+ connection = ActiveRecord::Base.connection
27
+ connection.rollback_transaction if connection.transaction_open?
28
+ ActiveRecord::Base.clear_active_connections!
29
+ end
30
+
31
+ # Increase characters displayed when exceptions fail (the RSpec default is 200 characters).
32
+ config.expect_with(:rspec) do |c|
33
+ c.max_formatted_output_length = 1_000_000
34
+ end
35
+ end
@@ -0,0 +1,60 @@
1
+ # Some test GraphQL objects for testing
2
+ module NulogyMessageBusProducer
3
+ module Specs
4
+ class TestObject < GraphQL::Schema::Object
5
+ graphql_name "testObject"
6
+
7
+ field :id, type: NulogyGraphqlApi::Types::UUID, null: false
8
+ end
9
+
10
+ class TestQuery < GraphQL::Schema::Object
11
+ graphql_name "testQuery"
12
+
13
+ field :foo, TestObject, null: false do
14
+ argument :id, type: NulogyGraphqlApi::Types::UUID, required: false
15
+ end
16
+ end
17
+
18
+ class TestSchema < GraphQL::Schema
19
+ use NulogyMessageBusProducer::PostgresPublicSubscriptions
20
+
21
+ query TestQuery
22
+ end
23
+ end
24
+ end
25
+
26
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
27
+ RSpec.configure do |config|
28
+ config.expect_with(:rspec) do |expectations|
29
+ # This is generally recommended, and will default to `true` in RSpec 4.
30
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
31
+ end
32
+
33
+ config.mock_with(:rspec) do |mocks|
34
+ # This is generally recommended, and will default to `true` in RSpec 4.
35
+ mocks.verify_partial_doubles = true
36
+ end
37
+
38
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
39
+ # have no way to turn it off -- the option exists only for backwards
40
+ # compatibility in RSpec 3). It causes shared context metadata to be
41
+ # inherited by the metadata hash of host groups and examples, rather than
42
+ # triggering implicit auto-inclusion in groups with matching metadata.
43
+ config.shared_context_metadata_behavior = :apply_to_host_groups
44
+ config.filter_run_when_matching(:focus)
45
+
46
+ # Allows RSpec to persist some state between runs in order to support
47
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
48
+ # you configure your source control system to ignore this file.
49
+ config.example_status_persistence_file_path = "tmp/examples.txt"
50
+
51
+ config.disable_monkey_patching!
52
+ config.default_formatter = "doc"
53
+ config.order = :random
54
+
55
+ # Seed global randomization in this process using the `--seed` CLI option.
56
+ # Setting this allows you to use `--seed` to deterministically reproduce
57
+ # test failures related to randomization by passing the same `--seed` value
58
+ # as the one that triggered the failure.
59
+ Kernel.srand(config.seed)
60
+ end
@@ -0,0 +1,56 @@
1
+ require "unit_spec_helper"
2
+
3
+ RSpec.describe NulogyMessageBusProducer::PublicSubscription do
4
+ context "when validating" do
5
+ before do
6
+ NulogyMessageBusProducer.register_schema("test", "NulogyMessageBusProducer::Specs::TestSchema")
7
+ end
8
+
9
+ it "is invalid with a blank query" do
10
+ model = NulogyMessageBusProducer::PublicSubscription.new(
11
+ schema_key: "test",
12
+ query: ""
13
+ )
14
+
15
+ model.validate
16
+
17
+ expect(model).to_not be_valid
18
+ expect(model.errors[:query]).to contain_exactly("can't be blank")
19
+ end
20
+
21
+ it "is invalid with an invalid query" do
22
+ model = NulogyMessageBusProducer::PublicSubscription.new(
23
+ schema_key: "test",
24
+ query: <<~QUERY
25
+ query ($id: UUID!) {
26
+ foo (id: $id) {
27
+ a_field_that_does_not_exist
28
+ }
29
+ }
30
+ QUERY
31
+ )
32
+
33
+ model.validate
34
+
35
+ expect(model).to_not be_valid
36
+ expect(model.errors[:query]).to contain_exactly("Field 'a_field_that_does_not_exist' doesn't exist on type 'testObject' (id: <new_record>)")
37
+ end
38
+
39
+ it "valid with a valid query" do
40
+ model = NulogyMessageBusProducer::PublicSubscription.new(
41
+ schema_key: "test",
42
+ query: <<~QUERY
43
+ query ($id: UUID!) {
44
+ foo (id: $id) {
45
+ id
46
+ }
47
+ }
48
+ QUERY
49
+ )
50
+
51
+ model.validate
52
+
53
+ expect(model.errors).to_not include(:query)
54
+ end
55
+ end
56
+ end