graphql-anycable icon indicating copy to clipboard operation
graphql-anycable copied to clipboard

Trigger doesn't fire rspec have_broadcasted_to

Open sjovanelly opened this issue 5 years ago • 5 comments

Describe the bug Switched to anycable from straight up AC. Trying to convert tests and the old tests that used to pass, now fail with 0 broadcasts. The app itself works fine with updates to AnyCable.

rspec test looks like this

it 'does project socket broadcast' do
   expect do
     subject.process(message_hash)  # this calls the trigger listed below in it's process
   end.to have_broadcasted_to("graphql-event::liveProject:projectId:#{project.id}")
end

Trigger is called this way...

MainApiSchema.subscriptions.trigger('liveActivityFeed', { project_id: project.id }, { item: feed })

Versions ruby: 2.6.3 rails (or other framework): 6.0.3.2 graphql: 1.11 graphql-anycable: 0.4.0 anycable: 1.0.1

GraphQL schema

module Types
  class ActivityFeedItemType < Types::BaseObject
    description 'Events that are associated to a project.'
    field :id, Integer, null: false
    field :category, String, null: false
    field :topic, String, null: false
    field :reference, String, null: false, method: :reference_type
    field :reference_id, Integer, null: false
    field :metadata, Types::Scalars::Json, null: false
    field :created_from_type, String, null: false
    field :created_from_id, Integer, null: false
    field :created_at, GraphQL::Types::ISO8601DateTime, null: false, method: :reference_created_at

    def metadata
      object.metadata['data']
    end
  end
end

class MainApiSchema < GraphQL::Schema
  mutation(Types::MutationType)
  query(Types::QueryType)
  subscription(Types::SubscriptionType)

  # enable batch loading
  use BatchLoader::GraphQL
  use GraphQL::Tracing::NewRelicTracing

  use GraphQL::Subscriptions::AnyCableSubscriptions
  use GraphQL::Execution::Interpreter
  use GraphQL::Analysis::AST
  use GraphQL::Execution::Errors
end

module Subscriptions
  class ActivityFeedSubscription < Subscriptions::BaseSubscription
    description 'An activity feed item was added to the project'
    argument :project_id, ID, required: true

    field :item,
          Types::ActivityFeedItemType,
          null: true,
          description: 'New feed item added for a project'
  end
end

GraphQL query

How do you subscribe to subscriptions?

subscription onActivityFeedCreated($projectId: ID!){
  liveActivityFeed(projectId: $projectId) {
    item {
      ...feedFragment
    }
  }

fragment feedFragment on ActivityFeedItem {
  id
  topic
  category
  reference
  referenceId
  metadata
  createdAt
  createdFromType
  createdFromId
}

Steps to reproduce Create rspec test and call. You can skip the middleman with my subject.call method and just put trigger in there.

it 'does feed socket broadcast' do
  expect do
     MainApiSchema.subscriptions.trigger('liveActivityFeed', { project_id: project.id }, { item: feedItem })
  end.to have_broadcasted_to("graphql-event::liveActivityFeed:projectId:#{project.id}")
end

Expected behavior have_broadcasted_to should return true

Actual behavior Error in rspec log:

ArtifactAssociatedConsumer#process_message when the artifact is present does socket broadcast
 Failure/Error:
   expect do
     subject.process(message_hash)
   end.to have_broadcasted_to("graphql-event::liveActivityFeed:projectId:#{project.id}")
    
  expected to broadcast exactly 1 messages to graphql-event::liveActivityFeed:projectId:13, but broadcast 0
  # ./spec/consumers/artifact_associated_consumer_spec.rb:77:in `block (4 levels) in <top (required)>'

Additional context Cable yml looks like this...

development:
  adapter: <%= ENV.fetch("ACTION_CABLE_ADAPTER", "any_cable") %>
test:
  adapter: test
production:
  adapter: <%= ENV.fetch("ACTION_CABLE_ADAPTER", "any_cable") %>

and my other config settings are per AnyCable documentation

sjovanelly avatar Aug 04 '20 23:08 sjovanelly

Thank you for pointing it out! @palkan, any thoughts?

I have no idea for now and it will require some time to investigate. I hope I will be able to dig into it next week maybe.

Envek avatar Aug 05 '20 12:08 Envek

I believe this happens because we broadcast directly via AnyCable, not via ActionCable.server.pubsub: https://github.com/anycable/graphql-anycable/blob/a0b48167327170add168714055940b2c297b6dc9/lib/graphql/subscriptions/anycable_subscriptions.rb#L83

The workaround for this could be adding a Rails specific Subscriptions class, which inherits from AnyCableSubscriptions and overrides the #deliver method to use Action Cable.

palkan avatar Aug 05 '20 14:08 palkan

Thx for feedback. Since this is in our testing, we changed our tests to make sure the trigger is getting called...

expect_any_instance_of(GraphQL::Subscriptions::AnyCableSubscriptions).to receive(:trigger).with('liveActivityFeed', { project_id: project.id }, { item: be_present })

We also stubbed out the trigger call so our external CI tools didn't require redis_url

sjovanelly avatar Aug 05 '20 16:08 sjovanelly

we broadcast directly via AnyCable, not via ActionCable.server.pubsub:

This is because we want it to be also usable without Rails. Not sure how to fix it there at the moment.

Envek avatar Aug 05 '20 16:08 Envek

Not sure how to fix it there at the moment.

This

The workaround for this could be adding a Rails specific Subscriptions class, which inherits from AnyCableSubscriptions

palkan avatar Aug 06 '20 09:08 palkan