Pact.io (машинопись) терпит неудачу, если присутствуют и заголовки и тело - PullRequest
0 голосов
/ 08 января 2019

Я использую Pact.io для контрактов между моим внешним интерфейсом (TypeScript) и внутренним. Я пытаюсь написать договор для загрузки файла; однако, если я укажу и headers.Content-Type, и body в разделе withRequest, проверка завершится неудачно без видимой причины (в веб-интерфейсе -> договор даже не генерируется). Если я пропускаю любой из этих двух разделов, проверка работает (но, конечно, некоторые данные отсутствуют, поэтому я не могу успешно проверить бэкэнд). Моя установка выглядит так:

const fileBody = '------boundary\r\n' +
    'Content-Disposition: form-data; name="file"; ' +
    'filename="test-attachment.pdf"\r\n' +
    'Content-Type: application/pdf\r\n' +
    '\r\n' +
    'file content\r\n' +
    '------boundary--\r\n';
const likeFileBody = fileBody.replace(/boundary/g, ".*");
const interaction: InteractionObject = {
    state: "my state",
    uponReceiving: "a file upload",
    withRequest: {
        method: 'POST',
        path: `/my/upload/path`,
        headers: {
            "Content-Type": Matchers.regex({
                generate: "multipart/form-data; boundary=----boundary",
                matcher: "multipart/form-data; boundary=.*",
            })
        },
        body: Matchers.regex({
            generate: fileBody,
            matcher: likeFileBody,
        }),
    },
    willRespondWith: {
        status: 201,
        headers: {'Content-Type': 'application/json'},
        body: {"some": "data"},
    }
};
await provider.addInteraction(interaction);

// ng2-file-upload module
const uploader = new FileUploader({
    url: `/my/upload/path`
});

uploader.addToQueue([new File(["file content"], "test-attachment.pdf")]);
uploader.uploadAll();
// poll uploader status
return new Promise(async resolve => {
    while (uploader.isUploading) {
        await new Promise((pollResolve => setTimeout(pollResolve, 10)));
    }
    resolve();
});

Журнал пакта говорит следующее:

 INFO -- : Registered expected interaction POST /my/upload/path
