SSブログ

bashの編集モードをviモードにしてみる [雑記]

普段Ubuntuで使ってるシェルはbashだ.
bashには編集モードというのがあって,デフォルトはemacsモードになっているらしいが,これをviモードに変更できる.普段使ってるエディタはVimなので,bashの編集モードもviモードにしたほうが便利だ.

というわけで変更してみる.
set -o vi

これでOK.実際は,.bashrcにでも書いておくといい.
ちなみにemacsモードにするにはviのところをemacsにすればいい.

これで,コマンドライン編集のときにviのキーバインドが(だいたい)使えるようだ.ま,Vimに慣れてる人なら違和感無く使えるというか,使いやすいと思う.

ところで,いろいろキーバインドを試していてビジュアルモードに入ろうとしたら,nanoが立ち上がってきた.どうやらnanoがデフォルト設定されているようだ.というわけでこれもVimに変更しておく.

この設定変更には,update-alternativesコマンドを使用するようだ.

まず,いまの設定を確認してみる.
sudo update-alternatives --config editor

すると,以下のような表示が出力されるはずだ.
alternative editor (/usr/bin/editor を提供) には 4 個の選択肢があります。

  選択肢    パス              優先度  状態
------------------------------------------------------------
* 0            /bin/nano            40        自動モード
  1            /bin/ed             -100       手動モード
  2            /bin/nano            40        手動モード
  3            /usr/bin/vim.basic   30        手動モード
  4            /usr/bin/vim.tiny    10        手動モード

現在の選択 [*] を保持するには Enter、さもなければ選択肢の番号のキーを押してください: 

これを見ると,確かにデフォルトはnanoになっているようだ.
で,Vimに変更するために,「3」を入力する.
変更されたかどうかは,再度同じコマンドを入力して,「3」のvim.basicが選択されていればOKだ.

これで完了.

nice!(0)  トラックバック(0) 
共通テーマ:日記・雑感

Google Testのアサーションをいろいろ使ってみる [Google Test]

前回に引き続き,Google Testを試してみる.
Google Testにはいろいろなアサーションが用意されてるので,それを試してみる.

前回と同様に適当なディレクトリにassert_projというディレクトリを作って,ファイル構成は以下のようにしてやる.なお,今回はアサーションのテストだけしかしないので,作成するファイルはCMakeLists.txtとassert_unittest.cppだけだ.
assert_proj/
├── CMakeLists.txt
└── test
    └── assert_unittest.cpp


CMakeLists.txt
cmake_minimum_required(VERSION 2.6)
project(assert_test)
enable_testing()
find_package(Threads)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

message(STATUS GTEST_DIR=$ENV{GTEST_DIR})

include_directories($ENV{GTEST_DIR}/include)
link_directories($ENV{GTEST_DIR}/lib)

add_executable(assert_test test/assert_unittest.cpp)
target_link_libraries(assert_test gtest gtest_main)
target_link_libraries(assert_test ${CMAKE_THREAD_LIBS_INIT})
add_test(NAME assert_test COMMAND assert_test)


assert_unittest.cpp
#include <gtest/gtest.h>

// message output test
TEST(TestAssert, Message)
{
    bool flag[2] = {true, false};
    for (int i = 0; i < 2; i++) {
        EXPECT_TRUE(flag[i]) << "test failed at index " << i;
    }
}

// bool test
TEST(TestAssert, AssertTrue)
{
    EXPECT_TRUE(true);
    ASSERT_TRUE(true);
}

TEST(TestAssert, AssertFalse)
{
    EXPECT_FALSE(false);
    ASSERT_FALSE(false);
}

// value test
TEST(TestAssert, Value)
{
    int expected = 2;
    int actual = 2;
    EXPECT_EQ(expected, actual);    // expected == actual

    int val1, val2;
    val1 = val2 = 3;
    EXPECT_NE(val1  , val2+1);  // val1 != val2
    EXPECT_LE(val1  , val2  );  // val1 <= val2
    EXPECT_GE(val1  , val2  );  // val1 >= val2
    EXPECT_LT(val1  , val2+1);  // val1 <  val2
    EXPECT_LE(val1  , val2+1);  // val1 <= val2
    EXPECT_GT(val1+1, val2  );  // val1 >  val2
    EXPECT_GE(val1+1, val2  );  // val1 >= val2
}

