nulogy_message_bus_producer 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
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