DEBUG -- : {
  "description": "a file upload",
  "providerState": "my state",                                                              
  "request": {                          
    "method": "POST",                                                                        
    "path": "/my/upload/path",
    "headers": {    
      "Content-Type": {      
        "json_class": "Pact::Term",    
        "data": {         
          "generate": "multipart/form-data; boundary=----boundary",
          "matcher": {"json_class":"Regexp","o":0,"s":"multipart/form-data; boundary=.*"}
        }
      }                                                                                                                                                   
    },                                                                                                                                                                                                               
    "body": { 
      "json_class": "Pact::Term",                                                                                                                                                     
      "data": {                                                                                                                                                                        
        "generate": "------boundary\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test-attachment.pdf\"\r\nContent-Type: application/pdf\r\n\r\nfile content\r\n------boundary--\r\n",
        "matcher": {"json_class":"Regexp","o":0,"s":"------.*\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test-attachment.pdf\"\r\nContent-Type: application/pdf\r\n\r\nfile content\r\n------.*--\r
\n"}              
      }                                                                                                                                                                                                        
    }                                                                                                                                                                                                                
  },     
  "response": {                                                                                                                                                                                                      
    "status": 201,
    "headers": {                                                                                                                                                                                                 
      "Content-Type": "application/json"                                                                                                                                                                        
    },                                                                                                                                                          
    "body": {}
  }
}
 INFO -- : Received request POST /my/upload/path
DEBUG -- : {
  "path": "/my/upload/path",
  "query": "",
  "method": "post",
  "body": "----------------------------163633642410335919983066\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test-attachment.pdf\"\r\nContent-Type: application/pdf\r\n\r\nfile content\r\n----------
------------------163633642410335919983066--\r\n",
  "headers": {
    "Content-Length": "234",
    "Content-Type": "multipart/form-data; boundary=--------------------------163633642410335919983066",
    "Referer": "http://localhost:8991/",
    "User-Agent": "Mozilla/5.0 (linux) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/11.12.0",
    "Accept-Language": "en",
    "Accept": "*/*",
    "Host": "localhost:8991",
    "Accept-Encoding": "gzip, deflate",
    "Connection": "close",
    "Version": "HTTP/1.1"
  }
}
ERROR -- : Error ocurred in mock service: NoMethodError - undefined method `split' for #<Pact::Term:0x00561356747038>
ERROR -- : /srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-support-1.8.0/lib/pact/shared/multipart_form_differ.
rb:8:in `call'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-support-1.8.0/lib/pact/consumer_contract/request.rb:72:in `body_diff'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-support-1.8.0/lib/pact/consumer_contract/request.rb:42:in `difference'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-support-1.8.0/lib/pact/consumer_contract/request.rb:28:in `matches?'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/mock_service/interactions/candidate_interactions.rb:8:in `block in matc
hing_interactions'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/mock_service/interactions/candidate_interactions.rb:7:in `select'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/mock_service/interactions/candidate_interactions.rb:7:in `matching_inte
ractions'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/mock_service/request_handlers/interaction_replay.rb:51:in `find_respons
e'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/mock_service/request_handlers/interaction_replay.rb:41:in `respond'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/mock_service/request_handlers/base_request_handler.rb:17:in `call'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/rack-2.0.5/lib/rack/cascade.rb:33:in `block in call'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/rack-2.0.5/lib/rack/cascade.rb:24:in `each'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/rack-2.0.5/lib/rack/cascade.rb:24:in `call'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/consumer/mock_service/cors_origin_header_middleware.rb:11:in `call'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/consumer/mock_service/error_handler.rb:13:in `call'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/mock_service/app.rb:33:in `call'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/pact-mock_service-2.12.0/lib/pact/consumer/mock_service/set_location.rb:14:in `call'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/rack-2.0.5/lib/rack/handler/webrick.rb:86:in `service'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/webrick-1.3.1/lib/webrick/httpserver.rb:138:in `service'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/webrick-1.3.1/lib/webrick/httpserver.rb:94:in `run'
/srv/service/node_modules/@pact-foundation/pact-node/standalone/linux-x64-1.61.1/lib/vendor/ruby/2.2.0/gems/webrick-1.3.1/lib/webrick/server.rb:191:in `block in start_thread'
 WARN -- : Verifying - actual interactions do not match expected interactions.
Missing requests:
        POST /my/upload/path


 WARN -- : Missing requests:
        POST /my/upload/path

Я что-то упустил или это ошибка в pact framework?

Ответы [ 2 ]

0 голосов
/ 09 января 2019

Изучив исходный код платформы pact, я обнаружил, что она уже заменяет границу подстановочным знаком; однако это происходит только в теле, а не в заголовке Content-Type. Следовательно, правильная формулировка для пакта:

const fileBody = '------boundary\r\n' +
    'Content-Disposition: form-data; name="file"; ' +
    'filename="test-attachment.pdf"\r\n' +
    'Content-Type: application/pdf\r\n' +
    '\r\n' +
    'file content\r\n' +
    '------boundary--\r\n';

...

headers: {
    "Content-Type": Matchers.regex({
        generate: "multipart/form-data; boundary=----boundary",
        matcher: "multipart/form-data; boundary=.*",
    })
},
body: fileBody,

С этим я смог проверить как у потребителя, так и у поставщика.

0 голосов
/ 08 января 2019

В настоящее время нельзя применять сопоставления тела для типов содержимого, отличных от JSON.

Официальное руководство заключается в тестировании других аспектов взаимодействия, но не самой двоичной полезной нагрузки: https://docs.pact.io/faq#how-do-i-test-binary-files-in-responses-such-as-a-download

...