// class test
class Point
{
    private:
        int x_;
        int y_;
    public:
        Point(int x, int y) : x_(x), y_(y) {}
        bool operator==(const Point& obj) const { return (x_ == obj.x_) && (y_ == obj.y_); }
        bool operator!=(const Point& obj) const { return !(*this == obj); }
};

TEST(TestAssert, Class)
{
    Point a(0, 0);
    Point b(0, 1);

    EXPECT_EQ(a, a);
    EXPECT_NE(a, b);
} 

// c string test
TEST(TestAssert, CStr)
{
    char str1[] = "aaa";
    char str2[] = "aaa";

    EXPECT_NE(str1, str2);
    EXPECT_STREQ(str1, str2);       // "aaa" vs "aaa"

    strcpy(str2, "Aaa");
    EXPECT_STRNE(str1, str2);       // "aaa" vs "Aaa"
    EXPECT_STRCASEEQ(str1, str2);   // "aaa" vs "Aaa"

    strcpy(str2, "bAA");
    EXPECT_STRCASENE(str1, str2);   // "aaa" vs "bAA"
}


じゃあビルド.前回と同様,assert_buildディレクトリを作ってビルド.
mkdir assert_build
cd assert_build/
cmake ../assert_proj/
make


これで,assert_testバイナリが生成される.

実行は,
make test ARGS=--output-on-failure

でOK.ARGS=-Vにすると詳細が表示されるんだけど,テストに失敗したときだけ詳細が表示されればいいんだったら,ARGS=--output-on-failureにするといい.ま,テスト成功のときはシンプルな表示で失敗のときにいろいろ表示されるほうが使いやすいかも.

アサーションの説明は,Google Test ドキュメント日本語訳の入門ガイドにあるアサーションあたりを読むと分かると思う.

ま,それだけだと寂しいので,テストの内容をいくつか,ざっくり書いとく.

TEST(TestAssert, Message)
アサーションに失敗したときにメッセージを出力するもの.flagがfalseのときに失敗して,「test failed at index 1」というメッセージが追加で表示される.成功のときはメッセージは表示されない.

TEST(TestAssert, Class)
値の比較をするアサーションは,組み込み型ならそのまま使える.もしユーザ定義型でも使いたい場合は,比較演算子を用意してやれば使える.今回の場合だと,EXPECT_EQとEXPECT_NEを使うので,==演算子と!=演算子を用意してやればよい.

TEST(TestAssert, CStr)
C言語文字列を比較したいときは,EXPECT_EQではなく,EXPECT_STREQを使う.EXPECT_EQだとポインタの比較になってしまい文字列そのものの比較にならない.

とりあえず今回はここまで.
お試しあれ.

nice!(0)  トラックバック(0) 
共通テーマ:日記・雑感

簡単なコードでGoogle Testを使ってみる [Google Test]

前回,Google Testを使えるようにしたので,今回は,ごく簡単なコードに対してGoogle Testを使ってみることにする.

というわけで,Google Testの使い方について検索するとよく出てきて定番っぽい,2つの変数を加算するadd関数について試してみる.

なるべく,実際使う構成に近い方がイメージしやすいと思うので(といいつつも,単にadd関数だけなんて作ること無いと思うのだけど...)適当なディレクトリに,add_projというディレクトリを作ってやって,ファイル構成は以下のようにしてやる.あと,cmakeを使ってビルドしてみる.
add_proj/
├── CMakeLists.txt
├── add.cpp
├── add.h
├── main.cpp
└── test
    └── add_unittest.cpp

それぞれのファイルの内容は以下のようになる.

