備忘録、はじめました。

作業したこと忘れないようにメモっておきます。

httptestでWriteHeaderができなかった話

はじめに goでhttpのhandlerのテストを書いているときに詰まったところを書きます。 詰まったところは、httptest.NewRecoder()の再利用ができなかったことです。 正確には、再利用する方法はあるかもしれないがよくわからなかったので、再度NewRecoder()を呼び出して、新規作成した、で解決しました。

内容

package mytest                                                                    
 
import (
    "bytes"
    "encoding/json"
    "net/http"
    "net/http/httptest"
    "testing"
)
 
func TestOverride(t *testing.T) {
    handler := http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
        var js map[string]interface{}
        decoder := json.NewDecoder(req.Body)
        if err := decoder.Decode(&js); err == nil {
            if js["msg"] == "error" {
                res.WriteHeader(http.StatusBadRequest)
                res.Write([]byte(`{"result": false}`))
            } else {
                res.WriteHeader(http.StatusOK)
                res.Write([]byte(`{"result": true}`))
            }
        }
    })
 
    // 1: StatusOK
    jsons := `{"msg": "test"}`
    w := httptest.NewRecorder()
    r, err := newRequest([]byte(jsons), "POST", "application/json")
    if err != nil {
        t.Errorf("%s", err)
    }
 
    handler.ServeHTTP(w, r)
    if w.Code != http.StatusOK {
        t.Errorf("Expected status code is 200 but got %d", w.Code)
    }
 
    // 2: BadRequest error code
    jsons = `{"msg": "error"}`
    w = httptest.NewRecorder() // ここで再度NewRecoder()を呼ぶ
 
    r, err = newRequest([]byte(jsons), "POST", "application/json")
    if err != nil {
        t.Errorf("%s", err)
    }
 
    handler.ServeHTTP(w, r)
    if w.Code == http.StatusOK {
        t.Errorf("Expected status code is NOT 200 but got %d", w.Code)
    }
}
 
func newRequest(data []byte, method string, c string) (*http.Request, error) {
    req, err := http.NewRequest(
        method,
        "",
        bytes.NewBuffer([]byte(data)),
    )
    req.Header.Set("Content-Type", c)
    return req, err
}

上記は、テストが通ります

はじめは、コメント部分をw.Body.Reset()をすれば大丈夫なのかなぁと安易にやったのですが、そうするとHeader部分への上書きはできませんでした。おそらく、GOの公式ドキュメントに記載されている内容なのかと思います。したがって、w.Body.Reset()で行うと、2回目のBadRequestのエラーを期待するのですが200が返ってくる結果となってしまいます。

goのバージョンを切り替えるだけのスクリプトコマンドを作成

はじめに

goのバージョンだけを単に切り替えたかったので、goのバージョンを切り替えるだけのスクリプトコマンドを作りました。 自分用でサクッと作ったため、installのファイルはlinux-amd64のみ対象としちゃってます。

インストール

ソースをダウンロードして、パスが通った場所にファイルを置くだけです。

$ git clone https://github.com/tkyshm/goenv.git
$ mv bin/goenv /usr/local/bin

また、bashzshの補完が使いたい場合は、補完関数も用意したのでcompletionsが格納されたディレクトリに放り投げるか読み込んであげれば補完もできるようになります。

使い方

helpを使っていただければほとんどわかるかと思います(中身単純なので)。

$ goenv help

切り替えはuseのsubcommandを使えばできます。 下みたいな感じです。

$ goenv use go1.6rc2
switched go version.
go version go1.6rc2 linux/amd64

github.com

Chefで複数リソースに更新があった時だけbashを実行

はじめに

cookbookのfilesの中に大量のtomlファイルが入っていて、各tomlファイルに対してコマンドを実行したい場面に直面しました。 ファイルの更新が合った時だけ、そのコマンドを実行したかったので、その時の作業をメモします。

目的

  • confファイルが更新されているかをチェック
  • 更新されていればファイルを差し替えしてスクリプトを実行

作業

作業環境は、仮想マシンにChef-ServerとChef-Clientを用意し、作業(knifeを実行するマシン)はホストマシンになります。 下記、レシピになります。

recipe.rb

