Bugzillaの移行完了

やっと職場のBugzillaが3系にアップグレードされました。(いろんな事情でずっとのびてました)
以前、移行方法を下調べしたときよりも時間が経ってたので、細かいところでまたビミョウにはまりました。。

細かいところ

MySQLのコンソール上でのデータ表示

コンソールで mysql コマンドで Bugzilla のデータベースに接続したとき、最初に

 SET NAMES "utf8"

とやってやらないと、SELECTとかしてデータのぞいても日本語の部分が「????」とかいう感じで文字化けする。

バグジラの設定

「パラメータ」の「Internationalization」の項では、

  • buglistmultibyteutf8 → ON に
  • utf8_decode_after_regexp → ON に
  • showbugusetextwrap → OFF に

「Localization」の項では、

  • languages の欄には「ja,en」というように記述
    • このとき、コンマの後にスペースをいれてはいけません! Software Error になります
      • やってしまった場合は、Bugzilla がインストールされているディレクトリ/data/params をエディタで開いて 'languages' のところを直す
    • この値を変更した後、Bugzilla がインストールされているディレクトリで再度 checksetup.pl を実行してテンプレートを生成する

Bugzilla 2.16 -> Bugzilla 3.0.3 完了

実はすでにできていた

少し前に、まだ途中とか書いていたけど、実はすでにアップグレードできてたっぽいという話。

フッターのメニュー「パラメータ」から、
buglistmultibyteutf8
utf8_decode_after_regexp
showbugusetextwrap
あたりをいじると、なんかちゃんと表示されるようになった。しかし、どういじるべきなのかがいまだによく分からん。とりあえず、showbugusetextwrap あたりはOffにしておかないと、メールが文字化けしたりするっぽい(まだちょっと不明)。

あと、ターゲットマイルストーンが表示されていなかったのも、パラメータで設定しなおせばOK。そうか。。このあたりの設定は、DB中にないから、アップグレードしたらOffになるんだな。。。

というわけで、最終的な手順をざっくりまとめ

  1. Bugzilla-3.0.3-ja.7 をダウンロード
  2. checksetup.pl
  • モジュールチェック、足りないものインストール
  1. localconfig ファイルが作られたら、それを編集*1
    1. データベースへの接続設定等を環境にあわせて設定
  2. 再度、checksetup.pl
  • 新しいテーブルやインデックスが作られる
  1. データの文字コードの変更を推奨されるので、Ctrl-Cで中断
  2. contrib/recode.pl のversions の定義を修正したうえで実行
  3. ./recode.pl --charset=euc-jp --show-failures
  4. 再々度、checksetup.pl
  5. ブラウザから、新バグジラにアクセス
  • 設定を変更できる権限を持つアカウントでログイン
    • (この時点では、フッターの検索条件名や、バグの詳細ページが文字化けする)
  1. フッターのメニュー「パラメータ」
    1. Internationalization の以下の項目あたりをいじる

buglistmultibyteutf8
utf8_decode_after_regexp -> このあたりOffにしないと、メールとか文字化けするっぽい?
showbugusetextwrap ->

  1. Bug Fields の設定で、以下のあたりがOffになっているのをOnにする(使ってる場合)

usetargetmilestone
useqacontact
usestatuswhiteboard

  1. その他、環境や利用方法に合わせて設定項目いじる

*1:前バージョンのコピーをあらかじめ置いておいても可

Bugzilla 2.16 -> Bugzilla 3.0 バージョンアップ移行記(まだ途中)

ちょびっと進捗。

recode.pl での処理時の versions テーブルの扱い

2.16 では、プロダクトごとに登録するバージョンが格納された versions テーブルに、プライマリーキーがなかったとして、それの代わりに以下のようなコードが contrib/recode.pl の52, 53行目に定義してあるのだが、

     52     # The 2.16 versions table lacked a PK
     53     versions          => 'product_id,value',

実際 versions テーブルに存在するカラムは program と value なので、これを

     52     # The 2.16 versions table lacked a PK
     53     versions          => 'program,value',

としてやる必要がある。

残る課題

  • 検索結果の一覧では文字化けせずに表示されるのに、バグの詳細ページや、フッターの保存された検索名が依然として文字化けしている
    • 日本語版ではなく本家の 3.0.3 を使って同じセットアップをすると大丈夫っぽいので、日本語版のアプリケーションの問題っぽい
  • ターゲットマイルストーンが検索フォームに表示されない…
    • これも上の、versions テーブルで起こってる話に近い?それか、文字化けにからむ問題か

ソフトウェアテストシンポジウム (JaSST 08) に行ってきた(初日のみ)

JaSST 08 に行ってきました。去年は2日間参加したけど、今年は初日の30日のみだけど、チュートリアルを受講してみました(会社の金で)。それも含めて、個人的なメモを残しておきます(あくまで、僕視点のまとめです)。

基調講演