CMakeLists.txt(CMake用の設定ファイル)
cmake_minimum_required(VERSION 2.6)
project(add)
enable_testing()
find_package(Threads)
set(CMAKE_INCLUDE_CURRENT_DIR ON)

message(STATUS GTEST_DIR=$ENV{GTEST_DIR})

include_directories($ENV{GTEST_DIR}/include)
link_directories($ENV{GTEST_DIR}/lib)

add_executable(add_main main.cpp add.cpp)
add_executable(add add.cpp test/add_unittest.cpp)
target_link_libraries(add gtest gtest_main)
target_link_libraries(add ${CMAKE_THREAD_LIBS_INIT})
add_test(NAME add COMMAND add)

ちなみに,GTEST_DIRは,前回Google Testをダウンロード,展開したディレクトリだ.
うちの場合だと,~/googletest/gtest-1.6.0/になる.なので,
export GTEST_DIR=~/googletest/gtest-1.6.0
としてやる.実際には,.bashrcにでも記載してやるといい.

add.cpp(add関数の定義)
#include "add.h"

int add(int x, int y)
{
    return x + y;
}


add.h(add関数の宣言)
#ifndef ADD_H
#define ADD_H

int add(int x, int y);

#endif // ADD_H


main.cpp(add関数を使用するmainの定義)
#include <iostream>
#include "add.h"

int main()
{
    int x = 2;
    int y = 3;

    std::cout << x << " + " << y << " = " << add(x, y) << std::endl;

    return 0;
}


test/add_unittest.cpp(add関数のテスト定義)
#include <gtest/gtest.h>
#include "add.h"

TEST(TestAdd, add1)
{
    ASSERT_EQ(3, add(1,2));
}


では,ビルドしてみる.
ビルドは,ソースファイルがあるディレクトリとは別のディレクトリにする(これをout-of-source buildとよぶらしい).同じディレクトリでもいいのだが,CMakeはかなり中間ファイルを生成してごちゃごちゃするので,別ディレクトリにするのがおすすめだ.
今回は,add_projと同一階層にadd_buildディレクトリを生成して,以下のようにしてやる.
mkdir add_build
cd add_build/
cmake ../add_proj/
make


で,これによって,2つのバイナリが生成される.
add_mainとaddだ.
add_mainのほうは,単にadd関数によって2と3を加算した結果を表示するだけのプログラムで,addのほうがadd関数のテストになる.今回は1+2の結果が3になることをテストしている.

テストの実行は,./addでもいいし,make testでもいい.
ただし,make testだと,結果は詳細は表示されない../addと同等の表示をしたければ,make test ARGS=-Vとしてやればいい.

なお,今回はadd_mainというadd関数を使ったプログラムも作ったが,単にadd関数のテストだけをやりたければ,main.cppはいらないし,add_mainの生成もしなくていい.

Google Testは,今回の値の一致テスト以外にもいろんなことができる.それについてはまた別の機会に...

では,お試しあれ.

タグ:Google Test CMAKE
nice!(0)  トラックバック(0) 
共通テーマ:日記・雑感

Google Testを使ってみる [Google Test]

C++のテストフレームワークとして,Google Testというのがあるので使ってみる.

Google Testはいろんなプラットフォームに対応しているらしい.例えばLinuxとかMac OS X,あとWindowsとかCygwinでも使えるらしい.

で,これをうちのビルドマシン上で使ってみる.ビルドマシンのOSはubuntu 12.04の64bit版だ.

では,まずは適当なディレクトリを作成し,Google Testをダウンロード,展開してやる.
cd ~/
mkdir googletest
cd googletest/
wget http://googletest.googlecode.com/files/gtest-1.6.0.zip
unzip gtest-1.6.0.zip

そしたらライブラリを作成してやる.作成方法の詳細は展開先のREADMEに書かれてるので一度ざっと目を通しとくといいかも.あと,この作業でCMakeを使うので先にインストールしておく(使わなくてもできるけど).
というわけでCMakeのインストール
sudo apt-get install cmake

