endokのブログ

IT・プログラミングネタ

Ansibleでgenerator-angular-fullstackのセットアップ

Ansibleでgenerator-angular-fullstackを使える状態にするtask設定例。
CentOS6.5用。

- name: node.jsのインストール
  yum: name="{{ item }}" enablerepo=epel
  with_items:
    - nodejs
    - npm 

- name: npmの更新
  npm: name=npm global=yes state=latest

- name: node.jsパッケージのインストール
  npm: name="{{ item }}" global=yes
  with_items:
    - yo
    - bower
    - grunt-cli
    - generator-angular-fullstack

compassをインストールする場合は、下記を追加。
(rubyは設定済とする)

- name: compassのインストール
  gem:
    name=compass
    user_install=no
    executable=/usr/local/bin/gem

ハマった部分として、yumでインストールしたnpmを再度npmで最新に更新しないと
yoのバージョンが古くなってしまいgenerator-angular-fullstackのインストールに失敗するということ。

generator-angular-fullstackでnpm installの際にgifsicleのインストールエラー

generator-angular-fullstackでgenerate後、npm install時にgifsicle@0.1.7のインストールエラーが発生。

> gifsicle@0.1.7 postinstall /home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle
> node index.js

⚠ pre-build test failed, compiling from source...
|
stream.js:94
      throw er; // Unhandled stream error in pipe.
            ^
Error: invalid tar file
    at Extract.Parse._startEntry (/home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle/node_modules/bin-build/node_modules/download/node_modules/decompress/node_modules/tar/lib/parse.js:145:13)
    at Extract.Parse._process (/home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle/node_modules/bin-build/node_modules/download/node_modules/decompress/node_modules/tar/lib/parse.js:127:12)
    at BlockStream.<anonymous> (/home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle/node_modules/bin-build/node_modules/download/node_modules/decompress/node_modules/tar/lib/parse.js:47:8)
    at BlockStream.emit (events.js:95:17)
    at BlockStream._emitChunk (/home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle/node_modules/bin-build/node_modules/download/node_modules/decompress/node_modules/tar/node_modules/block-stream/block-stream.js:145:10)
    at BlockStream.resume (/home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle/node_modules/bin-build/node_modules/download/node_modules/decompress/node_modules/tar/node_modules/block-stream/block-stream.js:58:15)
    at Extract.Reader.resume (/home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle/node_modules/bin-build/node_modules/download/node_modules/decompress/node_modules/tar/node_modules/fstream/lib/reader.js:255:34)
    at DirWriter.<anonymous> (/home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle/node_modules/bin-build/node_modules/download/node_modules/decompress/node_modules/tar/lib/extract.js:57:8)
    at DirWriter.emit (events.js:92:17)
    at /home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-gifsicle/node_modules/gifsicle/node_modules/bin-build/node_modules/download/node_modules/decompress/node_modules/tar/node_modules/fstream/lib/dir-writer.js:39:8

実際は最初のnpm install時には気づいておらず、grunt serve:dist時にimageminタスクでエラーになって気づいた。

ググるGitHubのissuesが見つかる。
npm install gifsicle@0.1.7 fails · Issue #36 · imagemin/gifsicle-bin · GitHub

package.jsonのgrunt-contrib-imageminのバージョンを0.8.1に上げて、再度インストール。

"grunt-contrib-imagemin": "~0.8.1"
$ rm -rf node_modules/grunt-contrib-imagemin
$ npm install
(省略)
> pngquant-bin@0.3.5 postinstall /home/endok/mean/node_modules/grunt-contrib-imagemin/node_modules/imagemin/node_modules/imagemin-pngquant/node_modules/pngquant-bin
> node index.js

⚠ pre-build test failed, compiling from source...
✖ pngquant failed to build, make sure that libpng-dev is installed

{ [Error: Command failed: make: *** `lib/libimagequant.a' に必要なターゲット `config.mk' を make するルールがありません.  中止.
] killed: false, code: 2, signal: null }

gifsicleはインストール成功するもpngquant-binのエラー。
libpng-devをインストールする。

$ sudo yum install libpng-devel

その後、再びnpm installで成功。

$ rm -rf node_modules/grunt-contrib-imagemin
$ npm install
(省略)
✔ pngquant built successfully!

grunt-contrib-coffeeでは最初のドットまでが同じcoffeeファイルは連結される