SPR の Capers Jones 氏による基調講演。タイトル「Software Quality in 2008」、幅広すぎ。。

  • 万国のいろんなプロジェクトから集めた品質指標のまとめが中心
  • 不具合*1除去効率が大事
    • 「リリース前に見つけた不具合」 対 「リリース後の不具合」
  • 不具合の原因となるのは、コーディングだけじゃない
    • 要件定義、設計、ドキュメントなどでも不具合は混入する
    • むしろ、高級言語のプロジェクトほど、コーディング以外に起因する不具合が多い
    • たとえば、Y2K問題では、年が2桁で定義されていること自体が仕様バグ。だけど昔は誰も不具合とは思ってなかった
  • FP(Function Point) を使おう。LOC(Line of Code) よりも
    • LOC はコードがないと計測できない(上での、コーディング以外のバグに起因する数値をはかれない)
    • 統計的な平均値で、変換可能 (例: C言語だと 128 LOC = 1 FP, C++ だと 50 LPC = 1 FP, など)
    • FP での規模感覚をつかむための参考として、世の中のプログラムが大体どれくらいのFPか*2
      • Windows Vista は 160,000 FP くらい
      • Microsoft Office は 100,000 FP くらい
      • SAP とかは 300,000 FP くらい
      • ケータイ(の制御ソフト?) は 15,000 FP くらい
      • iPhone は 20,000 FP くらい
      • iPod は 5,000 FP くらい
      • 車の制御ソフトは 3,000 FP くらい
      • 飛行機の制御ソフトは 25,000 FP くらい
  • "Error-Prone Module" …全体の5割のバグの原因となっているモジュール
    • 50%以上のバグが、5%のモジュールによって発生しているという統計も
    • そういうモジュールは取り除き、置き換えるべき (必ずしもできる気はしないが…)
  • 要求仕様がどれくらい膨れたのかもFPで計れる
  • 不具合除去率は、CMMレベルの高い組織ほど高い
    • 最近、CMMレベルの高い企業が多いのはインドという話
  • 「FPあたりの不具合率」と「不具合除去効率」を軸とした表に、自分のプロジェクトをプロットしてみよう
    • 不具合率が 3以下で、除去率 90%以上を目指すべき
  • インスペクション大事
    • テスティング以前の、要件仕様、設計など
    • インスペクションによって、各フェーズでの不具合をそのフェーズで検出できる
  • 個別のテストやインスペクションだけでは不具合検出は十分にできない
    • 各フェーズでの各種テストを総合的に実施しないと、高い検出率は達成できない

チュートリアル

午後に入って、引き続き、Caper Jones氏のチュートリアル。内容はけっこう基調講演ともかぶる部分もあって、それは残念。

  • いろいろなインスペクションや機能テストや各種非機能テストなどについて、下記の項目などの統計情報
    • どういった種類の不具合をどの程度除去できるか
    • FPあたりどの程度の時間がかかるものか
    • FPあたりどの程度テストケースが必要なものか
  • テストプランとテストケースのインスペクションは、やってないなら是非やるべき
  • 膨らんだ要求仕様は、元の要求仕様より、潜在的な不具合が含まれる率が高く、バグ除去効率が低い
  • FP の 1.25 乗で、平均的な潜在不具合数が算出できる
    • たとえば 100 FP なら、およそ 316 の潜在的な不具合があると見積もれる
    • CMMレベルが高ければ、1.25 よりも少なくはなる
  • FP の 0.25 乗で、必要な修正フェーズ回数を見積もれる
    • 100 FP なら、およそ 3
  • FP の 1.2 乗で、最大必要なテストケースの数を見積もれる
    • 100 FP なら、およそ 251
    • 最小限必要なテストケースを見積もりたいのであれば、 1.05 乗をかける
  • FP の 0.2 乗で、テスト実施回数を見積もれる
基調講演&チュートリアルを受けての個人的な所感

基調講演の最後で、「これからの課題」みたいな項目に「自動テスト」とか「アジャイルプロジェクトのデータ」とか、個人的にキーワードになりそうなところが入ってて、へこーッとなりました。つまり、全体的にウォーターフォールモデルを前提とした話のようで、そのあたりはかなりビミョウ。。

チュートリアルの終わりで、質問者が「たとえばユニットテストのテストケース内容を修正して再度テストを実施した場合、それぞれでひとつのテストステージとカウントするのか、それとも合わせてひとつなのか?」といった質問をしたら、「なぜ同じテストを繰り返すのか理解できない」といったようなことを言っていたので、完全にウォーターフォール脳のような印象を受けました。(単純に、質問を誤解していたのかもしれませんが。。)

あと、テスト以外の、インスペクションやレビューでの不具合検出率をはかるためには、そこで見つかった不具合を個別に記録しなければいけないけれど、そのコストがけっこう高そう。

ただ、テストによるバグの検出率は今のうちのサイクルでも算出できるはず。あとは、本番バグの原因分析(仕様バグなのか、テストでの見落としなのかなど)や、メジャーリリース後のバグFixリリースでどういった項目を今まで対応してきたのかの確認などは、もうちょっとちゃんとやろうと思いました。

セッション D4 「テスト設計かじり虫」

残りの時間は、D4の小セッション3つを聞く。

「テスト分析の方法 HAYST法とマインドマップを使って」

仕様書から、機能的なカットだけでHAYST法のテストケース作るのではなく、マインドマップを使って顧客視点を盛り込むと、リスクも捉えた充実したテストケースが組めるよ、という話。顧客視点で見たときに現れる内容は暗黙知であり、経験であるが、マインドマップの各枝を知識ベースとして蓄積することで共有できる。それによって、これまでは障害として報告されてはじめて分かっていたことが、予測的にケースとして捉えることができるようになる。というような内容と理解しました。