ライブラリ作成
cd ~/googletest/gtest-1.6.0/
mkdir lib
cd lib/
cmake ../
make

これで,「libgtest.a」と「libgtest_main.a」が作成されるはずだ.実際テストするときはこのライブラリをリンクして使うことになる.

そしたら,試しにサンプルをビルドして,テストを実行してみる.
cd ~/googletest/gtest-1.6.0/
mkdir build_sample
cd build_sample/
cmake -Dgtest_build_samples=ON ../
make

そうすると,以下の実行可能なファイルが作成されるはずだ.
sample1_unittest
sample2_unittest
sample3_unittest
sample4_unittest
sample5_unittest
sample6_unittest
sample7_unittest
sample8_unittest
sample9_unittest
sample10_unittest

試しにsample1_unittestを実行してみる.
./sample1_unittest

そうするとテストが実行されて以下のような結果が表示されるはずだ.
Running main() from gtest_main.cc
[==========] Running 6 tests from 2 test cases.
[----------] Global test environment set-up.
[----------] 3 tests from FactorialTest
[ RUN      ] FactorialTest.Negative
[       OK ] FactorialTest.Negative (0 ms)
[ RUN      ] FactorialTest.Zero
[       OK ] FactorialTest.Zero (0 ms)
[ RUN      ] FactorialTest.Positive
[       OK ] FactorialTest.Positive (0 ms)
[----------] 3 tests from FactorialTest (1 ms total)

[----------] 3 tests from IsPrimeTest
[ RUN      ] IsPrimeTest.Negative
[       OK ] IsPrimeTest.Negative (0 ms)
[ RUN      ] IsPrimeTest.Trivial
[       OK ] IsPrimeTest.Trivial (0 ms)
[ RUN      ] IsPrimeTest.Positive
[       OK ] IsPrimeTest.Positive (0 ms)
[----------] 3 tests from IsPrimeTest (0 ms total)

[----------] Global test environment tear-down
[==========] 6 tests from 2 test cases ran. (1 ms total)
[  PASSED  ] 6 tests.

実際には色もついて表示される.で,ここまで確認できればOK.

次のステップはサンプルじゃなくて自分のコードをテストすることになるのだが,それはまた次回.

タグ:Google Test CMAKE
nice!(1)  トラックバック(0) 
共通テーマ:日記・雑感

NTPで時刻合わせをしてみる [雑記]

前回,ダイナミックDNSのIPアドレス更新を自動化したときに,ログを出力するようにした.で,このログには時刻も記録されるようにした訳だが,動作確認したときの時刻をよく見ると,ちょっと時刻がズレてることに気づいた.

そういえば,時刻合わせって,気にしてなかった...

というわけで,NTPで時刻合わせするようにしてみる.
NTPの詳細はリンク先を見てもらうとして,要は時刻合わせをするためのプロトコルだ.

で,その時刻合わせをするためにNTPクライアントをインストールしてやる.
sudo apt-get install ntp

そしたら,設定.
sudo vi /etc/ntp.conf

変更内容は,まず,既存のserverから始まる行をコメントアウトしてやる.うちの環境では16行目から始まる以下をコメントアウトした.
# Use servers from the NTP Pool Project. Approved by Ubuntu Technical Board
# on 2011-02-08 (LP: #104525). See http://www.pool.ntp.org/join.html for
# more information.
# server 0.ubuntu.pool.ntp.org
# server 1.ubuntu.pool.ntp.org
# server 2.ubuntu.pool.ntp.org
# server 3.ubuntu.pool.ntp.org

# Use Ubuntu's ntp server as a fallback.
# server ntp.ubuntu.com

で,serverとして以下を追加した.
server ntp.nict.jp
server ntp.nict.jp
server ntp.nict.jp

3つとも同じサーバ名にしているが,これでよい.実際には複数台のサーバがあって,別々のサーバにアクセスするようになっている.
これらのサーバは,日本標準時を供給している独立行政法人情報通信研究機構(NICT)によるサービスで提供されてるものだ.個人利用も許可されてるのでありがたく利用させてもらう.

