savonrb / wasabi

A simple WSDL parser
MIT License
90 stars 84 forks source link

undefined method `element_children' for nil:NilClass parser.rb:318 #49

Open janhh opened 10 years ago

janhh commented 10 years ago

Hi, I receive a "undefined method" message at parser.rb:318. See attached screenshot, and the code in link. https://github.com/savonrb/wasabi/blob/v3.3.1/lib/wasabi/parser.rb#L318

The \@messages object is an empty hash and the port_message_type variable has a variable. Savon mocks the service I am testing against.

If I add a "if message" at the end of line 320, my rspec fails at parser.rb:260 with same error message. Interestingly, adding if check made test pass when I used wasabi 3.3.0 IIRC.

screenshot from 2014-10-02 16 29 43

tjarratt commented 10 years ago

Interesting issue @janhh -- could you expand more on "Savon mocks the service I am testing against"? If I understand correctly, it sounds like you're using this in a test environment and you're mocking the actual HTTP response?

If possible. could you share a small snippet of code that illustrates this problem? It's my understanding that this would occur when the WSDL does not have any message nodes, but I can't imagine a WSDL without at least one <message> element.

janhh commented 10 years ago

I use mocking feature to test my implementation, hopefully my code snippets below illustrate what I mean.

Client:

require 'savon'
module WsEsaOffentlig
  module V8041_10512
    class OffentligServiceClient

      CDATA_FORMAT = '<![CDATA[%s]]>'

      def initialize(endpoint = 'http://localhost')
        @client = Savon.client(wsdl: wsdl_file_path, endpoint: endpoint)
      end

      def search_off_journal(where, order_by, max_no_of_hits)
        message = {
          where: CDATA_FORMAT % where,
          order_by: order_by,
          max_no_of_hits: max_no_of_hits
        }
        @client.call(:search_off_journal, message: message)
      end

      def wsdl_file_path
        File.expand_path("../../wsdl/offentlig-service/offentlig_1.wsdl", __FILE__)
      end

    end
  end
end

Spec:

require 'savon/mock/spec_helper'
require_relative '../../../../../../../lib/impl/ws_esa_offentlig/v8041_10512/clients/offentlig_service_client.rb'

module WsEsaOffentlig
  module V8041_10512

    describe 'OffentligServiceClient' do

      include Savon::SpecHelper
      before(:all) {savon.mock!}
      after(:all) {savon.unmock!}

      describe "#wsdl_file_path" do
        it "returns a file path that is available" do
          file_path = VersionClient.new.wsdl_file_path
          expect(File.exist?(file_path)).to be true
        end
      end

      describe "#search_off_journal" do
        it "should return many ids when where clause is within september 2014" do
          fixture = File.read(File.expand_path("../../fixtures/offentlig_service_search_off_journal_september_response.xml", __FILE__))

          where = "jpjdato >= '08.09.14' AND jpjdato < '11.09.14'"
          order_by = ''
          max_no_of_hits = ''

          message = {
            where: "jpjdato >= '08.09.14' AND jpjdato < '11.09.14'",
            order_by: order_by,
            max_no_of_hits: max_no_of_hits
          }

          expected_message = message

          # Wrap message with CDATA.
          expected_message[:where] = OffentligServiceClient::CDATA_FORMAT % message[:where]
          savon.expects(:search_off_journal).with(message: expected_message).returns(fixture)

          client = OffentligServiceClient.new
          response = client.search_off_journal(where, order_by, max_no_of_hits)

          expect(response).to be_successful
        end
      end

    end

  end
end

The WSDL is spread out in different files, and uses wsdl:import statements. I used SoapUI to export definitions from actual Web Service.

screenshot from 2014-10-15 12 08 21

getabetterpic commented 9 years ago

I ran into this issue as well. What version of Nokogiri are you running? That turned out to be my problem. Wasabi only requires Nokogiri 1.4.0, but element_children were not put in until 1.4.2. If you update Nokogiri, it will probably fix this issue.

janhh commented 9 years ago

Hi, thanks for the suggestion. Actually, savon 2.6.0 depends on nokogiri 1.6.3.1.

I got around this issue by using JRuby and Java Axis2 client instead. But I still have a branch of the MRI attempt in our Git tree.

sshaw commented 9 years ago

The problem occurs when an HTML doc is returned by a server and passed to Nokogiri.XML. In this case the document's root in nil:

irb [2.1.3] (sshaw-savon)$ Nokogiri::XML("<!doctype html><head></head><body></body>").root
=> nil

You can reproduce this using Savon with:

client = Savon.client(wsdl: "http://example.com")               
client.call(:xxxx, message: "Death to Saxon XSLT!")

The result:

/Users/sshaw/.rvm/gems/ruby-2.1.3/gems/wasabi-3.3.0/lib/wasabi/parser.rb:311:in `sections': undefined method `element_children' for nil:NilClass (NoMethodError)
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/wasabi-3.3.0/lib/wasabi/parser.rb:304:in `section'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/wasabi-3.3.0/lib/wasabi/parser.rb:294:in `schemas'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/wasabi-3.3.0/lib/wasabi/parser.rb:67:in `parse_namespaces'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/wasabi-3.3.0/lib/wasabi/parser.rb:54:in `parse'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/wasabi-3.3.0/lib/wasabi/document.rb:161:in `parse'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/wasabi-3.3.0/lib/wasabi/document.rb:147:in `parser'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/wasabi-3.3.0/lib/wasabi/document.rb:64:in `soap_actions'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/savon-2.8.1/lib/savon/operation.rb:21:in `ensure_exists!'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/savon-2.8.1/lib/savon/operation.rb:14:in `create'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/savon-2.8.1/lib/savon/client.rb:32:in `operation'
    from /Users/sshaw/.rvm/gems/ruby-2.1.3/gems/savon-2.8.1/lib/savon/client.rb:36:in `call'
tjarratt commented 9 years ago

Hah, great catch @sshaw! I think the fix for this would be to catch this and return an error in this case, rather than trying to parse an HTML body. Will see if I can find time to fix this sometime next week, but if someone wants to issue a PR for this I'd be more than happy to help out.