HAYST法でテスト作ったことがないのでアレですが、今後、機能によっては参考にするといい部分があるかも。

「テストの”質”評価と欠陥分析によるソフトウェア信頼性評価」

信頼度成長曲線だけだと、テスト完了判断に使うのは微妙。テスト観点(テストの種類)ごとにテスト件数と検出されるバグ数の見積もりをたてておいて、実際に検出されるバグ数とつき合わせてフェーズごとに見ていくとより精度の高い曲線を得られるよ、という話。と理解しました。

うちも今は、実装する項目×平均検出バグ数という大雑把なかたちでしか見積もりたてていないので、このあたりの精度を上げることを考えるときに参考になるかも。少なくとも、実際に見つかったバグが、意図したタイミングに、意図したテストで出たものなのかどうか?という点はもう少し注意してみていくべきかと思いました。

「不具合に関する知識の抽出に関する研究」

バグの分析をする際、間違ったナレッジを抽出してしまわないようにしたい。そのため、誤解を招くような仕様や設計はアフォーダンスの観点から悪設計だとして、適切な原因分析のレベルに到達できるようにするべき、といった話。

正直、ちゃんと理解できた気がしていません。。プレゼンで紹介されていた例だと、「すでにメニューが表示されているときだけ、メニューボタンを押したときはメニューを表示するのではなく、メイン画面を表示する」こと、開発の際に間違いやすい(常にメニュー画面を表示するように作ってしまう)、といったことを言っていたが、この例だと、ユーザー視点からの仕様として求められているのでは?といった疑問を持ったので、いまいち納得感がありませんでした。

*1:「Defects」をとりあえずこのエントリーでは「不具合」と記述します

*2:数字はもしかしたら聞き間違えてるものあるかも…

改行コード混在ファイルの扱い

ちょっとしたPerlスクリプトをいじっていて、Windowsで保存したためにCSVファイル中の改行コードが(あたりまえだけど)CR+LFになっている文字列と、Perlのスクリプト中で組み立てた文字列との比較がなぜか一致しなくて地味にはまりました。。

http://perl.g.hatena.ne.jp/Cress/20070226/1172461972
こちらの記述を参考にして、結局は CR+LF があっても LF だけに置換するようにして対応しました。

もうこういう地味なところでひっかかるの止めたい。。

Bugzilla のバージョンアップができない。。

社内のBugzilla を、バージョン2系から3系にアップグレードしようとしてみています。3系はUTF-8が基本なのですが、これまでのデータがEUC-JPのエンコーディングだったため、変換する必要があるようです。

Bugzilla のセットアップは、checksetup.pl を実行することで設定チェックや更新作業をひととおりやってくれます。最初のセットアップ部分はここでは割愛して、データベースの接続設定などが終わった後、実行すると以下のようなデータベース更新処理のログがコンソールに出ます。

We are about to rename old indexes.
The estimated time to complete renaming is 7 minutes.
You cannot interrupt this action once it has begun.
If you would like to cancel, press Ctrl-C now... (Waiting 45 seconds...)