で,設定が完了したら,NTPを再起動して設定を有効にしてやる.
sudo /etc/init.d/ntp restart


そしたら動作チェック.
sudo ntpq -p

最初は以下のようにサーバ名の前は空白のはず.
     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
 ntp-a3.nict.go. .NICT.           1 u    7   64    1   15.500   -2.257   0.000
 ntp-b2.nict.go. .NICT.           1 u    6   64    1   17.769   -0.673   0.000
 ntp-b3.nict.go. .NICT.           1 u    5   64    1   15.264   -0.223   0.000

で,しばらくするとNTPサーバ名の前に*か+がつくはずだ.ちなみに意味合いは,以下のようになっている.
  "*" :現在,参照同期中のサーバー
  "+" :現在,クロック誤り検査に合格したサーバー
  "#" :現在,参照同期中ですが,距離が遠いサーバー
  " " :現在,参照していないサーバー
  "x" :現在,クロック誤り検査で不合格になったサーバー
  "." :現在,参照リストからはずされたサーバー

     remote           refid      st t when poll reach   delay   offset  jitter
==============================================================================
+ntp-a3.nict.go. .NICT.           1 u   19   64  177    5.291    2.974   4.926
+ntp-b2.nict.go. .NICT.           1 u   21   64  177    8.528    2.911   3.492
*ntp-b3.nict.go. .NICT.           1 u   23   64  177    9.097    2.497   2.848

これでOK.

あとは,dateコマンドで現在日時を表示できるのでちゃんと設定されてるかこれで確認できる.

これで時刻は正確に保たれるようになる.

タグ:NTP NICT
nice!(0)  トラックバック(0) 
共通テーマ:日記・雑感

ダイナミックDNSのIPアドレス更新を自動化してみる [雑記]

前回,ダイナミックDNSの登録をやって,ひとまず使えるようになったのだが,必須作業であるIPアドレスの更新が手動になっていた.今回はこれを自動化してみる.

で,ちょっと調べてみると,この自動更新をやってくれるクライアントソフトがある.
Windowsでは,DiCEが定番のようだ.
だけどうちのサーバはUbuntuだ.DiCE for Linux Beta Versionというのもあるようだが,もうちょっと調べてみると,「Dynamic DO!.jp」ならスクリプトとcronで簡単にできるようだ.

参考にしたサイトは以下の3つ.
240ねっと! - Linuxサーバの構築
DDNS/ddo.jp - PukiWiki
U1F BLOG: ddo.jp 自動更新スクリプト

では,具体的な作業に入ろう.

まずは,perlスクリプトの作成.IPアドレスの変更があったときだけ更新(登録)作業をするようなスクリプトとしておく.
cd /usr
sudo mkdir ddns
cd ddns
sudo vi ipchk.pl


ipchk.plは以下のとおり.
ちなみに,ホスト名とパスワードは「Dynamic DO!.jp」に登録したホスト名とパスワードだ.
#!/usr/bin/perl
#
$CRT_IPF = '/usr/ddns/CRT_IP.dat';
$NEW_IPF = '/usr/ddns/NEW_IP.dat';
$LOG = '/var/log/ddns.log';

open (INPUT,$CRT_IPF);
$CRT_IP=<INPUT>;
close (INPUT);

system("/usr/bin/wget -q -O $NEW_IPF http://info.ddo.jp/remote_addr.php");
open(INPUT,$NEW_IPF);
@xx = <INPUT>;
$c = $xx[1];
$stp = index($c,"REMOTE_ADDR:")+12;
$edp = length($c);

$NEW_IP = substr($c,$stp,($edp-$stp));
close(INPUT);

if ($NEW_IP ne "" and $CRT_IP ne $NEW_IP) {
    open (OUTPUT ,">$CRT_IPF");
    print OUTPUT $NEW_IP;
    close OUTPUT;

    print "IP Address update: $CRT_IP to $NEW_IP\n";
    system("wget -q -O - 'http://free.ddo.jp/dnsupdate.php?dn=ホスト名.ddo.jp&pw=パスワード'");

    $now_string = localtime;
    open (OUTPUT ,">>$LOG");
    print OUTPUT "$now_string DDNS IP Address Updated. $CRT_IP to $NEW_IP\n";
    close OUTPUT;
}


