29 Apr 2013, 07:25

音楽の速度をコマンドラインから自由自在に操れる!多機能すぎるオープンソースの音楽再生ソフト『VLC メディアプレイヤー』

音楽の速度をコマンドラインから操作する方法を探していたら、いいソフトを見つけたので紹介。

VLCメディアプレーヤー

VLCメディアプレーヤーはいわゆる音楽再生用のメディアプレイヤー。音楽再生に必要な機能はある程度実装されているようだ。

特徴は、マルチプラットフォーム、対応コーデックが豊富ということだが、自分がVLCで特に気に入ったのは、

  • オープンソースであること
  • 豊富すぎるコマンドラインインタフェース(やりたいことは全てできそう)

である。

VLCを使ってみる

ダウンロードは以下から。インストーラを立ちあげてインストール。

VideoLAN – オープンソースのビデオフレームワークであるVLCメディアプレイヤーの公式ホームページ

外見はこんな感じ。

skitch.png

速度調整をするためには、ツールバーの[表示] > [ステータスバー]にチェックを入れる。下に[1.00x]という表示が現れるので、マウスでドラッグして変更する。再生中の音楽をリアルタイムで変更できる。0.01単位で変更できるようだ。

また、ネットワーク上のファイルを開くことができるようだ。ツールバーの[メディア] > [ネットワークストリームを開く]を選択して、URLを入れる。youtube の再生もできる。

skitch.png

 

コマンドラインからVLCを操作する

環境

  • Windows 7 64bit(ただし、32bit版をインストールした)

コマンドラインからVLC起動

まずは基本から。コマンドラインからVLCを立ち上げるには、まずはコマンドプロンプトを起動。インストールしたディレクトリに移動して、vlcに再生したいファイルを引数にして実行する。

C:\Users\TSUNEMICHI>cd "C:\Program Files (x86)\VideoLAN\VLC"
C:\Program Files (x86)\VideoLAN\VLC>vlc Concerto_for_Orchestra.m4a

VLCをRCインターフェイスで操作する

VLCをRCモードで立ち上げることで、コマンドラインからいろいろと操作できる。

$ vlc -I rc [ファイル名やディレクトリ名]

で起動すると、新しいコンソールが立ち上がる。ここにコマンドを打ち込んで、いろいろと操作する。対応コマンドは helpと打ちこむとずらずらと出てくる。以下の操作がコマンドラインからできる。

help

+—-[ リモートコントロールコマンド ]

|

| add XYZ … … … … . XYZ をプレイリストに追加

| enqueue XYZ … … . . XYZをプレイリストにキューイング

| playlist … … . 現在のプレイリスト中にある項目を表示

| play … … … … … … . . ストリーム再生

| stop … … … … … … . . ストリーム停止

| next … … … … … . 次のプレイリストの項目

| prev … … … … … . 前のプレイリストの項目

| goto … … … … . インデックスにある項目に移動

| リピート [オン|オフ] … プレイリストのリピートの切り替え

| loop [on|off] … … . . プレイリストループの切り替え

| ramdom [on|off] … … … . ランダム再生の切り替え

| clear … … … … … . プレイリストのクリア

| status … … … … . . 現在のプレイリストの状態

| title [X] … … … 現在の項目のタイトルを設定/取得

| title_n … … … … . 現在の項目の次のタイトル

| title_p … … … … . 現在の項目の前のタイトル

| chapter [X] … … . 現在の項目のチャプターを設定/取得

| chapter_n … … … . . 現在の項目の次のチャプター

| chapter_p … … … . . 現在の項目の前のチャプター

|

| seek X … … . 再生中インスタンスのジャンプ先指定(秒)

| pause … … … … … . . 再生停止の切り替え

| fastforward … … … … … . 最大倍率に設定

| rewind … … … … … … . 最低倍率に設定

| faster … … … … … ストリームの早送り再生

| slower … … … … … . ストリームの遅延再生

| normal … … … … … . ストリームの通常再生

| frame … … … … … . . フレームごとに再生

| f [on|off] … … … … . . 全画面表示の切り替え

| info … … … … … . 現在のストリームの情報

| stats … … … … … … . 統計情報の表示

| get_time … … … . ストリームの最初からの経過時間

| is_playing … … … . ストリーム再生中:1, その他:0

| get_title … … … . . 現在のストリームのタイトル

| get_length … … … … . 現在のストリームの長さ

|

| volume [X] … … … … … . 音量の設定/取得

| volup [X] … … … … 音量を X ステップ分上げる

| voldown [X] … … … . . 音量を X ステップ分下げる

| adev [X] … … … . オーディオデバイスの設定/取得

| achan [X] … … … オーディオチャンネルの設定/取得

| atrack [X] … … … オーディオトラックの設定/取得

| vtrack [X] … … … . . ビデオトラックの設定/取得

| vratio [X] … … . . ビデオのアスペクト比の設定/取得

| vcrop [X] … … … ビデオのクロッピングの設定/取得

| vzoom [X] … … … … . ビデオズームの設定/取得

| snapshot … … … . . ビデオスナップショットを撮る

| strack [X] … … … … 字幕トラックの設定/取得

| key [hotkey name] … … ホットキー操作のシミュレート

| menu …[on|off|up|down|left|right|select] メニューの使用

|

| help … … … … … . . このヘルプメッセージ

| longhelp … … … … … 長いヘルプメッセージ

| logout … … … … 終了する(ソケット接続の場合)

| quit … … … … … … … . VLCを終了

|

+—-[ ヘルプの終り ]

さらに、key [hotkey name](ホットキー操作のシミュレート)を使えば、上記にない操作もできる。[hotkey name]に対応する名前は以下のページに載っている。

Hotkeys table – VideoLAN Wiki

速度変更に関わるキーは以下。

  • Faster key-faster 50%速度を上げる
  • Slower key-slower 50%速度を下げる
  • Normal rate key-rate-normal 通常の速度
  • Faster (fine) key-rate-faster-fine 10%速度を上げる
  • Slower (fine) key-rate-slower-fine 10%速度を下げる

たとえば、10%だけ速度を上げる場合は、[key key-rate-faster-fine]と打ち込む。

VLCサーバにコマンドラインから速度変更を依頼する

起動中のVLCにコマンドを送って操作するために、telnet通信を利用することができる。まずは、VLCをサーバとして起動する。[–rc-host [ホストアドレス]:[Port番号]]のオプションをつける。

vlc -I rc –rc-host localhost:8080

そうすると、telnetコマンドでサーバにアクセスすることができる。アクセスしたらコマンドを投げればよい。

telnet localhost 8080

クライアント側からリモートのホストに通信してコマンドを実行するためには、Linuxではこういう書き方もあるみたい。Windowsでも、Cygwinではできたけれども、コマンドプロンプトからだと、やりかたがワカラなかった。

$ (sleep 0.05;echo key key-slower;sleep 0.05)|telnet localhost 8080