Renaming indexes...
Renaming index bug_id to attachments_bug_id_idx...
Renaming index creation_ts to attachments_creation_ts_idx...
Renaming index priority to bugs_priority_idx...
Renaming index reporter to bugs_reporter_idx...
Renaming index creation_ts to bugs_creation_ts_idx...
Renaming index assigned_to to bugs_assigned_to_idx...
Renaming index qa_contact to bugs_qa_contact_idx...
Renaming index votes to bugs_votes_idx...
Renaming index bug_severity to bugs_bug_severity_idx...
Renaming index bug_status to bugs_bug_status_idx...
Renaming index delta_ts to bugs_delta_ts_idx...
Renaming index version to bugs_version_idx...
Renaming index component to bugs_component_idx...
Renaming index resolution to bugs_resolution_idx...
Renaming index target_milestone to bugs_target_milestone_idx...
Renaming index product to bugs_product_idx...
Renaming index op_sys to bugs_op_sys_idx...
Renaming index bug_id to bugs_activity_bug_id_idx...
Renaming index bug_when to bugs_activity_bug_when_idx...
Renaming index fieldid to bugs_activity_fieldid_idx...
Renaming index bug_id to cc_bug_id_idx...
Renaming index who to cc_who_idx...
Renaming index blocked to dependencies_blocked_idx...
Renaming index dependson to dependencies_dependson_idx...
Renaming index sortkey to fielddefs_sortkey_idx...
Renaming index name to fielddefs_name_idx...
Renaming index bit to groups_bit_idx...
Renaming index name to groups_name_idx...
Renaming index name to keyworddefs_name_idx...
Renaming index keywordid to keywords_keywordid_idx...
Renaming index bug_id to keywords_bug_id_idx...
Renaming index lastused to logincookies_lastused_idx...
Renaming index bug_id to longdescs_bug_id_idx...
Renaming index bug_when to longdescs_bug_when_idx...
Renaming index who to longdescs_who_idx...
Renaming index product to milestones_product_idx...
Renaming index userid to namedqueries_userid_idx...
Renaming index watchfordiffs to namedqueries_watchfordiffs_idx...
Renaming index login_name to profiles_login_name_idx...
Renaming index userid to profiles_activity_userid_idx...
Renaming index profiles_when to profiles_activity_profiles_when_idx...
Renaming index fieldid to profiles_activity_fieldid_idx...
Renaming index reflected to shadowlog_reflected_idx...
Renaming index userid to tokens_userid_idx...
Renaming index bug_id to votes_bug_id_idx...
Renaming index who to votes_who_idx...
Renaming index watcher to watch_watcher_idx...
Renaming index watched to watch_watched_idx...
Building Schema object from database...
Adding new table bz_schema ...
Initializing the new Schema storage...
Adding new table attach_data ...
Adding new table bug_group_map ...
Adding new table bug_severity ...
Adding new table bug_status ...
Adding new table category_group_map ...
Adding new table classifications ...
Adding new table component_cc ...
Adding new table email_setting ...
Adding new table flagexclusions ...
Adding new table flaginclusions ...
Adding new table flags ...
Adding new table flagtypes ...
Adding new table group_control_map ...
Adding new table group_group_map ...
Adding new table namedqueries_link_in_footer ...
Adding new table namedquery_group_map ...
Adding new table op_sys ...
Adding new table priority ...
Adding new table profile_setting ...
Adding new table quips ...
Adding new table rep_platform ...
Adding new table resolution ...
Adding new table series ...
Adding new table series_categories ...
Adding new table series_data ...
Adding new table setting ...
Adding new table setting_value ...
Adding new table user_group_map ...
Adding new table whine_events ...
Adding new table whine_queries ...
Adding new table whine_schedules ...
Fixing creation time on attachments...
Warning - could not determine correct creation time for attachment 62 on bug 9117
Done - converted 214 attachments
Updating column creation_ts in table attachments ...
Old: TIMESTAMP DEFAULT 'CURRENT_TIMESTAMP'
New: datetime NOT NULL
Updating column lastused in table logincookies ...
Old: TIMESTAMP DEFAULT 'CURRENT_TIMESTAMP'
New: datetime NOT NULL
Updating column delta_ts in table bugs ...
Old: TIMESTAMP DEFAULT 'CURRENT_TIMESTAMP'
New: datetime NOT NULL
Converting attach_data maximum size to 100G...

