Y-Ken Studio

新しもの好きのデータエンジニアが四方山話をお届けします。

Appraisalを用いた、Fluentdプラグインの後方互換性を保てるテスト方法 #Fluentd

2015年にはFluentd v0.12系が主流となってきましたが、まだ古いv0.10系を利用している環境も残っていると思います。
プラグイン開発する上では、Fluentdの後方互換性が保てているかのテストもTravis-CIで行いたいですよね。

その時にどのように行うのか、メモを残しておきたいと思います。
また、どのようにAppraisalsを使い、手元でバージョンを使い分けたテストが実行できるかも紹介します。

マイナーバージョン違いのFluentd毎にテストを実行する

td-agent1系とtd-agent2系で採用されているそれぞれのFluentdバージョンでテストを実行します。

次のように編集することで、複数のバージョンそれぞれでテストが実行できるようになります。

cf. https://github.com/y-ken/fluent-plugin-twitter/pull/22/files

diff --git a/.travis.yml b/.travis.yml
index 43ef400..9d916eb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -9,3 +10,9 @@ rvm:
 
 before_install:
   - gem update bundler
+
+gemfile:
+  - Gemfile
+  - gemfiles/fluentd_v0.10.gemfile
+  - gemfiles/fluentd_v0.12.gemfile
+
diff --git a/Appraisals b/Appraisals
new file mode 100644
index 0000000..ec90e47
--- /dev/null
+++ b/Appraisals
@@ -0,0 +1,8 @@
+appraise "fluentd v0.10" do
+  gem "fluentd", "~> 0.10.46"
+end
+
+appraise "fluentd v0.12" do
+  gem "fluentd", "~> 0.12.0"
+end
+
diff --git a/fluent-plugin-twitter.gemspec b/fluent-plugin-twitter.gemspec
index 59cbf45..747d2b8 100644
--- a/fluent-plugin-twitter.gemspec
+++ b/fluent-plugin-twitter.gemspec
@@ -17,6 +17,7 @@ Gem::Specification.new do |s|
 
   s.add_development_dependency "rake"
   s.add_development_dependency "test-unit", ">= 3.1.0"
+  s.add_development_dependency "appraisal"
   s.add_runtime_dependency "fluentd", ">= 0.10.46"
   s.add_runtime_dependency "twitter", ">= 5.0.0"
   s.add_runtime_dependency "tweetstream", ">= 2.6.1"
diff --git a/gemfiles/fluentd_v0.10.gemfile b/gemfiles/fluentd_v0.10.gemfile
new file mode 100644
index 0000000..5ababf3
--- /dev/null
+++ b/gemfiles/fluentd_v0.10.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "http://rubygems.org"
+
+gem "fluentd", "~> 0.10.46"
+
+gemspec :path => "../"
diff --git a/gemfiles/fluentd_v0.12.gemfile b/gemfiles/fluentd_v0.12.gemfile
new file mode 100644
index 0000000..058b6cf
--- /dev/null
+++ b/gemfiles/fluentd_v0.12.gemfile
@@ -0,0 +1,7 @@
+# This file was generated by Appraisal
+
+source "http://rubygems.org"
+
+gem "fluentd", "~> 0.12.0"
+
+gemspec :path => "../"

Fluentd v0.10.x ではFilterのテストを除外する

Fluentd v0.10系ではFilterをサポートしておりません。
このため、uninitialized constant Fluent::Filterエラーが発生しないよう、後述するテストの除外指定が必要です。