2011年11月25日 VLCをショートカットキーからリモート制御する方法 telnet編:FreeBSD Daily Topics|gihyo.jp … 技術評論社

参考リンク

 

28 Apr 2013, 06:32

組込み開発のシステムテスト・機能テストを自動化できるか?Rubyのminitestで非同期テストを実施する方法を本気出して考えてみた

はじめに

非同期な振る舞いをxUnitでテストできたらいいなと思った。具体的には、コンソールからコマンドを打ち込んで標準出力に現れたメッセージをアサートできればいいなと思った。

そういうツールを探してみたのだが、ちょっと探しただけでは見つからなかった。teratermマクロ(TTL)では、コンソールにコマンドを打ち込んでアサートということは簡単に実現できたが、xUnitのような機能、

  • SetUp
  • Teardown
  • テストの実行
  • テスト結果の集計

を自分で実装するのがけっこう大変そうだった。いろいろ調べていると、linuxで標準出力を監視するコマンドでexpectというのがある。これは、RubyやPythonでも同様なツールがあるようだ。

この記事では、GUIはSelenium、CLIはPexpectを利用すれば、どんな自動化テストも可能だと欠かれている。

Quick test automation using Pexpect and Selenium | thoughts from the test eye

そこで今回は、Rubyのminitestライブラリとexpectライブラリを利用して、非同期テストができそうかどうか探ってみた。

TODO

会社では、組み込みソフトの開発をC言語でしているのだが、実機を使ったテストをするときは、実機の目の前に置いてあるゲートウェイPCからシリアルケーブルでボードにアクセスしたり、GUI/CLIをいろいろいじったりしている。

ゲートウェイPCには、Rubyもexpectコマンドもインストールされていないので、自分のCygwinからゲートウェイPCにtelnetして、ウラウラコマンドを送りつけられたらいいなとおもった。なので、今回は以下のようなことを試してみて、実際に実現可能かどうかを探ってみた。

  • サーバにtelnetする。(expect,pty)
  • サーバ上でディレクトリを作成する(mkdir)。
  • ディレクトリが作成できたかどうかをチェックする(lsコマンド)。
  • 複数のテストを実行する。(minitest)
  • タイムアウトを使ってテストの失敗を検出する。(timeout)

サーバにtelnetする

サーバ上でディレクトリを作成する(mkdir)

Rubyを使ってサーバにtelnetしてコマンドを実行する方法は前回記事にしたので、そっちを参照。

Ruby から サーバ上にパスワードなしでtelnetログイン(expect,pty) | Futurismo

#!/usr/bin/env ruby
require 'pty'
require 'expect'

# ログイン情報を入力
hostname="ubuntu"
username="tsu-nera"
password="*******"

# expect で読み込んだ内容を標準出力に出力するおまじない
$expect_verbose=true