files = run_context.cookbook_collection["my-cookbook-name"].file_filenames
files.select!{ |file| file =~ /\.toml/ }

files.each do |file| 
  # 2. 配置したtomlを使ってコマンドを実行
  bash "exec-#{File.basename(file,".*")}" do
    action :nothing # 実行しない
    user "vagrant"
    cwd "/home/vagrant/conf"
    code "echo #{File.basename(file,".*")} >> /home/vagrant/exec-stamp.txt" # 処理したいコマンド
  end
end

files.each do |file| 
  # 1. tomlを配置
  cookbook_file "/home/vagrant/conf/#{File.basename(file)}" do
    owner "vagrant"
    group "vagrant"
    mode 0644
    source File.basename file
    not_if { FileUtils.cmp("/home/vagrant/conf/#{File.basename(file)}", file) } # ファイルの比較
    notifies :run, "bash[exec-#{File.basename(file,".*")}]" # bash[exec-hoge] の内容を実行しにいく
  end
end
続きを読む

レキシカルスコープとダイナミックスコープ

はじめに

レキシカルスコープとダイナミックスコープの違いについて簡単にまとめてみます。

メモ

以下、サンプルコードを元にして説明していきます。

1: func X(){
2:     print(s)
3: }
4: 
5: func Y() int{
6:     s := 12
7:     X()
8:     return s
9: }

上記のコードで想定している出力結果は、関数Yを呼び出したら12が出力されることとします。 実行している内容は、関数Yで定義された変数sを関数Xで出力するというものです。 下記、2つにスコープに分けて説明します。

続きを読む

Dockerでoperation not supportedが出てきた話

はじめに

DockerでイメージをbuildしようとDockerfileの作ってbuildしてみたものの、

operation not supported

というメッセージでRUNで記載したコマンドが実行できない事象に陥りました。

解決方法

LXCを導入したい場合、以下必要なことがわかりました(根本的な理由は調べてません)。

  • CONFIG_VETHの値(カーネルコンフィグ)
  • lxc
  • cgroups

CONFIG_VETHの値の確認は下記コマンドにて行いました。 下記の結果が表示されていれば値が入っている状態となります。

$ zcat /proc/config.gz | grep VETH
CONFIG_VETH=m

ちなみに、上記表記が出ない場合の対策については実施していません。

cgroupsはubuntuなどのOSであれば、cgroup-liteをapt-getしてあげるらしいです。 Archlinuxの環境ではyaourt -S libcgroupsが必要でした。下記のコマンドは適宜読み替えてください。

$ yaourt -S libcgroups
$ sudo pacman -S lxc

dockerでbuildとりあえずうまく行きました。。。

続きを読む

Riak searchを使ってみた

はじめに

Riakで全文検索してみたいと思い、Riakのsearch機能を利用する準備で行った作業をまとめました。

利用環境

  • Ubuntu server 14.04
  • Riakのホストは192.168.56.101
  • Riak 2.0.5(from source)

前準備

作業

indexの作成

例として、"api_index"という名前のindexを作成します。

export RIAK_HOST="http://192.168.56.101:8098"
curl -XPUT $RIAK_HOST/search/index/api_index \
     -H 'Content-Type: application/json' \
     -d '{"schema":"_yz_default"}'

下記、URLにアクセスし、api_indexのsolrのcore(?)が作成されているか確認します。 ※ solrについて詳しくないので上記言い回し的に間違ってたらご指摘ください。

http://192.168.56.101:8093/internal_solr/

続きを読む

Cowboyでobserverを起動するメモ

目的

軽量HTTPサーバcowboyのアプリケーションをErlangの監視ツールobserverで視覚的に監視できるようにしたい。

実施内容

  • relx.configの編集

レシピ

relx.configの作成したアプリケーション名(以下app_name)の他に、

  • wx
  • observer
  • runtime_tools

の3つを追加します。

{release, {animeeting_release, "1"}, [app_name,wx,observer,runtime_tools]}.
--省略--

上記の対処でobserverが起動できるようになります。 アプリをconsoleで起動し、下記コマンドをerlシェルで実行します。

1> observer:start().

下図みたいな感じなものが見れるようになります。

続きを読む