軽い気持ちでMEANスタックに触ってみたところ、npm,Gruntなどなど慣れないものばかりでハマりまくっています。

今回はcoffeeファイルをjsファイルに変換する際のGruntの挙動についてです。

現象

generator-angular-fullstackで生成したアプリケーションにて、
下記のようなcoffeeファイルがある場合。

$ ls client/app/main
main.coffee  main.controller.coffee

grunt serveで起動したHTMLを見てみると、

<script src="app/main/main.js"></script>

という記述のみで、main.controller.jsの読み込みはない。

main.jsの中身を見るとmain.coffeeとmain.controller.coffeeを連結した中身になっていた。

grunt-contrib-coffeeの挙動として連結されているのか?それとも別のプラグインの影響なのか?検証してみる。

検証

適当なフォルダにgrunt-contrib-coffeeを試すためのファイルを配置する。

{
  "name": "coffee",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "grunt": "^0.4.5",
    "grunt-contrib-coffee": "^0.12.0"
  }
}
  • Gruntfile.js
module.exports = function(grunt) {
  grunt.initConfig({
    coffee: {
      compile: {
        files: [{
          expand: true,
          cwd: 'src/',
          src: ['**/*.coffee'],
          dest: 'dest/',
          ext: '.js',
        }]  
      }   
    }   
  }); 
  grunt.loadNpmTasks('grunt-contrib-coffee');
  grunt.registerTask('default', 'coffee');
};
  • src/sample.coffee
variable = 100
  • src/sample.test.coffee
variable = 50

設置できたら、npmパッケージをインストールしてcoffeeタスクを実行。

$ npm install
$ grunt coffee

すると、
dest/sample.js
が出力される。

中身は

(function() {
  var variable;

  variable = 100;

}).call(this);

(function() {
  var variable;

  variable = 50;

}).call(this);

となっており、sample.coffeeとsample.test.coffeeが連結されていることが確認できる。

同様に、

  • src/sample.coffee
  • src/sample.test.coffee
  • src/sample2.coffee
  • src/sample2.test.coffee

の4ファイルを配置した場合、

  • dest/sample.js
  • dest/sample2.js

の2ファイルが生成される。

まとめ

結論としては、grunt-contrib-coffeeが複数ファイルコンパイルを行うときにこういった連結を行うということで良さそうです。
知っている人には当然ぽい挙動かと思いますが、何で検索したらいいかわからずでした。
近い話題としては下記が見つかりました。
coffeescript - grunt-contrib-coffee one-to-one compile - Stack Overflow
Gruntの理解にはまだまだかかりそうです。

gitをソースからインストールしようとすると、Can't locate ExtUtils/MakeMaker.pm in @INCエラー

Vagrantの"chef/centos-6.5"ボックスにソースからgitを入れようとしたときのこと。

Git - Gitのインストール
にある通り、

yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel

を行ってから、

wget https://github.com/git/git/archive/v2.0.1.zip -O git.zip
unzip git.zip
cd git-2.0.1
make prefix=/usr/local all
make prefix=/usr/local install

すると、

Can't locate ExtUtils/MakeMaker.pm in @INC (@INC contains: /usr/local/lib64/perl5 /usr/local/share/perl5 /usr/lib64/perl5/vendor_perl /usr/share/perl5/vendor_perl /usr/lib64/perl5 /usr/share/perl5 .) at Makefile.PL line 3.
BEGIN failed--compilation aborted at Makefile.PL line 3.
make[1]: *** [perl.mak] Error 2
make: *** [perl/perl.mak] Error 2

というエラー。

追加で、

yum install perl-ExtUtils-MakeMaker

を実行後に再度インストールで無事完了。

Chefのdarkfish documentationでRDoc::Error

MacOSX 10.9.3 にて。

久々にgemを更新しようと、

$ gem update

したところ、

