diff options
| author | azul <azul@leap.se> | 2014-07-18 12:21:49 +0200 | 
|---|---|---|
| committer | azul <azul@leap.se> | 2014-07-18 12:21:49 +0200 | 
| commit | bbd41c9bfd2cb88a88d7436dd58a8b46a5d10cf1 (patch) | |
| tree | 00b39da219151473437c02ce35344117bcd5b2fa | |
| parent | ade74d8a9091ae607586d7b287a0579a2ee7af8e (diff) | |
| parent | 20352249fa5dafe3abb2d4b751b1e5c8c0a59abc (diff) | |
Merge pull request #180 from azul/feature/messages-api
Feature/messages api
| -rw-r--r-- | app/controllers/controller_extension/json_responses.rb | 29 | ||||
| -rw-r--r-- | app/controllers/v1/messages_controller.rb | 4 | ||||
| -rw-r--r-- | app/models/message.rb | 4 | ||||
| -rw-r--r-- | app/models/user.rb | 7 | ||||
| -rw-r--r-- | config/initializers/add_controller_methods.rb | 1 | ||||
| -rw-r--r-- | config/locales/errors.en.yml | 1 | ||||
| -rw-r--r-- | config/locales/messages.en.yml | 4 | ||||
| -rw-r--r-- | features/messages.feature | 66 | ||||
| -rw-r--r-- | features/step_definitions/api_steps.rb | 8 | ||||
| -rw-r--r-- | features/step_definitions/messages_steps.rb | 32 | ||||
| -rw-r--r-- | features/support/hooks.rb | 14 | ||||
| -rw-r--r-- | test/factories.rb | 4 | ||||
| -rw-r--r-- | test/functional/v1/messages_controller_test.rb | 4 | ||||
| -rw-r--r-- | test/support/assert_responses.rb | 19 | 
14 files changed, 182 insertions, 15 deletions
diff --git a/app/controllers/controller_extension/json_responses.rb b/app/controllers/controller_extension/json_responses.rb new file mode 100644 index 0000000..da1ae58 --- /dev/null +++ b/app/controllers/controller_extension/json_responses.rb @@ -0,0 +1,29 @@ +module ControllerExtension::JsonResponses +  extend ActiveSupport::Concern + +  private + +  def success(key) +    json_message :success, key +  end + +  def error(key) +    json_message :error, key +  end + +  def json_message(type, key) +    long_key = "#{controller_string}.#{action_string}.#{key}" +    { type => key.to_s, +      :message => I18n.t(long_key, cascade: true) } +  end + +  def controller_string +    self.class.name.underscore. +      sub(/_controller$/, ''). +      sub(/^v\d\//, '') +  end + +  def action_string +    params[:action] +  end +end diff --git a/app/controllers/v1/messages_controller.rb b/app/controllers/v1/messages_controller.rb index a9b93a9..a496378 100644 --- a/app/controllers/v1/messages_controller.rb +++ b/app/controllers/v1/messages_controller.rb @@ -11,9 +11,9 @@ module V1        if message = Message.find(params[:id])          message.mark_as_read_by(current_user)          message.save -        render json: true +        render json: success(:marked_as_read)        else -        render json: false +        render json: error(:not_found), status: :not_found        end      end diff --git a/app/models/message.rb b/app/models/message.rb index 424f094..2478f3f 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -26,4 +26,8 @@ class Message < CouchRest::Model::Base    def unread_by?(user)      user_ids_to_show.include?(user.id)    end + +  def as_json(*args, &block) +    {"id" => id, "text" => text}.as_json(*args, &block) +  end  end diff --git a/app/models/user.rb b/app/models/user.rb index 6bc5841..9ac7d3d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -92,12 +92,9 @@ class User < CouchRest::Model::Base      Ticket.for_user(self).limit(count).all #defaults to having most recent updated first    end -  def messages(unseen = true) +  def messages      #TODO for now this only shows unseen messages. Will we ever want seen ones? Is it necessary to store? - -    # we don't want to emit all the userids associated with a message, so only emit id and text. -    Message.by_user_ids_to_show.key(self.id).map { |message| [message.id, message.text] } - +    Message.by_user_ids_to_show.key(self.id)    end    # DEPRECATED diff --git a/config/initializers/add_controller_methods.rb b/config/initializers/add_controller_methods.rb index f107544..4ad4213 100644 --- a/config/initializers/add_controller_methods.rb +++ b/config/initializers/add_controller_methods.rb @@ -2,5 +2,6 @@ ActiveSupport.on_load(:application_controller) do    include ControllerExtension::Authentication    include ControllerExtension::TokenAuthentication    include ControllerExtension::Flash +  include ControllerExtension::JsonResponses    include ControllerExtension::Errors  end diff --git a/config/locales/errors.en.yml b/config/locales/errors.en.yml index 93feab1..e0a909f 100644 --- a/config/locales/errors.en.yml +++ b/config/locales/errors.en.yml @@ -9,3 +9,4 @@ en:      text:        not_found: "You may have mistyped the address or the page may have moved."        server_error: The problem has been logged and we will look into it. +  not_found: Not found. diff --git a/config/locales/messages.en.yml b/config/locales/messages.en.yml new file mode 100644 index 0000000..d9d7613 --- /dev/null +++ b/config/locales/messages.en.yml @@ -0,0 +1,4 @@ +en: +  messages: +    not_found: That message could not be found. +    marked_as_read: Message has been marked as read. diff --git a/features/messages.feature b/features/messages.feature new file mode 100644 index 0000000..69c5637 --- /dev/null +++ b/features/messages.feature @@ -0,0 +1,66 @@ +Feature: Receive messages for the user + +  In order to stay in touch with the provider +  As an authenticated user +  I want to receive messages from the provider + +  Background: +    Given I authenticated +    Given I set headers: +      | Accept       | application/json | +      | Content-Type | application/json | +      | Authorization | Token token="MY_AUTH_TOKEN" | + +  Scenario: There are no messages yet +    When I send a GET request to "/1/messages.json" +    Then the response status should be "200" +    And the response should be: +      """ +      [] +      """ + +  Scenario: Fetch the unread messages +    Given there is a message for me with: +      | id   | 1a2b3c4d | +      | text | Your provider says hi ! | +    When I send a GET request to "/1/messages.json" +    Then the response status should be "200" +    And the response should be: +      """ +      [{ +       "id": "1a2b3c4d", +       "text": "Your provider says hi !" +      }] +      """ + +  Scenario: Send unread messages until marked as read +    Given there is a message for me +    And I have sent a GET request to "/1/messages.json" +    When I send a GET request to "/1/messages.json" +    Then the response status should be "200" +    And the response should include that message + +  Scenario: Mark message as read +    Given there is a message for me with: +      | id   | 1a2b3c4d | +    When I send a PUT request to "/1/messages/1a2b3c4d.json" +    Then that message should be marked as read +    And the response status should be "200" +    And the response should have "success" with "marked_as_read" +    And the response should have "message" + +  Scenario: Message not found +    When I send a PUT request to "/1/messages/1a2b3c4d.json" +    Then the response status should be "404" +    And the response should have "error" with "not_found" +    And the response should have "message" + +  Scenario: Do not send read messages +    Given there is a message for me +    And that message is marked as read +    When I send a GET request to "/1/messages.json" +    Then the response status should be "200" +    And the response should be: +      """ +      [] +      """ diff --git a/features/step_definitions/api_steps.rb b/features/step_definitions/api_steps.rb index a4f369c..7188694 100644 --- a/features/step_definitions/api_steps.rb +++ b/features/step_definitions/api_steps.rb @@ -13,8 +13,9 @@ end  Given /^I set headers:$/ do |headers|    headers.rows_hash.each do |key,value| -    value.sub!('MY_AUTH_TOKEN', @my_auth_token.to_s) if @my_auth_token -    header key, value +    replace = value.dup +    replace.sub!('MY_AUTH_TOKEN', @my_auth_token.to_s) if @my_auth_token +    header key, replace    end  end @@ -36,7 +37,7 @@ When /^I digest\-authenticate as the user "(.*?)" with the password "(.*?)"$/ do    digest_authorize user, pass  end -When /^I send a (GET|POST|PUT|DELETE) request (?:for|to) "([^"]*)"(?: with the following:)?$/ do |*args| +When /^I (?:have sent|send) a (GET|POST|PUT|DELETE) request (?:for|to) "([^"]*)"(?: with the following:)?$/ do |*args|    request_type = args.shift    path = args.shift    input = args.shift @@ -50,7 +51,6 @@ When /^I send a (GET|POST|PUT|DELETE) request (?:for|to) "([^"]*)"(?: with the f        request_opts[:input] = input      end    end -    request path, request_opts  end diff --git a/features/step_definitions/messages_steps.rb b/features/step_definitions/messages_steps.rb new file mode 100644 index 0000000..30bc7c3 --- /dev/null +++ b/features/step_definitions/messages_steps.rb @@ -0,0 +1,32 @@ +Given /^there is a message for me$/ do +  @message = FactoryGirl.create :message, user_ids_to_show: [@user.id] +end + +Given /^there is a message for me with:$/ do |options| +  attributes = options.rows_hash +  attributes.merge! user_ids_to_show: [@user.id] +  if old_message = Message.find(attributes['id']) +    old_message.destroy +  end +  @message = FactoryGirl.create :message, attributes +end + +Given(/^that message is marked as read$/) do +    @message.mark_as_read_by(@user) +    @message.save +end + +Then /^the response should (not)?\s?include that message$/ do |negative| +  json = JSON.parse(last_response.body) +  message = json.detect{|message| message['id'] == @message.id} +  if negative.present? +    assert !message +  else +    assert_equal @message.text, message['text'] +  end +end + +Then /^that message should be marked as read$/ do +  assert @message.reload.read_by? @user +  assert !@message.unread_by?(@user) +end diff --git a/features/support/hooks.rb b/features/support/hooks.rb index 19928d8..f11e602 100644 --- a/features/support/hooks.rb +++ b/features/support/hooks.rb @@ -5,6 +5,7 @@ After '@tempfile' do    end  end +# store end of server log for failing scenarios  After do |scenario|    if scenario.failed?      logfile_path = Rails.root + 'tmp' @@ -16,3 +17,16 @@ After do |scenario|      end    end  end + +# clear all records we created +After do +  names = self.instance_variables.reject do |v| +    v.to_s.starts_with?('@_') +  end +  names.each do |name| +    record = self.instance_variable_get name +    if record.is_a?(CouchRest::Model::Base) && record.persisted? +      record.reload && record.destroy +    end +  end +end diff --git a/test/factories.rb b/test/factories.rb index a96d48c..e16c738 100644 --- a/test/factories.rb +++ b/test/factories.rb @@ -47,4 +47,8 @@ FactoryGirl.define do  -----END PGP PUBLIC KEY BLOCK-----      EOPGP    end + +  factory :message do +    text Faker::Lorem.paragraph +  end  end diff --git a/test/functional/v1/messages_controller_test.rb b/test/functional/v1/messages_controller_test.rb index a50fded..6f7ea5d 100644 --- a/test/functional/v1/messages_controller_test.rb +++ b/test/functional/v1/messages_controller_test.rb @@ -30,7 +30,7 @@ class V1::MessagesControllerTest < ActionController::TestCase      @message.reload      assert !@message.user_ids_to_show.include?(@user.id)      assert @message.user_ids_have_shown.include?(@user.id) -    assert_json_response true +    assert_success :marked_as_read    end    test "do not get seen messages" do @@ -46,7 +46,7 @@ class V1::MessagesControllerTest < ActionController::TestCase    test "mark read responds even with bad inputs" do      login @user      put :update, :id => 'more nonsense' -    assert_json_response false +    assert_not_found   end    test "fails if not authenticated" do diff --git a/test/support/assert_responses.rb b/test/support/assert_responses.rb index 1c9d49d..7724fb4 100644 --- a/test/support/assert_responses.rb +++ b/test/support/assert_responses.rb @@ -20,6 +20,22 @@ module AssertResponses        response    end +  def response_content +    json_response || get_response.body +  end + +  def assert_success(message) +    assert_response :success +    assert_response_includes :success +    assert_equal message.to_s, json_response[:success] if message.present? +  end + +  def assert_not_found +    assert_response :not_found +    assert_response_includes :error +    assert_equal 'not_found', json_response[:error] +  end +    def assert_text_response(body = nil)      assert_equal 'text/plain', content_type      unless body.nil? @@ -45,8 +61,7 @@ module AssertResponses    # checks for the presence of a key in a json response    # or a string in a text response    def assert_response_includes(string_or_key) -    response = json_response || get_response.body -    assert response.include?(string_or_key), +    assert response_content.include?(string_or_key),        "response should have included #{string_or_key}"    end  | 
