API GatewayからAWS Lambdaを呼び出しリクエストボディで指定したrubocopのspecを実行する

つづき

hanachin.hateblo.jp

API Gatewayをつくる

雑に/にPOSTメソッド追加

POSTメソッドでリクエストパラメータでspecのパスをうけとりたいので、モデルとして定義する

なまえは適当に「SpecPaths」 コンテンツタイプは「application/json」でよかろう スキーマはこんな感じ(雑すぎ)

{
  "type": "array",
  "items": {
    "type": "string"
  }
}

リクエストボディにモデルを追加して、テストをする。リクエストボディは以下。

["spec/rubocop/cop/naming/constant_name_spec.rb"]

無事かえってきた。 けどtrueがかえってくる。昨日のハンドラーの設定が雑すぎである。 formatterにJSONを指定して一旦ファイルに書き出してからファイルの内容を読んで返す。 書き込む先は/tmpじゃないとread only file systemの怒られが発生する。 あと1回パースしてハッシュにしておかないといい感じのJSONがかえらない(JSONを更に文字列でJSON化したみたいな感じになってしまう)

require 'rubygems'
require 'bundler/setup'

ENV['HOME'] = '/var/task/tmp/home'
def lambda_handler(event:,context:)
  ARGV.clear
  ARGV << '--require'
  ARGV << 'spec_helper'
  ARGV << '--format'
  ARGV << 'j'
  ARGV << '--out'
  ARGV << '/tmp/result.json'
  ARGV.concat(event)
  version = ">= 0.a"
  load Gem.activate_bin_path('rspec-core', 'rspec', version)
  JSON.parse(File.read('/tmp/result.json'))
end

無事実行できたっぽい

{
  "version": "3.8.0",
  "messages": [
    "Run options: include {:focus=>true}",
    "\nAll examples were filtered out; ignoring {:focus=>true}"
  ],
  "seed": 6739,
  "examples": [
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:20]",
      "description": "checks qualified const names",
      "full_description": "RuboCop::Cop::Naming::ConstantName checks qualified const names",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 112,
      "run_time": 0.462345188,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:16]",
      "description": "does not check names if rhs is a `Struct.new` with conditional assign",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check names if rhs is a `Struct.new` with conditional assign",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 90,
      "run_time": 0.056915878,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:14]",
      "description": "does not check names if rhs is a `Class.new` with conditional assign",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check names if rhs is a `Class.new` with conditional assign",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 82,
      "run_time": 0.000736561,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:18]",
      "description": "does not check if rhs is another constant",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check if rhs is another constant",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 102,
      "run_time": 0.000392198,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:12]",
      "description": "does not check names if rhs is a method call with conditional assign",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check names if rhs is a method call with conditional assign",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 74,
      "run_time": 0.000314527,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:11]",
      "description": "does not check names if rhs is a method call",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check names if rhs is a method call",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 70,
      "run_time": 0.000308152,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:3]",
      "description": "registers an offense for camel case in const namewhen using frozen object assignment",
      "full_description": "RuboCop::Cop::Naming::ConstantName registers an offense for camel case in const namewhen using frozen object assignment",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 21,
      "run_time": 0.000509685,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:19]",
      "description": "does not check if rhs is a non-offensive const assignment",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check if rhs is a non-offensive const assignment",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 106,
      "run_time": 0.000353758,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:10]",
      "description": "allows screaming snake case with POSIX upper case characters",
      "full_description": "RuboCop::Cop::Naming::ConstantName allows screaming snake case with POSIX upper case characters",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 66,
      "run_time": 0.058376074,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:17]",
      "description": "does not check names if rhs is a method call with block",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check names if rhs is a method call with block",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 94,
      "run_time": 0.000621489,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:15]",
      "description": "does not check names if rhs is a `Struct.new`",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check names if rhs is a `Struct.new`",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 86,
      "run_time": 0.000435203,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:6]",
      "description": "registers an offense for snake case in const name",
      "full_description": "RuboCop::Cop::Naming::ConstantName registers an offense for snake case in const name",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 44,
      "run_time": 0.000380298,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:4]",
      "description": "registers an offense for non-POSIX upper case in const name",
      "full_description": "RuboCop::Cop::Naming::ConstantName registers an offense for non-POSIX upper case in const name",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 29,
      "run_time": 0.000560681,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:8]",
      "description": "allows screaming snake case in const name",
      "full_description": "RuboCop::Cop::Naming::ConstantName allows screaming snake case in const name",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 58,
      "run_time": 0.036730939,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:5]",
      "description": "registers offenses for camel case in multiple const assignment",
      "full_description": "RuboCop::Cop::Naming::ConstantName registers offenses for camel case in multiple const assignment",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 36,
      "run_time": 0.000646392,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:9]",
      "description": "allows screaming snake case in multiple const assignment",
      "full_description": "RuboCop::Cop::Naming::ConstantName allows screaming snake case in multiple const assignment",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 62,
      "run_time": 0.000390919,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:2]",
      "description": "registers an offense for camel case in const namewhen using frozen range assignment",
      "full_description": "RuboCop::Cop::Naming::ConstantName registers an offense for camel case in const namewhen using frozen range assignment",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 13,
      "run_time": 0.000480596,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:1]",
      "description": "registers an offense for camel case in const name",
      "full_description": "RuboCop::Cop::Naming::ConstantName registers an offense for camel case in const name",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 6,
      "run_time": 0.000325353,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:7]",
      "description": "registers 1 offense if rhs is offending const assignment",
      "full_description": "RuboCop::Cop::Naming::ConstantName registers 1 offense if rhs is offending const assignment",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 51,
      "run_time": 0.00038332,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:13]",
      "description": "does not check names if rhs is a `Class.new`",
      "full_description": "RuboCop::Cop::Naming::ConstantName does not check names if rhs is a `Class.new`",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 78,
      "run_time": 0.000369682,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:21:1:1]",
      "description": "does not check names",
      "full_description": "RuboCop::Cop::Naming::ConstantName when a rhs is a conditional expression when conditional branches contain only constants does not check names",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 123,
      "run_time": 0.057168639,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:21:2:1]",
      "description": "does not check names",
      "full_description": "RuboCop::Cop::Naming::ConstantName when a rhs is a conditional expression when conditional branches contain a value other than a constant does not check names",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 129,
      "run_time": 0.000738712,
      "pending_message": null
    },
    {
      "id": "./spec/rubocop/cop/naming/constant_name_spec.rb[1:21:3:1]",
      "description": "registers an offense",
      "full_description": "RuboCop::Cop::Naming::ConstantName when a rhs is a conditional expression when conditional branches contain only string values registers an offense",
      "status": "passed",
      "file_path": "./spec/rubocop/cop/naming/constant_name_spec.rb",
      "line_number": 135,
      "run_time": 0.00063151,
      "pending_message": null
    }
  ],
  "summary": {
    "duration": 0.719273616,
    "example_count": 23,
    "failure_count": 0,
    "pending_count": 0,
    "errors_outside_of_examples_count": 0
  },
  "summary_line": "23 examples, 0 failures"
}