$ bundle exec rake
/home/travis/.rvm/rubies/ruby-2.3.0/bin/ruby -I"lib:lib:test" -I"/home/travis/.rvm/gems/ruby-2.3.0/gems/rake-10.5.0/lib" "/home/travis/.rvm/gems/ruby-2.3.0/gems/rake-10.5.0/lib/rake/rake_test_loader.rb" "test/**/test_*.rb" 
/home/travis/build/y-ken/fluent-plugin-anonymizer/lib/fluent/plugin/
filter_anonymizer.rb:2:in `<module:Fluent>': uninitialized constant Fluent::Filter (NameError)

テストを除外する実装例としては次の通りです。

cf. Omit test when `Fluent::Filter` is not defined · y-ken/fluent-plugin-anonymizer@b48c382 · GitHub

diff --git a/test/helper.rb b/test/helper.rb
index 9f0ce2a..ae21d27 100755
--- a/test/helper.rb
+++ b/test/helper.rb
@@ -23,7 +23,10 @@ def method_missing(method, *args)
 end
 
 require 'fluent/plugin/out_anonymizer'
-require 'fluent/plugin/filter_anonymizer'
+if Fluent.const_defined?(:Filter)
+  require 'fluent/plugin/filter_anonymizer'
+end
+
 
 class Test::Unit::TestCase
 end
diff --git a/test/plugin/test_filter_anonymizer.rb b/test/plugin/test_filter_anonymizer.rb
index 2813b4a..df1e33a 100644
--- a/test/plugin/test_filter_anonymizer.rb
+++ b/test/plugin/test_filter_anonymizer.rb
@@ -2,6 +2,7 @@
 
 class AnonymizerFilterTest < Test::Unit::TestCase
   def setup
+    omit_unless(Fluent.const_defined?(:Filter))
     Fluent::Test.setup
     @time = Fluent::Engine.now
   end

テストの実行

依存関係を解決するため、appraisal installを実行します。
ここではbundler経由でappraisalを入れているため、次のような実行結果となります。

cf. https://github.com/thoughtbot/appraisal#usage

$ bundle exec appraisal install
Warning: Your gemfiles directive in .travis.yml is incorrect. Run `appraisal generate --travis` to get the correct configuration.
>> bundle check --gemfile='/***/fluent-plugin-twitter/gemfiles/fluentd_v0.10.gemfile' || bundle install --gemfile='/***/fluent-plugin-twitter/gemfiles/fluentd_v0.10.gemfile'
Resolving dependencies...
The Gemfile's dependencies are satisfied
>> bundle check --gemfile='/***/fluent-plugin-twitter/gemfiles/fluentd_v0.12.gemfile' || bundle install --gemfile='/***/fluent-plugin-twitter/gemfiles/fluentd_v0.12.gemfile'
Resolving dependencies...
The Gemfile's dependencies are satisfied

複数バージョンでテストするため、appraisal rake testコマンドを実行します。

$ bundle exec appraisal rake test
>> BUNDLE_GEMFILE=/***/fluent-plugin-twitter/gemfiles/fluentd_v0.10.gemfile bundle exec rake test
/Users/***/.rbenv/versions/2.2.0/bin/ruby -I"lib:lib:test" -I"/***/fluent-plugin-twitter/vendor/bundle/ruby/2.2.0/gems/rake-10.5.0/lib" "/***/fluent-plugin-twitter/vendor/bundle/ruby/2.2.0/gems/rake-10.5.0/lib/rake/rake_test_loader.rb" "test/**/test_*.rb"
Loaded suite /***/fluent-plugin-twitter/vendor/bundle/ruby/2.2.0/gems/rake-10.5.0/lib/rake/rake_test_loader
Started
...

Finished in 0.650067 seconds.
---------------------------------------------------------------------------------------------------------------------------------------
3 tests, 15 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
---------------------------------------------------------------------------------------------------------------------------------------
4.61 tests/s, 23.07 assertions/s
>> BUNDLE_GEMFILE=/***/fluent-plugin-twitter/gemfiles/fluentd_v0.12.gemfile bundle exec rake test
/Users/***/.rbenv/versions/2.2.0/bin/ruby -I"lib:lib:test" -I"/***/fluent-plugin-twitter/vendor/bundle/ruby/2.2.0/gems/rake-10.5.0/lib" "/***/fluent-plugin-twitter/vendor/bundle/ruby/2.2.0/gems/rake-10.5.0/lib/rake/rake_test_loader.rb" "test/**/test_*.rb"
Loaded suite /***/fluent-plugin-twitter/vendor/bundle/ruby/2.2.0/gems/rake-10.5.0/lib/rake/rake_test_loader
Started
...

Finished in 0.172614 seconds.
---------------------------------------------------------------------------------------------------------------------------------------
3 tests, 15 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
---------------------------------------------------------------------------------------------------------------------------------------
17.38 tests/s, 86.90 assertions/s

それぞれのFluentdバージョンを用いたテストもクリアした事が確認できました。