PTY.spawn("telnet -l #{username} #{hostname}") do |r,w|
w.sync = true
r.expect(/Password: /) { w.puts "#{password}" }
r.expect(/[$%#]/) { w.puts "mkdir testdir" }
r.expect(/[$%#]/) { w.puts "exit" }
end

ディレクトリが作成できたかどうかをチェックする(lsコマンド)

ちゃんとmkdirでtestdirが作成されたかかを、lsコマンドで画面に表示して確認する。

#!/usr/bin/env ruby 

....

r.expect(/[$%#]/) { w.puts "mkdir testdir" }

r.expect(/[$%#]/){ w.puts "ls" }
r.expect("testdir")

r.expect(/[$%#]/) { w.puts "exit" }
end

しかし、この方法だとtestdirが存在すれば処理が先にすすむのだが、失敗するとずっと待たされる(9999999秒?)。

タイムアウトを使ってテストの失敗を検出する。(timeout)

Rubyのtimeoutライブラリを利用して、タイムアウトを検出する。

library timeout

require ‘timeout’でライブラリを読み込む。タイマを貼りたい場所で、タイムアウトした場合の例外も考慮してて、以下のように書く。

  
begin

timeout(タイムアウト値) { 処理 }

rescue

タイムアウトした時の例外処理

end
#!/usr/bin/env ruby 

require 'timeout'

....

r.expect(/[$%#]/) { w.puts "mkdir testdir" }

r.expect(/[$%#]/){ w.puts "ls" }
begin
    timeout(3) { r.expect("testdir", 5) }
rescue Timeout::Error => ex
      w.puts "exit"
      puts ex.message
      return ex.class
end

r.expect(/[$%#]/) { w.puts "exit" }
end

複数のテストを実行する。(minitest)

ここから、Rubyライブラリのminitest/unitライブラリを利用して、複数テストを書く。

library minitest/unit

あまり、ベストな方法ではない気がするが、こんなようにしてみた。

  • スクリプト風に書いていたものをクラスに置き換える。
  • 実行したいテストケースごとにメゾッドを作成して、テストスイートから順次呼び出す
  • telnet処理はSetUp/Teardownへ移動して複数テストから呼び出せるようにする。

tc_mkdir_expect.rb

$ cat tc_mkdir_expect.rb
#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'pty'
require 'expect'
require 'timeout'

# expect で読み込んだ内容を標準出力に出力するおまじない
$expect_verbose=true

class MkdirExpect
  # ログイン情報を入力
  @@hostname="ubuntu"
  @@username="tsu-nera"
  @@password="*******"

  def setup
    # telnet通信を確立
    @pty = PTY.spawn("telnet -l #{@@username} #{@@hostname}")
    @sin = @pty[0]
    @sout= @pty[1]
    @pid = @pty[2]

    @sout.sync=true
    @sin.expect("Password:"){ @sout.puts "#{@@password}" }
  end

  def teardown
    # telnet通信の終了
    @sin.expect(/[$%#]/){@sout.puts "exit" }
  end

  def mkdir_testdir
    # Setup
    @sin.expect(/[$%#]/){
      @sout.puts "test -f testdir || rmdir testdir"
    }

    # Test
    @sin.expect(/[$%#]/){ @sout.puts "mkdir testdir" }

    # Verify
    @sin.expect(/[$%#]/){ @sout.puts "ls" }
    @sin.expect("testdir")

    # teardown
    return 0
  end

  def mkdir_two_directory
    # Setup
    @sin.expect(/[$%#]/){ @sout.puts "test -f dir1 || rmdir dir1" }
    @sin.expect(/[$%#]/){ @sout.puts "test -f dir2 || rmdir dir2" }

    # Test
    @sin.expect(/[$%#]/){ @sout.puts "mkdir dir1" }
    @sin.expect(/[$%#]/){ @sout.puts "mkdir dir2" }

    # Verify
    @sin.expect(/[$%#]/){ @sout.puts "ls" }
    @sin.expect("dir1")
    @sin.expect(/[$%#]/){ @sout.puts "ls" }
    @sin.expect("dir2")

    # teardown
    return 0
  end

  def mkdir_timeout
    # Setup
    @sin.expect(/[$%#]/){
      @sout.puts "test -f testdir || rmdir testdir"
    }

    # Test
    @sin.expect(/[$%#]/){ @sout.puts "mkdir testdir" }

    # Verify
    @sin.expect(/[$%#]/){ @sout.puts "ls" }
    begin
      timeout(3) { @sin.expect("testdir2", 5) }
    rescue Timeout::Error => ex
      @sout.puts "exit"
      puts ex.message
      return ex.class
    end

    # teardown
    return 0
  end
end

次は、テストスイート。これは公式リファレンスを見よう見まねで作成。

ts_mkdir_expect.rb

# -*- coding: utf-8 -*-
require 'minitest/unit'
require 'minitest/autorun'
require './tc_mkdir_expect'

class TestMkdirExpect < MiniTest::Unit::TestCase
  def setup
    @foo = MkdirExpect.new
    @foo.setup
  end

  def teardown
    @foo.teardown
    @foo = nil
  end

  def test_testdir
    assert_equal 0,@foo.mkdir_testdir
  end

  def test_mkdir_two_directory
    assert_equal 0,@foo.mkdir_two_directory
  end

  def test_mkdir_timeout
    assert_equal Timeout::Error,@foo.mkdir_timeout
  end

end

テスト結果

最後に、テストを実行してみる。なかなかよさげだ。

$ ruby ts_mkdir_expect.rb

Finished tests in 37.559148s, 0.0799 tests/s, 0.0799 assertions/s.

3 tests, 3 assertions, 0 failures, 0 errors, 0 skips

テストケースごとにテストを実行することもできる。

$ ruby ts_mkdir_expect.rb -n test_mkdir_timeout

タイムアウトで失敗させると、それなりのメッセージがでる。

Finished tests in 16.746958s, 0.0597 tests/s, 0.0597 assertions/s.

1) Failure:

test_mkdir_timeout(TestMkdirExpect) [ts_mkdir_expect.rb:27]:

Expected: 0

Actual: Timeout::Error

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

終わりに

実際にテストできるかどうかはまだまだ試行錯誤が必要そうだ。実際の仕事で適用するためには、後処理から正常な状態に復旧させる処理が最大の課題だと思っている。あとメンテナンスも。

なんとなく、可能性だけはつかめた気がしたので、いろいろと隠れて遊んでみようと思う。

27 Apr 2013, 10:50

Ruby から サーバ上にパスワードなしでtelnetログイン(expect,pty)

前回までは、sshやシェルスクリプトのexpectコマンドでサーバへのログインについて書いて来ました。今回は、Rubyを使って、サーバにログインする方法を調べてみました。

Expect コマンドでパスワードなしでログインする方法(telnet,ssh,scp) | Futurismo

環境

前回と同じように、CygwinからUbunsuサーバに接続してみる。

  • 接続先: ubuntu
  • 接続元: cygwin
  • Ruby 1.9.3

net/telnetライブラリを利用して、telnetする

Rubyでtelnetを利用するためには、net/telnetライブラリを読み込んで利用します。公式リファレンスはココ。

class Net::Telnet

ポイントは以下

  • require ‘net/telnet’
    telnet用のライブラリを読み込む
  • new
    telnetオブジェクトを生成して、リモートホストと接続。
  • login
    ユーザ名とパスワードを用いてログインする
  • cmd
    コマンドを実行する。
  • close
    telnetを終了する。
# -*- coding: utf-8 -*-
require 'net/telnet'

# リモートホスト  に接続
# タイムアウトは 10 秒
telnet = Net::Telnet.new("Host" => "192.168.118.129",
                         "Timeout" => 10)

# ログインし、プロンプトが出るまで待ち合わせる
telnet.login("tsu-nera", "*******") {|c| print c}

# ls コマンドを実行し、実行後、プロンプトが出るまで待ち合わせる
telnet.cmd("ls") {|c| print c}

# ログインセッションの終了
telnet.cmd("exit") {|c| print c}
telnet.close


Expectコマンドを利用した時よりも、実行速度は遅い。そして、interactのような、telnetの途中で標準入出力をキーボードに切り替える方法もないようだ。

ただし、シェルスクリプトに比べてずっとコードが綺麗。

pyt,expectを利用してtelnetする

こっちが本題。Rubyにもシェルスクリプトと同様なexpectがあった。これを利用する。

pytは擬似tty(Pesude tty)。

module PTY

これで、擬似的にttyを生成して、標準入出力を操作する。

#!/usr/bin/env ruby
# -*- coding: utf-8 -*-
require 'pty'
require 'expect'

# ログイン情報を入力
hostname="ubuntu"
username="tsu-nera"
password="*******"

# expect で読み込んだ内容を標準出力に出力するおまじない
$expect_verbose=true

PTY.spawn("telnet -l #{username} #{hostname}") do |r,w|
w.sync = true
r.expect(/Password: /) { w.puts "#{password}" }
r.expect(/[$%#]/) { w.puts "ls" }
r.expect(/[$%#]/) { w.puts "exit" }
end

21 Apr 2013, 12:32

恐るべきレガシーコードの救世主になるか?!ドロドロ依存なモジュールたちを『CMock』ですっ裸にする

はじめに

仕事では、今までは新規開発だった。なので、真っ白なテキストからテストを書くことができた。しかし、これからは、流用開発。既存コードに機能追加しなければならない。そしてその既存コードはうんざりするほどの量があり、かつテストは1つもない。。。

1つのファイルは5000行くらいあって、インクルードはし放題。インターフェイスもごちゃまぜな感じ。そもそも、ヘッダファイルがソースコードごとにない!テストを通そうにも、うんざりするほどのUndef関数を作成しなければならず、実行ファイルも自力では作れなさそうだ。。。

そんなゲームオーバーで泣きたくなるような状況でも、なんとかテスト環境を構築する方法を模索していた。Undef関数をヘッダファイルから自動生成するツールがどうしても欲しかった。そこで、いろいろと探した所、”CMock”がよさそうだったので、今日は遊んでみた。

CMockとは

CMockとは、C言語用のモッキングフレームワーク。

Throw The Switch! – White Papers – CMock Intro

 

 

以下、概要を日本語訳。

CMock はヘッダファイルからモックインターフェイスを生成する小粋なツールです。CMockによって依存関係のあるモジュールをより簡単にUnitTestすることができます。

int DoesSomething(int a, int b);

…自動的にDoesSomething関数が生成され、実際のDoesSomething関数の代わりにリンクすることができます。このモック化されたものをつかうことによって、期待したデータをモジュールが受け取ったかを検証することができ、モジュールからどんなデータでも望むように返すことができます。あなたが欲しいエラーを返すことだって、もっともっと・・・隣接する実際の最新モジュールの振る舞いはなんだって作り出し、瞬時にしてあなたは以下のような力を得るのです。

“オレは作った出来立てのモジュールのあらゆる細部をコントロールし、検証できるのだ!”

このことをより簡単にするために、CMockでは以下のような関数郡も用意しています。なのでテストごとに、その生成されたDoesSomething関数に、どのように振る舞うのかをきけばよいのです。

void DoesSomething_ExpectAndReturn(int a, int b, int toReturn);
void DoesSomething_ExpectAndThrow(int a, int b, iEXCEPTION_T error);
void DoesSomething_StubWithCallback(CMOCK_DoesSomething_CALLBACK YourCallback);
void DoesSomething_IgnoreAndReturn(int toReturn);

これらの関数を次々に重ねあわせていくことで、あなたがなにを検証したいのかを意識させます。こんなふうに、

test_CallsDoesSomething_ShouldDoJustThat(void)
{
    DoesSomething_ExpectAndReturn(1,2,3);
   
DoesSomething_ExpectAndReturn(4,5,6);
   
DoesSomething_ExpectAndThrow(7,8, STATUS_ERROR_OOPS);

    CallsDoesSomething( );
}

このテストはCallsDoesSomethingを呼びます。これが、われわれがテストしたい関数です。この関数がDoesSomethngを3回呼ぶことを期待しています。初めは、DoesSomething(1,2)で呼ばれることを確かに確認し、魔法のように3を返します。二回目は、DoesSomething(4,5)で呼ばれることを確認し、6を返します。3回めはDoesSomething(7,8)で呼ばれて値の代わりにエラーを投げます。もしCallsDoesSomethingがこの通りでないならば、テストは失敗します。DoesSomethingを呼ばなくても、呼びすぎても、また間違った引数でよんでも、間違った順番で読んでも、テストは失敗します。

CMockはUnityをベースにしています。そしてそれは、全ての内部でのテストに使われています。CMockは全ての作業でRubyを使います(version 1.8.6 – 1.9.2)

CMockのダウンロード

CMockのダウンロードは以下のサイトから。

CMock プロジェクト日本語トップページ – SourceForge.JP

githubでも公開されている。

$ git clone git://github.com/ThrowTheSwitch/CMock.git .

(補足)git cloneだと、vendor配下にあるunityとc_expectionがダウンロードできなかった。それぞれを追加で持ってくる。

$ git clone git://github.com/ThrowTheSwitch/Unity.git vendor/unity
$ git clone git://github.com/ThrowTheSwitch/CException.gitvendor/c_exception/ vendor/c_expeption

CMockをとりあえず動かしてみる

事前にRuby と rakeをインストールしておくことが必要。

examples配下で実行

とりあえず、ちゃんとダウンロードできたかどうかを確認するために、examples配下に移動して以下を実行。(mocksとbuildディレクトリをつくっておかないとエラーした(´・_・`))

$ cd examples/
$ mkdir mocks
$ mkdir build
$ rake

それっぽいモック生成メッセージとテストが走ってやや感動するはず。最後までテストが通らなかったけれども、とりあえずよしとしよう。

cmock配下で実行

つづいて、cmockインストールディレクトリでrakeを実行。

$ rake
rake aborted!
cannot load such file — rspec/core/rake_task

rspecがないよといわれるのでrspecをインストールする。

$ gem install rspec

再度rakeを実行すると以下のエラー。

/usr/lib/ruby/1.9.1/rubygems/custom_require.rb:36:in `require’: cannot load such file — hardmock (LoadError)

hardmockをインストールする。

$ gem install hardmock

再度rakeを実行て、それっぽいテストが動作した。ヤタ───v(-∀-)v───♪

CMockの使い方

これも、原文をそのまま日本語訳してしまう。

CMockはRubyスクリプトとクラスです。なので、コマンドラインから直接リヨ出来ます。また、自分のスクリプトやrakeファイルにインクルードできます。

コマンドラインからモックする

CMockを解凍したら、’lib’ディレクトリ内にCMock.rbがある。これが動作させるものです。モックするためには、ヘッダファイルのリストが必要です。それとともに、より詳細な構成をしていするためには、オブションとしてyamlファイルが必要です。(configration optionの章を参照)

たとえば、これは構成をMyConfig.ymlで指定して、3つのモックを生成する。

ruby cmock.rb -oMyConfig.yml super.h duper.h awesome.h

これは、デフォルト構成で2つのモックを生成する。

ruby cmock.rb ../mocking/stuff/is/fun.h ../try/it/yourself.h

スクリプトやRakeからモックする

CMockはスクリプトやRakeファイルから直接利用できる。cmock.rbをインクルードして、CMockの実装を生成する。実装を生成したら、3つのうちのいずれかの方法で初期化する。

なにも指定しなければ、デフォルトの設定で動作させることになる。
cmock = CMock.new

YAMLファイルを指定することで、好きな構成オプションを指定できる。
cmock = CMock.new(‘../MyConfig.yml’)

例外として、オプション指定可能。
cmock = Cmock.new(:plugins => [:cexception, :ignore], :mock_path => ‘my/mocks/’)

既存コードにcmockを組み込んで実行する

ここからが本題。一つのファイル(モジュール)をテストしたい時、他のファイルが存在しなくてもテストを実行するために、Undef関数をcmockで自動生成したい。

cmockと同じgithub上にあった、以下のサンプルを利用する。

git clone git://github.com/ThrowTheSwitch/CMockExample.git .

src/LedControl.cをテストしたいとする。普通にコンパイルしようとすると、当然怒られる。

$ gcc src/LedControl.c
/tmp/ccsR1nMW.o:LedControl.c:(.text+0x14): undefined reference to `_GPIO_SetPin’
/tmp/ccsR1nMW.o:LedControl.c:(.text+0x28): undefined reference to `_GPIO_SetPin’
/tmp/ccsR1nMW.o:LedControl.c:(.text+0x68): undefined reference to `_GPIO_ClearPin’
/tmp/ccsR1nMW.o:LedControl.c:(.text+0x7c): undefined reference to `_GPIO_ClearPin’
/usr/lib/gcc/i686-pc-cygwin/4.5.3/../../../libcygwin.a(libcmain.o): In function `main’:
/usr/src/debug/cygwin-1.7.17-1/winsup/cygwin/lib/libcmain.c:39: undefined reference to
`_WinMain@16′
collect2: ld はステータス 1 で終了しました

モックを生成する。モックを生成するためのディレクトリを作成して、コマンド実行。

$ mkdir mocks
$ ruby ../lib/cmock.rb src/Gpio.h src/main.h src/System.h
Creating mock for Gpio…
Creating mock for main…
Creating mock for System…
$ ls mocks/
MockGpio.c  MockGpio.h  Mockmain.c  Mockmain.h  MockSystem.c  MockSystem.h

おお、感動的だ。゚(●’ω’o)゚。

ココからが独自カスタマイズ。必要な部品をunityプロジェクト、cmockプロジェクトからカレントディレクトリにかき集めてくる。

  • unity/src/unity.c  unity.h unity_internals.h
  • unity/auto/*
  • cmock/lib/*
  • cmock/config/*
  • cmock/src/cmock.c cmock.h

rakeをよく知らんので、Makefileもちょろっと書いてmakeしてみる。Makefileって自動生成できないのかな。。

TARGET_BASE = LedControl
TARGET_EXTENSION=.exe
TARGET = $(TARGET_BASE)$(TARGET_EXTENSION)

Unity Files

SRC_FILES = src/unity.c

CMock Files

SRC_FILES += src/cmock.c

Source Files

SRC_FILES += src/LedControl.c SRC_FILES += test/test_LedControl.c SRC_FILES += build/test_LedControl_Runner.c

SRC_FILES += mocks/mock_Gpio.c SRC_FILES += mocks/mock_main.c SRC_FILES += mocks/mock_System.c

INC_DIRS =-Isrc INC_DIRS +=-Imocks

SYMBOLS=-DTEST -DUNITY_SUPPORT_64

CLEANUP = rm -f build/*.o ; rm -f $(TARGET); mkdir -p build

all: clean default

default: ruby auto/generate_test_runner.rb test/test_LedControl.c build/test_LedControl_Runner.c ruby lib/cmock.rb src/Gpio.h ruby lib/cmock.rb src/main.h ruby lib/cmock.rb src/System.h $(C_COMPILER) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES) -o $(TARGET) ./$(TARGET)

clean: $(CLEANUP)

>
> >

> このままだと、mocks/Mock*というモックオブジェクトが生成される。test_と結合しようとするとエラーしたので、lib/CMockConfigでmock_prefixを変更する。 >

> >
>

> :mockprefix => ‘mock’, >

>
> >

> 再度実行してみる。 >

> >
>

> $ make

rm -f build/*.o ; rm -f LedControl.exe  ; mkdir -p build

>
>

> ruby auto/generate_test_runner.rb test/test_LedControl.c build/test_LedControl_Runner.c >

>
>

> ruby lib/cmock.rb src/Gpio.h >

>
>

> Creating mock for Gpio… >

>
>

> ruby lib/cmock.rb src/main.h >

>
>

> Creating mock for main… >

>
>

> ruby lib/cmock.rb src/System.h >

>
>

> Creating mock for System… >

>
>

> gcc  -Isrc  -Imocks  -DTEST -DUNITY_SUPPORT_64 src/unity.c  src/cmock.c  src/LedControl.c  test/test_LedControl.c  build/test_LedControl_Runner.c mocks/mock_Gpio.c mocks/mock_main.c mocks/mock_System.c -o LedControl.exe >

>
>

> ./LedControl.exe >

>
>

> test/test_LedControl.c:13:test_LedControl_TurnLedOn_should_turn_on_GPIO_pin_1_when_turning_on_the_red_LED:PASS >

>
>

> test/test_LedControl.c:22:test_LedControl_TurnLedOn_should_turn_on_GPIO_pin_2_when_turning_on_the_blue_LED:PASS >

>
>

> test/test_LedControl.c:31:test_LedControl_TurnLedOff_should_turn_off_GPIO_pin_1_when_turning_off_the_red_LED:PASS >

>
>

> test/test_LedControl.c:40:test_LedControl_TurnLedOff_should_turn_off_GPIO_pin_2_when_turning_off_the_blue_LED:PASS >

>
>

> ———————– >

>
>

> 4 Tests 0 Failures 0 Ignored >

>
>

> OK >

>
>

> 。゚(●’ω’o)゚。おお、感動的だ。゚(●’ω’o)゚。 >

>
>

> 果たして、このツールは泥沼スパゲッティコードを断ち切る勇者となるか、使えない愚者になるか。まだまだ評価が必要そうだ。 >

>
>

> これさえあれば、どんなに依存関係があって、Undef関数だらけなコンパイルエラーを攻略できそうだ。たとえそれが、10000行くらいのソースコードであっても・・・orz?? >

>
>

> ああ、無情。でもガンバルじゃん。 >

>
>

> おまけ  書籍の紹介 >

>
>

> Embedded Testing with Unity and CMock >

>
>

> UnityとCMockの使い方について、電子書籍とペーパーブックが出ている。6ドルくらい。 >

>
>

> Embedded Testing with Unity and CMock by Mark VanderVoord (eBook) – Lulu >

>
>

>
>

>
>

> 内容はとても異色だ。まず、ページが正方形なのが、なんかおかしい。物語形式で話が進んでいく。途中に可愛い?!マンガチックなイラストがたくさんでてくる。文学表現が初めの方はおおくて、知らない単語が多かったりした。前半がUnityの話、後半がCMockの話。 >

>
>

> UnityとCMockの使い方が分かる本『Embedded Testing with Unity and CMock』を読んだ | Futurismo >

>
>

> test driven development for embedded c >

>
>

> UnityおよびCMockについては、以下の書籍でも話題にでている。 >

>
> >
>

> (電子書籍はここから)

http://pragprog.com/book/jgade/test-driven-development-for-embedded-c >

>
>

> Unityはけっこうベージが割かれているけれども、CMockについては2ページくらい。どちらかというと、Mockを自力で作成するためのアイデアに役に立つ。 >

>
>

> そろそろ『test driven development for embedded c』について書いてみる | Futurismo >

21 Apr 2013, 11:36

UnityとCMockの使い方が分かる本『Embedded Testing with Unity and CMock』を読んだ

UnityとCMockはC言語のためのxUnitとMockフレームワーク。UnityとCMockの使い方について、電子書籍とペーパーブックが出ている。6ドルくらいなので、購入して読んでみた。


Embedded Testing with Unity and CMock by Mark VanderVoord (eBook) – Lulu


内容はとても異色だ。まず、ページが正方形なのが、なんかおかしい。物語形式で話が進んでいく。途中に可愛い?!マンガチックなイラストがたくさんでてくる。文学表現が初めの方はおおくて、知らない単語が多かったりした。

前半がUnityの話、後半がCMockの話。全部で40ページくらいなので、あまり内容は深くない。使い方が説明されている。ツールについてくるドキュメントよりは詳しくツールが解説されている。特に、オプション周り。

この本、手順はしょりすぎ。。。けっこう苦労したので、補う意味で手順をメモしておく。

なお、UnityとCMock利用するためには、Rubyが必須ツール。Rubyスクリプトをガンガン使うため。事前にインストールすること。

CMockのダウンロード

githubからダウンロードします。unityやceelingというプロジェクトも必要になります。サブモジュール扱いされているので、それらも取得します。

#CMockをcloneする
$ git clone git://github.com/ThrowTheSwitch/CMock.git
# Unityとceelingをcloneする
$ git submodule init
$ git submodule update

CMockをcloneする

$ git clone git://github.com/ThrowTheSwitch/CMock.git

Unityとceelingをcloneする

$ git submodule init
$ git submodule update

Unityはどんなコンパイラだって、コンパイルできるらしい(と書いてあった)。まずは、自分が使う予定のコンパイラでUnityが動作するかチェックする。

Cygwinだと、どうもWindowsに解釈されるので、makefileをチョット修正。

$ cd CMock/vendor/unity
$ emacs makefile
$ make

こんな感じに修正。

#ifeq ($(OS),Windows_NT)    
# TARGET_EXTENSION=.exe
#else
TARGET_EXTENSION=.out
#endif

—————–

#ifeq ($(OS),Windows_NT)
# CLEANUP = del /F /Q build\* && del /F /Q $(TARGET1) && del /F /Q $(TARGET2)
#else
CLEANUP = rm -f build/*.o ; rm -f $(TARGET1) ; rm -f $(TARGET2)
#endif

—————-

./$(TARGET1)

これで174のテストが走る。Great! v(o´∀`o)v

別のコンパイラを試すには、makefileの先頭にC_COMPILER=gccという部分を修正する。

C_COMPILER=g++
C_COMPILER=gcc-3

CMockはデフォルトコンパイラがgccのようだが、他のコンパイラでのテスト方法がかワカラなかった。gccでのテスト方法は、以下を実行する。

$ cd CMock
$ rake

Unity編(p3~)

以下のようにコマンドを実行することで、MenacingLED.c/MenacingLED.h/TestMenacingLED.cができる。

$ ruby auto/generate_module.rb MenacingLED
File /home/TSUNEMICHI/src/unity/book/auto/../src//MenacingLED.c created    
File /home/TSUNEMICHI/src/unity/book/auto/../src//MenacingLED.h created
File /home/TSUNEMICHI/src/unity/book/auto/../test//TestMenacingLED.c created
Generate Complete

次に以下のコマンドでTestMenacingLED_Runner.cができる。

$ ruby auto/generate_test_runner.rb test/TestMenacingLED.c

makefileを編集する。以下の4つを追加する。作成された4つのファイルをコンパイルしてリンクし、実行ファイルを生成。実行する。

# Unity File
SRC_FILES = src/unity.c

# Source Files
SRC_FILES += src/MenacingLED.c
SRC_FILES += test/TestMenacingLED.c
SRC_FILES += test/TestMenacingLED_Runner.c

$ make
rm -f build/*.o ; rm -f book.exe ; mkdir -p build
gcc -Isrc -DTEST -DUNITY_SUPPORT_64 src/unity.c src/MenacingLED.c test/TestMenacingLED.c test/TestMenacingLED_Runner.c -o book.exe

./book.exe
test/TestMenacingLED.c:14:test_MenacingLED_NeedToImplement:IGNORE
-----------------------
1 Tests 0 Failures 1 Ignored
OK

CMock編(p14~)

S5モジュールを生成。

$ ruby auto/generate_module.rb S5    
File /home/TSUNEMICHI/src/unity/book/auto/../src//S5.c created
File /home/TSUNEMICHI/src/unity/book/auto/../src//S5.h created
File /home/TSUNEMICHI/src/unity/book/auto/../test//TestS5.c created
Generate Complete

S5_Exec()をS5.hとS5.cに空実装する。

同様にして、ButtonsとS5モジュールを生成する。

$ ruby auto/generate_module.rb Buttons    
$ ruby auto/generate_module.rb S5Ctrl

Buttons_CheckS5Switch と S5Ctrl_Silenceをヘッダに宣言する。

ここからが書いていないのだが、モックオブジェクトを生成する。以下をカレントディレクトリにコピーしてくる。

  • cmock/lib
  • cmock/config/
  • cmock/src(cmock.cとcmock.hが欲しい)

mocksディレクトリを作成して、cmock生成用のスクリプトを実行する。

$mkdir mocks
$ ruby lib/cmock.rb src/Buttons.h src/S5Ctrl.h
Creating mock for Buttons...
Creating mock for S5Ctrl...

Makefileを編集する。インクルードファイルにもmocksディレクトリを追加。

cmockを利用するためには、unity.cとcmock.cも同時にコンパイルしてやる。最終的なMakefileはこんな感じ

C_COMPILER=gcc 
TARGET_BASE = MenacingLED 
TARGET_BASE2 = S5 
TARGET_EXTENSION=.exe 
TARGET = $(TARGET_BASE)$(TARGET_EXTENSION) 
TARGET2 = $(TARGET_BASE2)$(TARGET_EXTENSION)

# Unity Files 
SRC_FILES   = src/unity.c 
SRC_FILES2  = src/unity.c

# CMock Files 
SRC_FILES  += src/cmock.c 
SRC_FILES2 += src/cmock.c

# Source Files 
SRC_FILES += src/MenacingLED.c 
SRC_FILES += test/TestMenacingLED.c 
SRC_FILES += build/TestMenacingLED_Runner.c

SRC_FILES2 += src/S5.c 
SRC_FILES2 += test/TestS5.c 
SRC_FILES2 += build/TestS5_Runner.c

SRC_FILES2 += mocks/MockButtons.c 
SRC_FILES2 += mocks/MockS5Ctrl.c

INC_DIRS  =-Isrc 
INC_DIRS +=-Imocks 
SYMBOLS=-DTEST -DUNITY_SUPPORT_64

CLEANUP = rm -f build/*.o ; rm -f $(TARGET); rm -f $(TARGET2) ; mkdir -p build

all: clean default

default: 
        ruby auto/generate_test_runner.rb test/TestMenacingLED.c build/TestMenacingLED_Runner.c 
        ruby auto/generate_test_runner.rb test/TestS5.c build/TestS5_Runner.c 
        ruby lib/cmock.rb src/S5Ctrl.h 
        ruby lib/cmock.rb src/Buttons.h 
        $(C_COMPILER) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES) -o $(TARGET) 
        $(C_COMPILER) $(INC_DIRS) $(SYMBOLS) $(SRC_FILES2) -o $(TARGET2) 
        ./$(TARGET) 
        ./$(TARGET2)

clean: 
        $(CLEANUP)

21 Apr 2013, 11:32

githubに新しいリポジトリを作成してローカルのリポジトリをアップロードする

ローカルで書いたコードをGithubに上げる方法を人生のウチでもう3回も調べている気がするので、ここらでメモしておきます。ああ、モノ忘れが激しい。。。

ローカルでgit リポジトリを作成して作業

リポジトリを作成して、いろいろほげほげ作業します。今回は、このリポジトリをgithubで公開したいとする。

$ git init

githubとの間でSSH通信を確立する

githubとローカルPCをつなぐ通信はSSH通信を利用します。なので、まずは鍵を生成。sshがどうもパソコンに入っていな場合は、もってこよう。詳しくは、ここの過去記事を参照のこと。

SSHを使いこなそう!Windows上のCygwinからvmware上のUbuntuにパスワードなしでSSH通信するまでのまとめ | Futurismo

(この記事のせいでローカルで持っていた鍵が紛失したため、githubとの設定を今やり直している。。。(T_T))

鍵を生成します。ここではRSA暗号方式を利用する。パスワードはとりあえずなしで。

$ ssh-keygen -t rsa

.ssh/配下にid_rsa(秘密鍵)と、 id_rsa.pub(公開鍵)が生成される。id_rsa.pubをgithubに登録する。

ブラウザからgithubにアクセスする。

GitHub

ログインして上のツールバーから[Account Setting] > [SSH Keys] > [Add SSH key]を選択する。

github

鍵を入力する画面が現れるので、titleとkeyを入れる。ここでのkeyはid_ras.pubを入れる。

$ cat id_rsa.pub

[Add Key]を押すと、githubアカウントのパスワード入力が求められるので入力して完了。登録が完了すると、登録完了メールが飛んでくる。

github上にリポジトリを作成

githubにローカルと連携したいリポジトリを作成する。ツールバーの[Create Repositry]を選択。リポジトリ名を入力して、詳細の説明を入力。

Public/Privateで公開と非公開を選択できる。

Initialize this repository with a READMEにチェックを入れるとREADME.mdというファイルが作成される。リモートとローカルの連携がややこしくなるので、初めはチェックをいれない。

Add .gitignoreで.gitignoreの選択もできるが、すでにローカルで.gitignoreがあるので、ここではNoneを選択。

ここでは、embedded_testing_with_unity_and_cmockという名前のリポジトリを作成する。[Create Repositry]を選択して作成。

github2

作成すると、クイックセットアップの方法が表示される。

image

ここでは、既存のリポジトリをコマンドラインでgithubにアップロードしたいので、以下を実行する。

$ git remote add origin git@github.com:tsunera/embedded_testing_with_unity_and_cmock.git

このコマンド、によってoriginがこの長いURLであることを覚える。あとは、git pushコマンドで、ローカルリポジトリをgithubにブッシュして完了。

$ git push -u origin master

20 Apr 2013, 10:51

ストレス社会を乗り切るために!cygwinとemacsの起動が遅い場合の高速化2選(emacsclient)

私はWindows上でCygwinとEmacsをガリガリ使っているひとですが、悩みは

起動が遅いことヽ(`Д´)ノ

である。cygwinの起動は10秒くらい、emacsも5秒くらいかかり、イライラする。

そこで、そんなストレス社会を薬物に頼らずに乗り切るために、起動高速化のための方法を調べてみたので、まとめてメモしておく。

Cygwin起動高速化の方法(/etc/bash_completion)

私はCygtermでCygwinを起動している。起動時にcygwinはいろいろな設定をしているのだが、特に時間がかかる原因が

/etc/bash_completion

の読み込みらしい。なので、この/etc/bash_completionを読み込まないように設定する。行頭にreturnを挿入することで解決。

以下の記事が参考になった。

Cygwin 1.7 の起動が遅い@ Windows 7 x64 | Mazn.net

# この項は今後も調べたら追加するかも。。

Emacs起動高速化の方法(emacsclient)

次に、emacsの起動。

Emacsは起動時にいろいろな設定ファイルを開くので、時間がかかるのは仕方がないEmacsは一度立ち上げたらめったに落とすものではないのだ。それが正しい使い方なのである。

しかし、簡単な設定ファイルを開こうとする度に5秒待たされたのでは溜まったものではない。そんなときに役に立つのが、EmacsServerとEmacsClientだ。

EmacsServerを立ちあげると、以後にemacsで編集をするときは、emacsClientからServerに通信してすでに開いているEmacs上で編集することがデキる。つまり、emacsを起動しなくても編集できる。

EmacsServerの立ちあげ

Emacsサーバを立ち上げるためには、Emacs上で

“M-x server-start”

と打ち込む。これだと、いちいちコマンドを打ち込まないといけないので、起動設定ファイルに以下を入力することで、起動時に自動でサーバを起動できる。

自分の場合は、$HOME/.emacs.d/init.el)に以下の設定を追加した。.emacsでもよい。自分の設定に合わせて。

; server start for emacs-client
(require 'server)
(unless (server-running-p)
  (server-start))

または、デーモンを起動しておけば、ウィンドウを閉じていてもバックグラウンドでサーバが立ち上がる。コマンドラインから以下のコマンドを叩く。

$ emacs -daemon

また、emacs daemonの終了は以下の通り

$  emacsclient -e ‘(kill-emacs)’

再起動も含め、シェルにしておくとよい。

 

EmacsClientで編集する

いつもは、emacsでファイルを編集しようとしていたものを、emacsclient.exeで編集する。

$ emacsclient .bashrc

Waiting for Emacs…

これでサーバ上でファイルが編集できる。もっと便利にするためには、aliasを切るとよい。これもcygwin起動ファイルに以下を追加。(自分の場合は.bashrc)

alias emacs=“emacsclient.exe -nw”

デフォルトでemacsclientを使うように指定する。”-nw”オプションをつけることで、今開いているターミナル上でファイルが編集できる。閉じるときは”Ctrl + x + #“で。

参考:emacsclientを使おう – Life is very short

これで、ストレスにつぶれてこの世を呪うことなく生きることができる。

20 Apr 2013, 07:50

Expect コマンドでパスワードなしでログインする方法(telnet,ssh,scp)

前回、sshを使ってパスワードなしでログインする方法を書きましたが、linuxのコマンド”expect”を利用することでも、パスワードなしでログインできたのでメモします。

環境

前回と同じように、CygwinからUbunsuサーバに接続してみる。

  • 接続先: ubuntu
  • 接続元: cygwin

expectコマンドの紹介

expectコマンドは対話型シェルを実現するためのコマンド。デフォルトでは入っていないようなので、手に入れる。インストール方法は省略します。

覚えるべきコマンドは以下の5つ。

  • set timeout
    設定した秒数の間、標準入力から応答がないとexpectは、終了します。
  • spawn
    自動で実行したいコマンドを指定します。
  • expect
    指定された文字列を待ちます。
  • send
    指定された文字列(「”」に囲まれた文字)を先に実行したコマンドのジョブに送信します。
  • interact
    実行ジョブの標準入出力をキーボードと画面にします。端末からログインしたのと同じ状態になります。

サンプルスクリプト

telnet,ssh,scpでのパスワードなし接続方法を書きます。
ubuntuサーバにtsu-neraユーザでログインします。

telnet

#!/bin/bash

# ログイン情報を入力
hostname=ubuntu
username=tsu-nera
password=*********

# expect コマンドを実行
expect -c "
# タイムアウト値の指定
set timeout 20
# spawnで新しいジョブ生成
spawn telnet $hostname

# login
expect login:
send \"$username\n\"
expect Password:
send \"$password\n\"

# spawnジョブを通常の通信にする
interact
"

ssh

#!/bin/bash

# ログイン情報を入力
hostname=ubuntu
username=tsu-nera
password=*********

# expect コマンドを実行
expect -c "
# タイムアウト値の指定
set timeout 20
# spawnで新しいジョブ生成
spawn ssh -l $username $hostname

# login
expect password:
send \"$password\n\"

# spawnジョブを通常の通信にする
interact
"

scp

ファイルパスは第一引数で指定します。

#!/bin/bash

# ログイン情報を入力
hostname=ubuntu
username=tsu-nera
password=*********

# ファイルパスは第一引数で
if [ "$1" != "" ]; then
    filepass=$1
else
    echo "Error: Input File Path"
    exit 1
fi

# expect コマンドを実行
expect -c "
# タイムアウト値の指定
set timeout 20
# spawnで新しいジョブ生成
spawn scp $username@$hostname:$filepass .

# login
expect password:
send \"$password\n\"

expect $
"
exit 0

17 Apr 2013, 23:15

リモートシェルの終了ステータス確認する方法のメモ

rshを利用してリモートホスト上のシェルスクリプトを実行すると、シェルスクリプトの成功・失敗にかかわらず終了ステータスはrst/sshの終了ステータスが返る。たとえば、リモートシェルが失敗した場合でも、通信が成功すると、終了ステータスは成功となる。

たとえは、これだと終了ステータスは正常終了の0がかえる。

#!/bin/bash
rsh tsu-nera@192.168.118.129 fail_shell
echo "$?"

こんなときは、コマンド実行結果をローカルファイルにリダイレクトして、その中身を見てみるとよい。ローカル側で $? が解釈されないように\$?とする必要があることに注意。

#!/bin/bash

# リモートシェル実行
rsh tsu-nera@192.168.118.129 "~/bin/fail_shell;echo \$?" > tmp

# ファイル出力から変数に代入
tail -n 1 tmp >> tmp2; rm tmp
read RESULT < tmp2;    rm tmp2

# 結果判定
if [ $RESULT -eq 0 ]; then
    echo "Shell Sucess"
    exit 0
else
    echo "Shell failed"
    exit 1
fi

もっとシンプルな書き方がある気がする。。。

13 Apr 2013, 04:13

SSHを使いこなそう!Windows上のCygwinからvmware上のUbuntuにパスワードなしでSSH通信するまでのまとめ

OpenSSHには、個人的に何度も苦労しているので、ココらへんで接続確立手順をまとめておこうと思う。

環境

  • SSHサーバ Ubuntu  Ubuntu 12.10 (vmware上で起動)
  • SSHクライアントCygwin  1.7.17-1(Windows 7上で動作)

Windows上のCygwinからvmware上のUbuntuにSSHするまでを目指す。

OpenSSHとは

OpenSSHについてもまとめておく。OpneSSHとは、SSH通信をするためのフリーソフト/ツール。SSHとは、暗号技術を利用して安全に情報をやりとりするためのプロトコル。SSHのウレシイところは、パスワードなしで自由に他のコンピュータと通信ができるところだ。公式サイトはココ。

OpenSSH

OpenSSHに必要なもの

サーバ側の設定

UbuntuにSSHサーバをインストールする。以下のコマンドで取得。

$sudo apt-get install openssh-server

次に、SSHサーバの設定ファイルを編集します。これも管理者権限でオープン。

$sudo emacs /etc/ssh/sshd_config

PasswordAuthentication というの項目をyesに変更。PasswordAuthenticationはパスワード認証を許可するかどうかの設定。defaultではコメントされている。また、今回はRSA暗号を使うため、設定ファイルでRSAを有効にしておく。

# Change to no to disable tunnelled clear text passwords
PasswordAuthentication yes

RSAAuthentication yes
PubkeyAuthentication yes

最後に設定を反映するために、サーバを再起動します。

$sudo /etc/init.d/ssh restart

 

クライアント側の設定

cygwin側にもSSHクライアントを導入します。setup.exeからopensshを取得してインストールします。

OpenSSH通信の確立

クライアント側で鍵生成

クライアント側で暗号鍵を生成します。ここではRSA暗号方式を採用。一番有名なので。以下のコマンドで$HOME/.sshに秘密鍵と公開鍵が作成される。パスワード入力が求められるが、ここではなにも入れずにEnterをおす。

  • id_rsa(秘密鍵)
  • id_rsa.pub(公開鍵)

$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/TSUNEMICHI/.ssh/id_rsa):
Created directory ‘/home/TSUNEMICHI/.ssh’.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/TSUNEMICHI/.ssh/id_rsa.
Your public key has been saved in /home/TSUNEMICHI/.ssh/id_rsa.pub.
The key fingerprint is:
78:af:12:31:f3:e2:b5:12:93:cc:8d:97:5e:36:5b:5c tsu-nera@TSUNEMICHI-VAIO
The key’s randomart image is:
+–[ RSA 2048]—-+
|                 |
|                 |
|                 |
|      +.      E  |
|     o.OS…   |
|      X.*.+ o    |
|     . O +.+     |
|      + o..      |
|       o.        |
+—————–+

クライアントの公開鍵をサーバに送信

クライアントの公開鍵をサーバに送ります。安全のために、ここではscpコマンドを使うのがよいでしょう。

$ scp ~/.ssh/id_rsa.pub  tsu-nera@192.168.118.129:
The authenticity of host ‘192.168.118.129 (192.168.118.129)’ can’t be established.
ECDSA key fingerprint is 3e:0c:49:ce:a0:14:79:82:bd:88:02:9d:1a:7c:d3:c0.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ‘192.168.118.129’ (ECDSA) to the list of known hosts.
tsu-nera@192.168.118.129’s password:
id_rsa.pub                                  100%  406     0.4KB/s   00:00

サーバ側で公開鍵の認証登録をする

ここからは、サーバの設定です。まずは、クライアントの公開鍵を保存するためのディレクトリを作成。アクセス権限は自分だけに与えます。そうしないと、パスワードを聞かれる。(ココてハマった)

$ mkdir .ssh
$ chmod 700 .ssh

$ ls -al|grep ssh
drwx——  2 tsu-nera tsu-nera  4096  4月 13 12:49 .ssh

次に、クライアントの公開鍵をauthorized_keysというファイルに覚えます。覚えさせたら、クライアントの公開鍵はすみやかに削除しましょう。

$ cat id_rsa.pub >> .ssh/authorized_keys
$ rm id_ras.pub

.ssh/authorized_keysのアクセス権限も変更します。

$$ chmod 600 .ssh/authorized_keys

ちなみにauthorized_keysてはなくauthorized_keys2の場合もあるらしい。Ubuntuではauthorized_keysがデフォルト。うまくいかない場合は、設定ファイルで以下の項目を確認するとよい。

$ grep AuthorizedKeysFile /etc/ssh/sshd_config
AuthorizedKeysFile %h/.ssh/authorized_keys

クライアント側からアクセスしてみる

準備完了。クライアント側からアクセスしてみる。

$ ssh  tsu-nera@192.168.118.129
Welcome to Ubuntu 12.10 (GNU/Linux 3.5.0-18-generic i686)

Last login: Fri Apr 12 20:50:51 2013 from 192.168.118.1

アクセスできたら、サーバ側の設定ファイルでパスワード認証を解除する。

# Change to no to disable tunnelled clear text passwords
PasswordAuthentication no

最後に設定を反映するために、サーバを再起動します。

$sudo /etc/init.d/ssh restart

[http://www.youtube.com/embed/yaNiOf-7X_o?rel=0]