WARNING: We are about to convert your table storage format to UTF8. This
         allows Bugzilla to correctly store and sort international characters.
         However, if you have any non-UTF-8 data in your database,
         it ***WILL BE DELETED*** by this process. So, before
         you continue with checksetup.pl, if you have any non-UTF-8
         data (or even if you're not sure) you should press Ctrl-C now
         to interrupt checksetup.pl, and run contrib/recode.pl to make all 
         the data in your database into UTF-8. You should also back up your
         database before continuing. This will affect every single table
         in the database, even non-Bugzilla tables.

         If you ever used a version of Bugzilla before 2.22, we STRONGLY
         recommend that you stop checksetup.pl NOW and run contrib/recode.pl.

         Press Enter to continue or Ctrl-C to exit...

ここで、データベースがちゃんとしていないまま、リターンキーを押すと、以下のようなメッセージが出てコケます。

Converting components.name to be stored as UTF-8...
DBD::mysql::db do failed: Duplicate entry '9-' for key 2 at Bugzilla/DB/Mysql.pm line 638

なので、リターンキーを押す代わりに、いったん Ctrl-C で終了し、上のメッセージにしたがって、 contrib/recode.pl を実行します。

./contrib/recode.pl --guess --charset=euc-jp --show-failures

そして、checksetup.pl を再実行。今度は、さっき中断したとこでReturn押して続行。すると、以下のような出力が続きますが。。。

Converting table storage format to UTF-8. This may take a while.
Converting attachments.description to be stored as UTF-8...
Converting attachments.mimetype to be stored as UTF-8...
Converting attachments.filename to be stored as UTF-8...
Converting attachstatusdefs.name to be stored as UTF-8...
Converting attachstatusdefs.description to be stored as UTF-8...
Converting attachstatusdefs.product to be stored as UTF-8...
Converting bug_severity.value to be stored as UTF-8...
Converting bug_status.value to be stored as UTF-8...
Converting bugs.bug_file_loc to be stored as UTF-8...
Converting bugs.short_desc to be stored as UTF-8...
Converting bugs.product to be stored as UTF-8...
Converting bugs.version to be stored as UTF-8...
Converting bugs.component to be stored as UTF-8...
Converting bugs.target_milestone to be stored as UTF-8...
Converting bugs.status_whiteboard to be stored as UTF-8...
Converting bugs.keywords to be stored as UTF-8...
Converting bugs_activity.added to be stored as UTF-8...
Converting bugs_activity.removed to be stored as UTF-8...
Converting classifications.name to be stored as UTF-8...
Converting classifications.description to be stored as UTF-8...
Converting components.value to be stored as UTF-8...
Converting components.program to be stored as UTF-8...
Converting components.description to be stored as UTF-8...
Converting fielddefs.name to be stored as UTF-8...
Converting fielddefs.description to be stored as UTF-8...
Converting flags.status to be stored as UTF-8...
Converting flagtypes.name to be stored as UTF-8...
Converting flagtypes.description to be stored as UTF-8...
Converting flagtypes.cc_list to be stored as UTF-8...
Converting flagtypes.target_type to be stored as UTF-8...
Converting groups.name to be stored as UTF-8...
Converting groups.description to be stored as UTF-8...
Converting groups.userregexp to be stored as UTF-8...
Converting keyworddefs.name to be stored as UTF-8...
Converting keyworddefs.description to be stored as UTF-8...
Converting logincookies.ipaddr to be stored as UTF-8...
Converting longdescs.thetext to be stored as UTF-8...
Converting milestones.value to be stored as UTF-8...
Converting milestones.product to be stored as UTF-8...
Converting namedqueries.name to be stored as UTF-8...
Converting namedqueries.query to be stored as UTF-8...
Converting op_sys.value to be stored as UTF-8...
Converting priority.value to be stored as UTF-8...
Converting products.product to be stored as UTF-8...
Converting products.description to be stored as UTF-8...
Converting products.milestoneurl to be stored as UTF-8...
Converting products.defaultmilestone to be stored as UTF-8...
Converting profile_setting.setting_name to be stored as UTF-8...
Converting profile_setting.setting_value to be stored as UTF-8...
Converting profiles.login_name to be stored as UTF-8...
Converting profiles.cryptpassword to be stored as UTF-8...
Converting profiles.realname to be stored as UTF-8...
Converting profiles.disabledtext to be stored as UTF-8...
Converting profiles.emailflags to be stored as UTF-8...
Converting profiles_activity.oldvalue to be stored as UTF-8...
Converting profiles_activity.newvalue to be stored as UTF-8...
Converting quips.quip to be stored as UTF-8...
Converting rep_platform.value to be stored as UTF-8...
Converting resolution.value to be stored as UTF-8...
Converting series.name to be stored as UTF-8...
Converting series.query to be stored as UTF-8...
Converting series_categories.name to be stored as UTF-8...
Converting setting.name to be stored as UTF-8...
Converting setting.default_value to be stored as UTF-8...
Converting setting.subclass to be stored as UTF-8...
Converting setting_value.name to be stored as UTF-8...
Converting setting_value.value to be stored as UTF-8...
Converting shadowlog.command to be stored as UTF-8...
Converting tokens.token to be stored as UTF-8...
Converting tokens.tokentype to be stored as UTF-8...
Converting tokens.eventdata to be stored as UTF-8...
Converting versions.value to be stored as UTF-8...
Converting versions.program to be stored as UTF-8...
Converting whine_events.subject to be stored as UTF-8...
Converting whine_events.body to be stored as UTF-8...
Converting whine_queries.query_name to be stored as UTF-8...
Converting whine_queries.title to be stored as UTF-8...
Converting whine_schedules.run_day to be stored as UTF-8...
Converting whine_schedules.run_time to be stored as UTF-8...
Inserting values into the 'priority' table:
'P1' sortkey: 100
'P2' sortkey: 200
'P3' sortkey: 300
'P4' sortkey: 400
'P5' sortkey: 500
Inserting values into the 'bug_status' table:
'UNCONFIRMED' sortkey: 100
'NEW'         sortkey: 200
'ASSIGNED'    sortkey: 300
'REOPENED'    sortkey: 400
'RESOLVED'    sortkey: 500
'VERIFIED'    sortkey: 600
'CLOSED'      sortkey: 700
Inserting values into the 'rep_platform' table:
'All'       sortkey: 100
'DEC'       sortkey: 200
'HP'        sortkey: 300
'Macintosh' sortkey: 400
'PC'        sortkey: 500
'SGI'       sortkey: 600
'Sun'       sortkey: 700
'Other'     sortkey: 800
Inserting values into the 'resolution' table:
''           sortkey: 100
'FIXED'      sortkey: 200
'INVALID'    sortkey: 300
'WONTFIX'    sortkey: 400
'LATER'      sortkey: 500
'REMIND'     sortkey: 600
'DUPLICATE'  sortkey: 700
'WORKSFORME' sortkey: 800
'MOVED'      sortkey: 900
Inserting values into the 'bug_severity' table:
'blocker'     sortkey: 100
'critical'    sortkey: 200
'major'       sortkey: 300
'normal'      sortkey: 400
'minor'       sortkey: 500
'trivial'     sortkey: 600
'enhancement' sortkey: 700
Inserting values into the 'op_sys' table:
'All'              sortkey: 100
'Windows 3.1'      sortkey: 200
'Windows 95'       sortkey: 300
'Windows 98'       sortkey: 400
'Windows ME'       sortkey: 500
'Windows 2000'     sortkey: 600
'Windows NT'       sortkey: 700
'Windows XP'       sortkey: 800
'Mac System 7'     sortkey: 900
'Mac System 7.5'   sortkey: 1000
'Mac System 7.6.1' sortkey: 1100
'Mac System 8.0'   sortkey: 1200
'Mac System 8.5'   sortkey: 1300
'Mac System 8.6'   sortkey: 1400
'Mac System 9.x'   sortkey: 1500
'MacOS X'          sortkey: 1600
'Linux'            sortkey: 1700
'BSDI'             sortkey: 1800
'FreeBSD'          sortkey: 1900
'NetBSD'           sortkey: 2000
'OpenBSD'          sortkey: 2100
'AIX'              sortkey: 2200
'BeOS'             sortkey: 2300
'HP-UX'            sortkey: 2400
'IRIX'             sortkey: 2500
'Neutrino'         sortkey: 2600
'OpenVMS'          sortkey: 2700
'OS/2'             sortkey: 2800
'OSF/1'            sortkey: 2900
'Solaris'          sortkey: 3000
'SunOS'            sortkey: 3100
'other'            sortkey: 3200
Removing existing compiled templates ...
Precompiling templates...
Fixing file permissions...
Adding new column 'obsolete' to the 'fielddefs' table...
Marking qacontact_accessible and assignee_accessible as obsolete fields...
Adding new column 'type' to the 'fielddefs' table...
Adding new column 'custom' to the 'fielddefs' table...
Adding new column 'enter_bug' to the 'fielddefs' table...
Renaming column 'fielddefs.fieldid' to 'fielddefs.id'...
SQL fragment found in the 'fielddefs' table...
Old field name: (to_days(now()) - to_days(bugs.delta_ts))
Fixing the 'fielddefs' table...
New field name: days_elapsed
Updating column product in table bugs ...
Old: varchar(64) DEFAULT '' NOT NULL
New: varchar(64) NOT NULL
Updating column program in table versions ...
Old: varchar(64) DEFAULT '' NOT NULL
New: varchar(64) NOT NULL
Updating column cryptpassword in table profiles ...
Old: varchar(34)
New: varchar(128)
Adding new column 'work_time' to the 'longdescs' table...
Adding new column 'estimated_time' to the 'bugs' table...
Adding new column 'remaining_time' to the 'bugs' table...
Adding new column 'deadline' to the 'bugs' table...
Adding new column 'isprivate' to the 'longdescs' table...
Adding new column 'isprivate' to the 'attachments' table...
Adding new column 'alias' to the 'bugs' table...
Adding new index 'bugs_alias_idx' to the bugs table ...
Deleting the 'watchfordiffs' column from the 'namedqueries' table...
Updating database to use product IDs.
Adding new column 'id' to the 'products' table...
Adding new column 'product_id' to the 'components' table...
Adding new column 'product_id' to the 'versions' table...
Adding new column 'product_id' to the 'milestones' table...
Adding new column 'product_id' to the 'bugs' table...
Adding new column 'product_id' to the 'attachstatusdefs' table...
Updating the database to use component IDs.
Adding new column 'id' to the 'components' table...
Adding new column 'component_id' to the 'bugs' table...
Fixing Indexes and Uniqueness.
Removing index 'milestones_product_idx' from the milestones table...
Adding new index 'milestones_product_id_idx' to the milestones table ...
Removing index 'bugs_product_idx' from the bugs table...
Adding new index 'bugs_product_id_idx' to the bugs table ...
Removing index 'bugs_component_idx' from the bugs table...
Adding new index 'bugs_component_id_idx' to the bugs table ...
Removing, renaming, and retyping old product and component fields.
Deleting the 'program' column from the 'components' table...
Deleting the 'program' column from the 'versions' table...
Deleting the 'product' column from the 'milestones' table...
Deleting the 'product' column from the 'bugs' table...
Deleting the 'component' column from the 'bugs' table...
Deleting the 'product' column from the 'attachstatusdefs' table...
Renaming column 'products.product' to 'products.name'...
Updating column name in table products ...
Old: varchar(64)
New: varchar(64) NOT NULL
Renaming column 'components.value' to 'components.name'...
Updating column name in table components ...
Old: tinytext
New: varchar(64) NOT NULL
Adding indexes for products and components tables.
Adding new index 'products_name_idx' to the products table ...
Adding new index 'components_product_id_idx' to the components table ...
Adding new index 'components_name_idx' to the components table ...
Removing index 'groups_bit_idx' from the groups table...
Removing index 'groups_name_idx' from the groups table...
Adding new column 'id' to the 'groups' table...
Adding new index 'groups_name_idx' to the groups table ...
Deleting the 'groupset' column from the 'profiles' table...
Deleting the 'blessgroupset' column from the 'profiles' table...
Deleting the 'groupset' column from the 'bugs' table...
Deleting the 'bit' column from the 'groups' table...
Converting attachment statuses to flags...
Dropping the 'attachstatuses' table...
Dropping the 'attachstatusdefs' table...
done.
Adding new column 'extern_id' to the 'profiles' table...
Adding new column 'already_wrapped' to the 'longdescs' table...
Fixing old, mis-wrapped comments...
Updating column bug_status in table bugs ...
Old: ENUM DEFAULT 'UNCONFIRMED' NOT NULL
New: varchar(64) NOT NULL
Updating column resolution in table bugs ...
Old: ENUM DEFAULT '' NOT NULL
New: varchar(64) DEFAULT '' NOT NULL
Updating column priority in table bugs ...
Old: ENUM DEFAULT 'P1' NOT NULL
New: varchar(64) NOT NULL
Updating column bug_severity in table bugs ...
Old: ENUM DEFAULT 'blocker' NOT NULL
New: varchar(64) NOT NULL
Updating column rep_platform in table bugs ...
Old: ENUM
New: varchar(64) NOT NULL
Updating column op_sys in table bugs ...
Old: ENUM DEFAULT 'All' NOT NULL
New: varchar(64) NOT NULL
Adding new index 'longdescs_thetext_idx' to the longdescs table ...
Removing paths from filenames in attachments table...
Done.
Resizing attachments.filename from mediumtext to varchar(100).
Updating column filename in table attachments ...
Old: mediumtext NOT NULL
New: varchar(100) NOT NULL
Dropping the 'shadowlog' table...
Renaming column 'votes.count' to 'votes.vote_count'...
Updating column short_desc in table bugs ...
Old: mediumtext
New: mediumtext NOT NULL
Adding new column 'classification_id' to the 'products' table...
Adding new index 'bugs_activity_who_idx' to the bugs_activity table ...
Updating column lastdiffed in table bugs ...
Old: datetime NOT NULL
New: datetime
Updating column qa_contact in table bugs ...
Old: mediumint NOT NULL
New: mediumint
Updating column initialqacontact in table components ...
Old: mediumint NOT NULL
New: mediumint
Migrating email preferences to new table...
......
Deleting the 'emailflags' column from the 'profiles' table...
Initializing "Dependency Tree Changes" email_setting ...
Updating column value in table versions ...
Old: tinytext
New: varchar(64) NOT NULL
Fixing duplicate version Ãþ¸Â訢-0 in product_id 3...
Fixing duplicate version æ¬çªå¾ in product_id 5...
Fixing duplicate version å®å® in product_id 6...
Fixing duplicate version 社åGateway in product_id 11...
Fixing duplicate version ä¼ç»å¡¾ãã¼ã¸ã§ã³ in product_id 13...
Fixing duplicate version å®å®å± in product_id 21...
Fixing duplicate version ã»ã³ãã©ã«ç­è³ãªã³ã©ã¤ã³ãã¬ã¼ã in product_id 22...
Fixing duplicate version è訢件å®ç¾© in product_id 23...
Adding new index 'versions_product_id_idx' to the versions table ...
Updating column creation_ts in table bugs ...
Old: datetime NOT NULL
New: datetime
Adding new index 'attachments_submitter_id_idx' to the attachments table ...
Migrating attachment data to its own table...
(This may take a very long time)
Deleting the 'thedata' column from the 'attachments' table...
Adding new column 'isurl' to the 'attachments' table...
Adding new column 'query_type' to the 'namedqueries' table...
Updating column cookie in table logincookies ...
Old: mediumint auto_increment NOT NULL PRIMARY KEY
New: varchar(16) NOT NULL PRIMARY KEY
Cleaning control characters from bug summaries... 3700... 4984... 4985... 4986... 4987... 5055... 12539... 12543... 12545... 12550... done.
Adding new column 'comment_id' to the 'longdescs' table...

WARNING: Some of your bugs had summaries longer than 255 characters.
They have had their original summary copied into a comment, and then
the summary was truncated to 255 characters. The affected bug numbers were:
1051, 1204, 1209, 2145, 2648, 3262, 3756, 3771, 3777, 4102, 4137, 4487, 4508, 4517, 5109, 5151, 5159, 5160, 5161, 5179, 5338, 5393, 5395, 5457, 5585, 5601, 5621, 5622, 5735, 5777, 5809, 5826, 5887, 5923, 6234, 6322, 6448, 6522, 6558, 6744, 6797, 7326, 7394, 7449, 7519, 7941, 8000, 8092, 8268, 8335, 8651, 8703, 9000, 9200, 11133, 11986, 12185, 12172, 12133, 12059, 12330, 12382, 12587, 12612, 12699, 12719

Updating column short_desc in table bugs ...
Old: mediumtext NOT NULL
New: varchar(255) NOT NULL
Adding new column 'id' to the 'namedqueries' table...
Deleting the 'linkinfooter' column from the 'namedqueries' table...
Adding new column 'disable_mail' to the 'profiles' table...
Updating column disallownew in table products ...
Old: tinyint DEFAULT 0 NOT NULL
New: tinyint DEFAULT 0 NOT NULL
Updating column id in table keyworddefs ...
Old: smallint NOT NULL PRIMARY KEY
New: smallint auto_increment NOT NULL PRIMARY KEY
Updating column userid in table tokens ...
Old: mediumint NOT NULL
New: mediumint
Updating column realname in table profiles ...
Old: varchar(255)
New: varchar(255) DEFAULT '' NOT NULL
Removing index 'longdescs_who_idx' from the longdescs table...
Adding new index 'longdescs_who_idx' to the longdescs table ...
Updating column thetext in table longdescs ...
Old: mediumtext
New: mediumtext NOT NULL
Adding new column 'type' to the 'longdescs' table...
Adding new column 'extra_data' to the 'longdescs' table...
Adding new column 'id' to the 'versions' table...
Adding new column 'id' to the 'milestones' table...
Adding new column 'mailchar' to the 'profiles' table...
Creating group editclassifications...
Creating group bz_canusewhines...
Creating group bz_sudoers...
Creating group bz_canusewhineatothers...
Creating group bz_sudo_protect...
Adding a new user setting called 'skin'
Adding a new user setting called 'quote_replies'
Adding a new user setting called 'lang'
Adding a new user setting called 'post_bug_submit_action'
Adding a new user setting called 'per_bug_queries'
Adding a new user setting called 'bug_comment_pos'
Adding a new user setting called 'zoom_textareas'
Adding a new user setting called 'csv_colsepchar'
Adding a new user setting called 'state_addselfcc'
Adding a new user setting called 'comment_sort_order'
Adding a new user setting called 'display_quips'
Creating default classification 'Unclassified'...

・・・終わってみたら、なぜか文字化けしています。。recode.pl を実行した直後にデータベースをのぞくと、ちゃんとUTF-8になっているようなのに、なぜ。。。

社内の MySQL 本体や、CPANモジュールをインフラチームにアップデートしてもらったりして、もう一歩なのに、なかなかどうして遠い Bugzilla バージョンアップへの道。

パフォーマンス・テストの種類

ひとくちにパフォーマンス・テストと言っても、何を目的とするかによって、いろいろな種類のテストがあります。パフォーマンスにまつわる会話を関係者間でしていると、そこに期待するものが違うために、時折話が食い違うこともあります。

パフォーマンス・テストを行うにあたって、どのように設計し、計画を立てるべきかを考えるのに先立って、求められている要件が何なのか整理し、目的をはっきりさせておくべきだと思います。

Performance Testing Guidance for Web Applications にアップされているドキュメントの Chapter 2 には、目的の違いによってそれぞれ種類の異なるパフォーマンステストの定義が説明されています。

自分のアタマの整理も兼ねて、主な4種類のテストが説明されている箇所を大雑把に翻訳・要約してみました。これらを念頭に置いて、ともすれば要件が混乱してしまいそうなパフォーマンステストについて、自分が行おうとしている内容の目的を見失わず、適切な手法を用いるように気をつけたいところです。

Performance Test : パフォーマンステスト

目的、メリット
  • 速度、スケーラビリティ、安定性を決定・検証するための技術的調査
    • ユーザが満足するパフォーマンスがでるかどうか検証する
    • チューニングや最適化を支援する
難しいところ、目的としないところ
  • 機能的な不具合を検出できるとは限らない
  • 注意深く設計しないと、運用シナリオのほんの一部しかカバーできない
  • 実運用で用いるハードウェアと全く同様の環境でない限り、結果にはある程度の不確かさが付きまとう
象徴的な質問
  • 「十分な速度(レスポンス)が出るか?」

Load Test : 負荷テスト

目的
  • 実運用での、通常時/ピーク時の負荷に対して耐えうるかの検証
    • ピーク時に十分なスループットが発揮できるか
    • ハードウェアやロードバランサーが適切か
    • 並行処理にまつわる問題や機能的なエラーを検出する
    • パフォーマンスが劣化する前にサポートできるユーザ数の測定や、ハードウェアのリソースが限界に達する負荷量の計測を助ける
  • しばしばSLAで定義されたパフォーマンス要求を目的とする
  • 耐久テスト(endurance test) はこれのサブセット。長期間の負荷下での振る舞いの診断に特化したもの
難しいところ、目的としないところ
  • レスポンスの速さを見ることを優先して設計されるものではない
  • テスト結果は、他の関連する負荷テストと相対的な比較でのみ有効
  • 負荷がノーマルの状態→ピークの状態と推移させて、想定負荷に耐えられるか検証する
象徴的な質問
  • 「全ユーザをサポートできるか?」

Stress Test : ストレステスト

  • 実運用での想定利用モデル下で、負荷量と負荷サイズの増大させ、過負荷な状態で発生するバグ(同期の問題、競合条件、メモリーリークなど)を検出するため
    • どの程度の状況で、(遅くなるだけではなく)エラーが起こるか
    • 過負荷時にデータの破損やセキュリティ的な脆弱性が発生しないか
    • エラーの事前検知のために何をモニタリングしておくべきか
  • Spike test*1 はこれのサブセット。短時間に繰り返し急な負荷を与えた場合の検証に特化したもの
難しいところ、目的としないところ
  • 仮定するストレスの状態が非現実的なため、テスト結果が関係者に無視されるかも
  • どれくらいのストレスを与えるのが適切なのか知るのは難しい
  • テスト環境が独立していないと、アプリケーションやネットワークなどに深刻な被害をもたらす可能性がある
象徴的な質問
  • 「何かおかしくなったとき何が起こるか?」

Capacity Test : キャパシティ(処理能力)テスト

目的
  • パフォーマンス要件を満たしつつ、どの程度のユーザやトランザクションをさばけるか検証するため
    • 将来的なユーザ数やデータ量の増加に対して、どういったリソース(CPU性能、メモリ使用量、HDD容量、ネットワーク帯域など)を拡充すべきかのプランニングのための調査となる
    • プランニングのために、現在のリソースの使われ方や処理能力の傾向をつかめる
難しいところ、目的としないところ
  • 処理能力の検証モデルの構築は難しい
  • 一回のテストで、処理能力のすべての面を検証することはできない
象徴的な質問
  • 「ユーザが増えたとき何を増やせばいいか?」

*1:適切な訳語が分からない。ちなみに [http://eow.alc.co.jp/spike/UTF-8/:title=spike の意味]の中では「〔グラフなどの〕急な山形」がこの場合、負荷のかたちを示すものということで適切か