Installing darkfish documentation for chef-11.12.8
ERROR:  While executing gem ... (RDoc::Error)
    error generating /Users/endok/.rbenv/versions/2.0.0-p353/lib/ruby/gems/2.0.0/doc/chef-11.12.8/rdoc/lib/chef/streaming_cookbook_uploader_rb.html: Error while evaluating /Users/endok/.rbenv/versions/2.0.0-p353/lib/ruby/2.0.0/rdoc/generator/template/darkfish/page.rhtml: undefined method `chomp' for nil:NilClass (RDoc::Error)

のエラー。

ググると、同じような問題を発見。
ruby - Error installing rails-4.0.0 - Stack Overflow

rdocを更新すればよいとのことなので、

$ gem update rdoc
Updating installed gems
Updating rdoc
Fetching: rdoc-4.1.1.gem (100%)
rdoc's executable "rdoc" conflicts with /Users/endok/.rbenv/versions/2.0.0-p353/bin/rdoc
Overwrite the executable? [yN]  y
rdoc's executable "ri" conflicts with /Users/endok/.rbenv/versions/2.0.0-p353/bin/ri
Overwrite the executable? [yN]  y
Depending on your version of ruby, you may need to install ruby rdoc/ri data:

<= 1.8.6 : unsupported
 = 1.8.7 : gem install rdoc-data; rdoc-data --install
 = 1.9.1 : gem install rdoc-data; rdoc-data --install
>= 1.9.2 : nothing to do! Yay!
Successfully installed rdoc-4.1.1
Parsing documentation for rdoc-4.1.1
Installing ri documentation for rdoc-4.1.1
Installing darkfish documentation for rdoc-4.1.1
Gems updated: rdoc

と無理やり上書きしてみる。

その後もう一度、

$ gem update

で更新成功。

AMIとEBS、スナップショットの関係がよくわかっていなかった話

AWSの話。
AWS使っている方であれば当たり前に理解している話かと思います。

AMIとEBS

インスタンス起動時にAMIが読み込まれ、
EBSは追加データを保存する場所なのかなと思っていたのだけど、
どこからどこまでがEBSに保存されるんだ?などどいまいち腑に落ちていなかった。

で、ちゃんと調べてみたところ、

Amazon マシンイメージ(AMI)は、ソフトウェア構成(オペレーティングシステムアプリケーションサーバー、アプリケーションなど)を記録したテンプレートです。AMI から、クラウドで仮想サーバーとして実行される AMI のコピーであるインスタンスを起動します。
(http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/ec2-instances-and-amis.html)

AMI には次が含まれています。

インスタンスのルートボリュームのテンプレート(オペレーティングシステムアプリケーションサーバー、アプリケーションなど)

起動許可(AMI を使用してインスタンスを起動する権限を特定の AWS アカウントに与える)

インスタンスの起動時にインスタンスにアタッチするボリュームを指定するブロックデバイスマッピング
(http://docs.aws.amazon.com/ja_jp/AWSEC2/latest/UserGuide/AMIs.html)

ということで、

AMI = EC2インスタンスの元となるテンプレート
EBS = インスタンス作成時にAMIから情報がコピーされる場所

というのが正しかったようだ。
つまりAMIが起動されるという考え方が間違っていて、

インスタンス作成時にAMIのテンプレート内容がEBSにコピー

その後はEBSからインスタンスが起動される

といった形になるらしい。

AMIとスナップショット

ではAMI ≒ EBSスナップショットなのか?ということで調べてみると、そのものずばりの解説記事を発見。

AWS Solutions Architect ブログ: AWSトレーニングでよくいただくご質問シリーズ - 第一回 Amazon Machine Image (AMI) とスナップショットの違い

AMI = EBSスナップショット + α(管理情報)
とのこと。

おわりに

これまでもやっととしていた部分が理解できてすっきり。
個人の範疇なので本格的に利用するのは難しいが、しばらくAWSを触ってみようと思う。

間違い、指摘等あればコメントお願いします。

xUnit Test PatternsのPART Ⅰ読んだ+テストに関する雑感

ようやくPART Ⅰまで読み終わったので忘れないうちに感想など。

xUTPという略語で呼ばれたり、読書会が開かれていたりと、ソフトウェアテスト本としてかなり評判が良い様子。

Kindle版を買ってみたものの

  • ボリュームが多い(ハードカバー版だと900ページ超えとのこと)
  • 日本語版がない

ということで長らく放置していた。

最近仕事でも自動テストを導入しつつあるので、ようやく読んでみた。

xUTPを読んで

全体の構成は、PART Ⅰで各パターンに触れながらテストに関する戦略や思想を解説、PART Ⅱ、PART Ⅲは各"Test Smell"やテストパターンの解説となっている。
(PofEAAのような構成)

とりあえずPART Ⅰに目を通しておけば良さそうだったので、PART Ⅰのみ読了。
PART Ⅰだけでも1ヶ月ぐらいはこの本を読んでいた気がする。
やはり英語はつらい。

内容的はxUnitに限らないのはもちろん、単体テストにも限らず自動テスト全般を対象にしていて、かなり網羅的。
ほとんどの話は誰もが一度は経験するようなあるある系なのだけれど、きちっとそれらに名前を付け、メリット・デメリットを整理しているところが良い。
整理した上で、"ベストプラクティスはこれだ"という話をするのでなくて、"こういったトレードオフになりますよ"という立ち位置なのも現実的で良かった。

結局は対象とするシステムやプロジェクトの性質や制約によってベストプラクティスは変わってくるものなので、変に正解を出されるよりも誠実だと思った。

あとは他の書籍でも使われるような言葉の定義("Mock"、"Test Double"など)も行っているので、その辺が気になる人にもいいと思う。

テストについて最近思うこと

さてテストを書こう、という時にいつも思うのが、"保守性の高いテストを書くにはどうしたらよいか?"ということ。
テストを書いてみたものの、その後メンテされず(せず)に二度と実行されない状態をしばしば見てきた。
テスト失敗しそうだからテスト実行しづらいし、新しいテストも書きづらいという悪循環。

特にテストの粒度について気になっていて、

など、考え出すともやもやが止まらない。

時と場合によるという話なのだろうが、自分なりの基準を持っておきたいところ。

xUTP を参考に

xUTPでもその辺りは当然取り上げられている。

単体テストの依存関係

Chapter4の"State or Bahavior Verification?"で、

  • "statist"は、テスト対象がテスト後に望んだ状態になったかを検証する
  • "behaviorist"は、テスト後の状態だけでなく、テスト対象がテスト中に依存コンポーネントをどう呼んでいるかも検証する
    (No.2342/25720)

とある。
つまり、MockやStubをガンガン使うのが"behaviorist"ということ。

"behaviorist"なテストは、テストの独立性を高めるが、リファクタリングが行いづらくなる。
(No.2358/25720)

で、この"behaviorist"なテストをやりすぎると、"Overspecified Software(Chapter16)"になってしまう。
問題点は、

ソフトウェアが何を為すべきかでなく、ソフトウェアがどのように為すべきか、をテストが表現してしまう
(No.2571/25720)

こと。

上記を踏まえて極力MockやStubを使わないテスト(statist)とMockやStubを使ったテスト(behaviorist)の特徴を整理してみる。

statist

behaviorist

で、この辺りの話の自分の結論としては、「MockやStubを使う特別な理由がない限りは使わない」。
特別な理由というのは、テストの実行速度だったり、Mockを使わないと検証できなかったり、外部サービスに依存していたり、など。
リファクタリングの頼りにテストを使いたいという気持ちが強いし、Mockを使ったテストを書いていると何をテストしているんだっけ?という気分になる。
著者の考えもこの路線のようだ。

単体テスト結合テスト

単体テスト結合テストも定義を用意してくれている。
多分に用語の問題を含むが、ここでは単純に単体テスト=UnitTest、結合テスト=ComponentTestとして考えている。

Unit testは、設計の結果としての1つのクラスまたはメソッドの振る舞いを検証する。 この振る舞いは、ビジネスロジックがクラスやメソッドカプセル化されている場合を除き、要求に直接関係するものではない。 これらのテストは開発者が利用するために書かれる。 テストの形式で、そのユニットの振る舞いを要約して表現する。
 
Component testは、何らかのサービスを提供するクラスの集合コンポーネントを検証する。 テスト対象の範囲の点で、Unit testとCustomer testの中間に位置する。 "integration tests","subsystem tests"と呼ぶ人たちもいるが、それらは"システム全体の中の特定の一部のまとまったコンポーネントのテスト"とは異なったものを意味している。
(No.2733/25720)

このあたりの記述をもとに考えると、

単体テスト:1つのメソッドが意図通り実装できているかのテスト
結合テスト:複数クラスを組み合わせて実現する機能が正しく動作するかのテスト

といった観点で見ればよい気がした。

結論

テストについて考える時の前提知識または材料として、読んでおくとよいと思う。
テスト方針だったり、困っていることだったりに対してどういった考え方があるのか?というのが参考になる。
なんだかテストいまいちなんだけど、このやり方はしょうがないのかなー他にいいやり方あるのかなーという方におすすめ。
あとKindle版のが安いし用語にリンクが貼ってあっておすすめ。