All files / src/plugins/validation/swagger2/semantic-validators operations-ibm.js

95.56% Statements 43/45
93.02% Branches 40/43
100% Functions 6/6
95.56% Lines 43/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126                  29x 29x 29x 29x 29x   29x 46x   46x   46x 93x     93x                 93x   124x         124x   87x     87x     87x 87x 2x 2x 2x           87x 87x 84x 85x 79x         87x         34x                 124x 124x     123x     123x     123x 123x 236x     123x   123x 2x                 124x 124x   36x 1x                     46x    
// Assertation 1:
// PUT and POST operations with body parameter must have a non-empty `consumes` field
 
// Assertation 2:
// GET operations should not specify a consumes field.
 
// Assertation 3:
// GET operations must have a non-empty `produces` field.
 
const each = require('lodash/each');
const includes = require('lodash/includes');
const map = require('lodash/map');
const pick = require('lodash/pick');
const MessageCarrier = require('../../../utils/messageCarrier');
 
module.exports.validate = function({ jsSpec }, config) {
  const messages = new MessageCarrier();
 
  config = config.operations;
 
  map(jsSpec.paths, (path, pathKey) => {
    Iif (pathKey.slice(0, 2) === 'x-') {
      return;
    }
    const pathOps = pick(path, [
      'get',
      'head',
      'post',
      'put',
      'patch',
      'delete',
      'options'
    ]);
    each(pathOps, (op, opKey) => {
      // if operation is excluded, don't validate it
      Iif (!op || op['x-sdk-exclude'] === true) {
        // skip this operation in the 'each' loop
        return;
      }
 
      if (includes(['put', 'post'], opKey.toLowerCase())) {
        const hasLocalConsumes =
          op.consumes &&
          op.consumes.length > 0 &&
          !!op.consumes.join('').trim();
        const hasGlobalConsumes = !!jsSpec.consumes;
 
        // Check for body parameter in path
        let hasBodyParamInPath = false;
        if (path.parameters) {
          path.parameters.forEach(parameter => {
            Eif (parameter.in === 'body') {
              hasBodyParamInPath = true;
            }
          });
        }
 
        // Check for body parameter in operation
        let hasBodyParamInOps = false;
        if (op.parameters) {
          op.parameters.forEach(parameter => {
            if (parameter.in === 'body') {
              hasBodyParamInOps = true;
            }
          });
        }
 
        if (
          !hasLocalConsumes &&
          !hasGlobalConsumes &&
          (hasBodyParamInOps || hasBodyParamInPath)
        ) {
          messages.addMessage(
            `paths.${pathKey}.${opKey}.consumes`,
            'PUT and POST operations with a body parameter must have a non-empty `consumes` field.',
            config.no_consumes_for_put_or_post,
            'no_consumes_for_put_or_post'
          );
        }
      }
 
      const isHeadOperation = opKey.toLowerCase() === 'head';
      if (!isHeadOperation) {
        // operations should have a produces property
        const hasLocalProduces =
          op.produces &&
          op.produces.length > 0 &&
          !!op.produces.join('').trim();
        const hasGlobalProduces = !!jsSpec.produces;
 
        // determine if only success response is a 204
        const responses = op.responses || {};
        const successResponses = Object.keys(responses).filter(
          code => code.charAt(0) === '2'
        );
        const onlyHas204 =
          successResponses.length === 1 && successResponses[0] === '204';
 
        if (!hasLocalProduces && !hasGlobalProduces && !onlyHas204) {
          messages.addMessage(
            `paths.${pathKey}.${opKey}.produces`,
            'Operations must have a non-empty `produces` field.',
            config.no_produces,
            'no_produces'
          );
        }
      }
 
      const isGetOperation = opKey.toLowerCase() === 'get';
      if (isGetOperation) {
        // get operations should not have a consumes property
        if (op.consumes) {
          messages.addMessage(
            `paths.${pathKey}.${opKey}.consumes`,
            'GET operations should not specify a consumes field.',
            config.get_op_has_consumes,
            'get_op_has_consumes'
          );
        }
      }
    });
  });
 
  return messages;
};