このスクリプトにはパスワードが平文で書かれてるので,アクセス権をrootだけにしてやる.
sudo chmod 700 ipchk.pl


動作テストしてエラーが無ければcronに登録してやる.
「Dynamic DO!.jp」には以下のような記載がある.
「IPアドレス更新リクエストが毎時00分前後の数秒に集中しております。 サーバ負荷の増大に伴い、その間の更新リクエストが失敗する場合もございます。 自動更新処理は毎時00分を避けるよう設定ください。」
なので5分ごとの更新タイミングを3分ずらすようにする(3分,8分,13分・・・とする).
あと,まるっきりIPアドレスが変わらないと更新(登録)作業がされないことになるが,最低1ヶ月に1回はIPアドレスの更新をしないといけない.なので,スクリプトが生成する「現在のIPアドレスを保持するファイル」を週に2回削除するようにして,必ず更新(登録)作業がされるようにしてやる.

crontabの編集
sudo crontab -e

記載内容
3-58/5 * * * * /usr/ddns/ipchk.pl
0 5 * * 0 rm -f /usr/ddns/CRT_IP.dat
0 5 * * 3 rm -f /usr/ddns/CRT_IP.dat


これでIPアドレス更新が自動的に行われるようになるはずだ.

試しにサーバのIPアドレスを変更したり,CRT_IP.datファイルを削除して動作を確認してみたが正常に動作しているようだ.
ちなみにLogは/var/log/ddns.logに出力される.更新(登録)作業がされたときに出力されるようになっていて動作が確認できる.

以上で作業は完了.これでIPアドレスが変わってもちゃんとDNSでアクセスできるようになる.

nice!(0)  トラックバック(0) 
共通テーマ:日記・雑感

ダイナミックDNSを使ってみる [雑記]

外出してるときとかでも,いま使ってる格安サーバ(PRIMERGY MX130 S2)にアクセスできるようにしてみる.
幸い,うちはグローバルIPが割り振られてるので,IPアドレスさえ分かれば外からでもsshで接続できる.でも,IPアドレスなんて覚えられないし,残念ながら固定IPでもない.

で,こんなときはダイナミックDNSだ.
詳細はリンク先を見てもらうとして,ま,ざっくり言えば固定IPじゃなくてもDNSが使えるようになるってことだ.IPアドレスが変わったときにダイナミックDNSのサービスに通知するようにしておけばIPとDNSの対応付けをやってくれる.

ダイナミックDNSのサービスは検索すると.無料で使えるサービスがいろいろある.
で,いろいろ比較した結果,「Dynamic DO!.jp」を利用することにした.
Dynamic DO!.jpでは有料版もあるけど,いま考えてる用途なら無料版で全く問題ない.ありがたく無料版を利用させてもらう.

使い方(登録方法)はとっても簡単.特に悩むところはないと思う.検索すれば登録方法を詳しく説明してるサイトもあるようだ.

で,登録が完了すれば,ホスト名.ddo.jpが使えるようになるわけだが,サーバのIPアドレスを登録しないといけない.
とりあえず手動で設定するにはDynamic DO!.jpのサイトから「IPアドレスの更新」をすればよい.
これでDNSとIPアドレスの関係が正しく設定されることになる.

ところで,Dynamic DO!.jpの無料版だと最低1ヶ月に1回はIPアドレスの更新をしないといけない(更新がないと登録削除される).それに,そもそもサーバのIPアドレスが変わったら更新をしないといけない.
これを手動でやるのはとっても面倒だ.
で,自動化するわけだが,とりあえず今回はここまで.
自動化の作業はまた次回...

nice!(0)  トラックバック(0) 
共通テーマ:日記・雑感

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。