あとはAPIのデプロイで雑にproductionステージを作ってデプロイする。

% curl -X POST -d '["spec/rubocop/cop/naming/constant_name_spec.rb"]' ざつに認証かけてない秘密のURL

さっきのスクリプト何度か実行するとエラーになる、RSpecの結果がファイルに書き足されていった結果JSONじゃなくなっちゃうっぽい。なおす。

require 'rubygems'
require 'bundler/setup'
require 'json'
require 'time'

ENV['HOME'] = '/var/task/tmp/home'
def lambda_handler(event:,context:)
  output_path = '/tmp/result-%s.json' % Time.now.iso8601
  ARGV.clear
  ARGV << '--require'
  ARGV << 'spec_helper'
  ARGV << '--format'
  ARGV << 'j'
  ARGV << '--out'
  ARGV << output_path
  ARGV.concat(event)
  version = ">= 0.a"
  load Gem.activate_bin_path('rspec-core', 'rspec', version)
  JSON.parse(File.read(output_path))
end

これでなおったけど、何度か実行すると結果のexampleの数が増えてく。リセットされてなさそう。雑にRSpec.resetする。

require 'rubygems'
require 'bundler/setup'
require 'json'
require 'time'

ENV['HOME'] = '/var/task/tmp/home'
def lambda_handler(event:,context:)
  output_path = '/tmp/result-%s.json' % Time.now.iso8601
  ARGV.clear
  ARGV << '--require'
  ARGV << 'spec_helper'
  ARGV << '--format'
  ARGV << 'j'
  ARGV << '--out'
  ARGV << output_path
  ARGV.concat(event)
  version = ">= 0.a"
  load Gem.activate_bin_path('rspec-core', 'rspec', version)
  RSpec.reset
  JSON.parse(File.read(output_path))
end

これだと今度はうまく動かない。リセットされすぎ。RSpec.clear_examplesする。

require 'rubygems'
require 'bundler/setup'
require 'json'
require 'time'

ENV['HOME'] = '/var/task/tmp/home'
def lambda_handler(event:,context:)
  output_path = '/tmp/result-%s.json' % Time.now.iso8601
  ARGV.clear
  ARGV << '--require'
  ARGV << 'spec_helper'
  ARGV << '--format'
  ARGV << 'j'
  ARGV << '--out'
  ARGV << output_path
  ARGV.concat(event)
  version = ">= 0.a"
  load Gem.activate_bin_path('rspec-core', 'rspec', version)
  RSpec.clear_examples
  JSON.parse(File.read(output_path))
end

うまく動いた!! イェイ!

考え

リアルワールドRailsアプリケーションとかでやるとteardown漏れててうまく動かないみたいな問題が起こりえそうで怖い...

とりあえずこれでPOSTでファイルパス投げたらテスト実行できるようになったので、雑にGoとかででリクエスト投げまくって結果まってマージして書き出すみたいなの書けば全ファイル同時実行できそうな気がする。

いいなと思ったらKyashでお金を下さい
20191128011151
GitHubスポンサーも受け付けています
https://github.com/sponsors/hanachin/