もがき系プログラマの日常

もがき系エンジニアの勉強したこと、日常のこと、気になっている技術、備忘録などを紹介するブログです。

laravelでrouteにdomainを指定した場合のfeatureテスト方法

はじめに

こんばんは。

すごく短いですが、今日少し悩んだので、備忘録として残しておきます。

試した環境はこちら。

  • PHP 7.3.1
  • Laravel 5.8.28

laravelでmulti認証をやる際、routesにdomainが設定されている場合にどうやってfeatureテストを行うかを調査していたのですが、とりあえず以下みたいな感じで出来ました。

やってみた

こんな感じのroute設定があるとします。

routes.php

Route::group(['prefix' => 'api', 'domain' => config('app.admin_host')], function () {
    Route::post('/auth/login', 'AdminLoginController@login');
    Route::delete('/auth/logout', 'AdminLoginController@logout');
    Route::get('/auth/refresh', 'AdminLoginController@refresh');
});

Route::group(['prefix' => 'api', 'domain' => config('app.user_host')], function () {
    Route::post('/auth/login', 'UserLoginController@login');
    Route::delete('/auth/logout', 'UserLoginController@logout');
    Route::get('/auth/refresh', 'UserLoginController@refresh');
});

config('app.admin_host') とかは .envとかで指定して app.php で読み込んでおきます。

とりあえずこんな感じで登録しておきます。

.env

ADMIN_HOST=127.0.0.1
USER_HOST=localhost

config/app.php

return [
    ...
    'admin_host' => env('ADMIN_HOST', 'admin.kojirock'),
    'user_host'  => env('USER_HOST', 'user.kojirock'),
];

それぞれのrouteのfeatureテストを実行する際、ここで設定しているデータを取れる必要がありそうです。

なので、 phpunit環境変数を渡します。

phpunit.xml

<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
         backupStaticAttributes="false"
         bootstrap="vendor/autoload.php"
         colors="true"
         convertErrorsToExceptions="true"
         convertNoticesToExceptions="true"
         convertWarningsToExceptions="true"
         processIsolation="false"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="MAIL_DRIVER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <env name="ADMIN_HOST" value="admin.local"/> ← これ
        <env name="USER_HOST" value="user.local"/>   ← これ
    </php>
</phpunit>

featureテストファイルには以下のようにテストコードを書きます。

AdminLoginControllerTest.php

<?php


namespace Tests\Feature;

use Illuminate\Foundation\Testing\DatabaseTransactions;
use Tests\TestCase;

class AdminLoginControllerTest extends TestCase
{
    use DatabaseTransactions;

    public function testLogin()
    {
        $response = $this->post('http://admin.local/api/auth/login', [
            'email'    => 'kojirock5260@kojikoji.com',
            'password' => 'secret_secret_secret'
        ]);
        $data = json_decode($response->getContent(), true);
        $this->assertSame('xxxxxxxxxx', $data['accessToken']);
    }
}

これで問題なくテストが通りました。

終わりに

ぶっちゃけ、 config/app.php で設定する際の デフォルト設定でやってしまうというのもあるのですが、個人的に デフォルト設定にテストのものが適用する という運用が嫌なので今回はこのアプローチにしました。

dockerで作成したローカル環境でしか試してないので、circleCIとかで実行する際はまた勝手が違うかもしれません。

もっといいやり方あれば、ぜひ教えて下さい...

.env.testingに書けばいいよね?という一番スマートなやり方を教えてもらいました!

なるほどたしかにw

現場からは以上です。

tblsの論理設定を使ってみる

はじめに

こんばんは。

久々のブログです。

前回tblsの記事をあげたところ、開発者の方からこんな意見をもらいました。

ちなみに以前の記事はこちら

kojirooooocks.hatenablog.com

早速やってみます。

本題

1. サンプルテーブル群作成

サンプルで使用するテーブル群は前回と同様ですが、リレーションやらコメントやらをすべて取っ払ったテーブル設計にしてみました。

CREATE TABLE `master_categories` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(256) NOT NULL DEFAULT '',
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `master_items` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `category_id` int(11) unsigned NOT NULL,
  `name` varchar(256) NOT NULL DEFAULT '',
  `price` int(11) unsigned NOT NULL DEFAULT 0,
  `delivery_cost` int(11) unsigned NOT NULL DEFAULT 0,
  `stock` int(11) unsigned NOT NULL DEFAULT 0,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `userId` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `master_tags` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(255) NOT NULL,
  `short_name` varchar(64) NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `master_tag_relations` (
  `tag_id` int(11) unsigned NOT NULL,
  `item_id` int(11) unsigned NOT NULL,
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`tag_id`,`item_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

このテーブル群を、論理値設定で前回のテーブル設計と同じ情報を作り出したいと思います。

2. .tbls.ymlの設定

今回の .tbls.yml の設定は以下。

dsn: mysql://local_user:1qazxcvb@127.0.0.1:3306/local_test_db
docPath: schema

comments:
  -
    table: master_categories
    tableComment: カテゴリ管理テーブル
    columnComments:
      id: PrimaryKey
      name: カテゴリ名
      created: 登録日
      modified: 更新日
  -
    table: master_items
    tableComment: アイテム管理テーブル
    columnComments:
      id: PrimaryKey
      category_id: カテゴリID
      name: アイテム名
      price: 価格
      delivery_cost: 配送料
      stock: 在庫
      created: 登録日
      modified: 更新日
  -
    table: master_tags
    tableComment: タグ管理テーブル
    columnComments:
      id: PrimaryKey
      name: タグ名
      short_name: ふりがな
      created: 登録日
      modified: 更新日
  -
    table: master_tag_relations
    tableComment: タグ中間テーブル
    columnComments:
      tag_id: タグID
      item_id: アイテムID
      created: 登録日

relations:
  -
    table: master_items
    columns:
      - category_id
    parentTable: master_categories
    parentColumns:
      - id
    def: master_items->master_categories
  -
    table: master_tag_relations
    columns:
      - tag_id
    parentTable: master_tags
    parentColumns:
      - id
    def: master_tag_relations->master_tags
  -
    table: master_tag_relations
    columns:
      - item_id
    parentTable: master_items
    parentColumns:
      - id
    def: master_tag_relations->master_items

3. 結果確認

実行してみます。

$ tbls doc
schema/schema.png
schema/master_categories.png
schema/master_items.png
schema/master_tag_relations.png
schema/master_tags.png
schema/README.md
schema/master_categories.md
schema/master_items.md
schema/master_tag_relations.md
schema/master_tags.md

f:id:kojirooooocks:20190727041229p:plain

問題なく作成されています!

実際の情報を確認してみます。

f:id:kojirooooocks:20190727041241p:plain

リレーションは問題なさそうです。

f:id:kojirooooocks:20190727041252p:plain

コメントも問題なさそうです!

終わりに

実際に試してみましたが、設定も簡単でとても使いやすかったです。

ymlでテーブルごとに設定できるので、設計的に足りてないものだけ論理値設定してあげるなど柔軟なこともできると思います。

PlantUMLでもoutput出来るようなので試してみました。

f:id:kojirooooocks:20190727041303p:plain

問題なく作成されました。が、情報量的にやはり markdown で出力したほうが良さそうかな?と思いました。

現場からは以上です。

tbls試してみた

はじめに

こんばんは。

以前の記事で紹介した crondocに引き続き、 tableのドキュメント自動生成ツールとかないかなと思っていたところ教えてもらった、tblsというツールを試してみました。

github.com

やってみた

今回の試すにあたってvagrant上にテストDBとテストテーブル群を用意しました。

CREATE TABLE `master_categories` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'PrimaryKey',
  `name` varchar(256) NOT NULL DEFAULT '' COMMENT 'カテゴリ名',
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登録日',
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日',
  PRIMARY KEY (`id`),
  KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'カテゴリ管理テーブル';

CREATE TABLE `master_items` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'PrimaryKey',
  `category_id` int(11) unsigned NOT NULL COMMENT 'カテゴリID',
  `name` varchar(256) NOT NULL DEFAULT '' COMMENT 'アイテム名',
  `price` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '価格',
  `delivery_cost` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '配送料',
  `stock` int(11) unsigned NOT NULL DEFAULT 0 COMMENT '在庫',
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登録日',
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日',
  PRIMARY KEY (`id`),
  KEY `userId` (`name`),
  CONSTRAINT `master_items_fk_1` FOREIGN KEY (`category_id`) REFERENCES `master_categories` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'アイテム管理テーブル';

CREATE TABLE `master_tags` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT 'PrimaryKey',
  `name` varchar(255) NOT NULL COMMENT 'タグ名',
  `short_name` varchar(64) NOT NULL COMMENT 'ふりがな',
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登録日',
  `modified` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新日',
  PRIMARY KEY (`id`),
  UNIQUE KEY `name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'タグ管理テーブル';

CREATE TABLE `master_tag_relations` (
  `tag_id` int(11) unsigned NOT NULL COMMENT 'タグID',
  `item_id` int(11) unsigned NOT NULL COMMENT 'アイテムID',
  `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '登録日',
  PRIMARY KEY (`tag_id`,`item_id`),
  CONSTRAINT `master_tag_relations_fk_1` FOREIGN KEY (`tag_id`) REFERENCES `master_tags` (`id`) ON DELETE CASCADE,
  CONSTRAINT `master_tag_relations_fk_2` FOREIGN KEY (`item_id`) REFERENCES `master_items` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT 'タグ中間テーブル';

では早速試します。

1. インストール

$ go get github.com/k1LoW/tbls

2. .tbls.yml 作成

$ cat .tbls.yml 
dsn: mysql://local_user:1qazxcvb@192.168.33.10:3306/tbls_test_db
docPath: schema

3. 実行

$ tbls doc
schema/schema.png
schema/master_categories.png
schema/master_items.png
schema/master_tag_relations.png
schema/master_tags.png
schema/README.md
schema/master_categories.md
schema/master_items.md
schema/master_tag_relations.md
schema/master_tags.md

docPathに指定したフォルダにmarkdownファイルとpngファイルが作成されます。

f:id:kojirooooocks:20190714225120p:plain

README.mdを開くとこんな感じ

f:id:kojirooooocks:20190714225159p:plain

めちゃめちゃいい感じです。

pngはリレーション状態を表示してくれるようです。

READMEは全体情報で、各テーブルごとの個別の情報もあります。

たとえば master_items はこちら

f:id:kojirooooocks:20190714225226p:plain

f:id:kojirooooocks:20190714225251p:plain

うん。みやすい。

終わりに

テーブルのスキーマ自体に情報がない場合(リレーションしてないとかコメントないとか)は使いづらいですが、これを使いたいという前提でスキーマの強化をしていくというアプローチもありかと思いました。

そういえば昔師匠が言ってたなぁ。

データベースの各テーブルのスキーマを見れば、サイト全体が把握できるようにするべきって。

現場からは以上です。

以前作ってたgithub通知のロジックを公開した

内容

こんばんは。

めっちゃ簡単なブログですが、まとめてたので、書いときます。

slackのmentionとgithubのmentionって連動していないから微妙ですよね。

プルリク上とか、issue上でメンションつけてコメントしてもslackに通知が来ないからどうも使いにくいと思ってて、自分で実装しました。

github.com

作ったのは去年くらいで、バーっと3〜4時間で作ってたので、雑な作りになってます。 てゆか調べたら皆さん結構自分で実装してますよね。

www.google.com

他と違ったところだと、設定次第でslackとchatworkどちらでも動くというのと、定時の設定が出来て、その時間中じゃないと通知が飛ばないとか、かゆいところに手が届く設定を少しだけ追加してます。

以下がサポートされてる機能です。

  • github上でメンションをつけると、使用するchatサービスのメンションに変換してくれます。
  • プルリクを作成した際は、プルリクを作成したユーザーと同じグループ(エンジニアの場合は mention_engineers)の人たち全員に自動でメンションを付与します。
  • pull_request_auto_mention_ignore を設定することで プルリク時の自動メンション付与を除外するユーザーを設定できます。
  • pull_request_auto_mention_ignore を設定したくないけど、このプルリクだけは自動メンションを付与したくないという場合は、プルリク作成時に -@xxxx という感じで、 - をつけてあげるとメンション付与を除外します。
  • start_time end_time を指定することで、会社の定時に合わせてメンションをつけるかどうかを設定できます。何時でメンションをつけてもいい場合は start_time: 00:00:00 end_time: 23:59:59 と指定してください。

最終確認をしてないので動かない可能性もありますが、、、、w

今はlambda上で実行されるjs版も作ったりしています。

簡単ですが、こんな感じで。 現場からは以上です。

Effective DevOpsオンライン輪読会Vol.7レポート

はじめに

challenge-every-month の Slack メンバーで 「Effective DevOps」のオンライン輪読会を行っています!

今回は輪読会 Vol.7でした。

前回自分の都合で一周飛ばしてしまったので、開催が2週間ぶりとなりました。

Effective DevOps ―4本柱による持続可能な組織文化の育て方

Effective DevOps ―4本柱による持続可能な組織文化の育て方

過去のレポート

Vol.1

kojirooooocks.hatenablog.com

Vol.2

sadayoshi-tada.hatenablog.com

Vol.3

kojirooooocks.hatenablog.com

Vol.4

kdnakt.hatenablog.com

Vol.5

kdnakt.hatenablog.com

Vol.6

sadayoshi-tada.hatenablog.com

担当した章

今回の担当章は 第十章 アフィニティ:誤解と問題解決 です。

資料

感想

前回の自分の担当と同じく、短い章でした。

ただ、過去の自分に当てはまる部分が多かった章でした。

特に自分にぐさりと響いたのは、 10.2.5 仕事の技術的な側面ばかり考えていて人間関係について考えていない というブロックで書いていた一文です。

人間関係はよかれ悪しかれ組織に影響を与える。それを無視するのは近視眼的である。 こういった考え方をする人は「本当の」仕事とは何かについての見方がとても固定的な傾向がある。だが、この見方は、仕事をするのが人間であり、個人レベルであれ集団レベルであれ、人の生産性に影響を与えるものは何でも「仕事」に計測可能な影響を与えることを無視している。

過去自分は、技術をとにかく付けなければと思い、人間関係については特に考えずに生きてきたところがありました。

その結果知らず知らずに他の人を傷つけてしまったりしたこもとありました。

この文章を過去の自分にタイムスリップして教えてあげたいです。。

次回

@kdnakt さんの担当です!

よろしくお願いいたします!

crondocを使ってみた。

はじめに

こんにちは。

ドキュメントの管理めんどくさいなと思いますよね。

僕は思います。

今お仕事もらってる会社も、DB定義書やCronのドキュメントなどいろいろととっています。

更新した際に毎回修正がとにかくめんどくさい。

そこで、所属しているslackチームの人に相談したところ神の啓示がきました。

f:id:kojirooooocks:20190628174512p:plain

紹介された crondoc を使ってみました。

本題(crondoc)

今回使ったテストでcron設定は以下

PHP_PATH=/usr/bin/php
MAIL_TO=''

# KPIレポート作成バッチ
# 日別、月別のKPIレポートを作成します。
00 20 * * * $PHP_PATH artisan kpi:report

# メールマガジン送信バッチ
# 対象の時間に送信予定として登録されているメールマガジンを送信します。
10 00,03,06,09,12 * * * $PHP_PATH artisan mailMagazine:send

実行するとこんな感じでした。

$ cron_tab -l | crondoc -s
# effective crontab


| min|hour|day|month|day week|command |
|:---|:---|:---|:---|:---|:---|
| PHP_PATH=/usr/bin/php| MAIL_TO=''

***

 - KPIレポート作成バッチ
 - KPIレポートを作成します。

| min|hour|day|month|day week|command |
|:---|:---|:---|:---|:---|:---|
| 00| 20| *| *| *| `$PHP_PATH artisan kpi:report` |


***

# commentout crontab



generated by crondoc

うーん。ちょっとだけ表示が崩れています。

cronの書き方に問題があるのかもしれません。

本題(cron-doc-gen)

表示が少し崩れましたが、このアプローチは個人的に好きなので、PHPで似たようものを作ってみました。

ざっくり作ったので、例外対応とかはしてません。

今度はパスを指定するようにしたので、実行してみます。

$ ./cron-doc-gen /etc/crontab
# Cron Document

## 変数

| Key | Value |
|------|------|
|PHP_PATH|/usr/bin/php|
|MAIL_TO|''|

## バッチ一覧

### KPIレポート作成バッチ
#### 日別、月別のKPIレポートを作成します。
| 分 | 時 | 日 | 月 | 曜日| コマンド |
|:------:|:------:|:------:|:------:|:------:|----|
|00|20|*|*|*|`$PHP_PATH artisan kpi:report`|

### メールマガジン送信バッチ
#### 対象の時間に送信予定として登録されているメールマガジンを送信します。
| 分 | 時 | 日 | 月 | 曜日| コマンド |
|:------:|:------:|:------:|:------:|:------:|----|
|10|00,03,06,09,12|*|*|*|`$PHP_PATH artisan mailMagazine:send`|

いい感じでまとまりました。

終わりに

もうちょいコードを整理しつつ、mergeされたタイミングで esa とかにpushするのを作れば、cronのドキュメントは毎回更新されるので、最新に保つことが出来ます。

簡単ですが公開しときます。

kojirock5260/cron-doc-gen

Databaseのドキュメント生成ツールも教えてもらったので、次はそちらも試してみます。

現場からは以上です。

安全なWebアプリケーションの作り方 読んだ

こんばんは。簡単な記事です。

仕事で忙しく、ずっっっっっっっっと積本だった本をやっと読みました。

ボリュームはかなりあるのですが、過去発売されていた本も読んでいますので、比較的すんなりと読めることができました。

SQLインジェクション, XSS, CSRFなど代表的な脆弱性についての発生条件や影響度、また対応策など細かく記載されており、過去の本では多分乗ってなかった?と思う webAPIで起こりうる脆弱性などについても記載されていました。


だいぶ昔(7〜8年くらい前)の転職面接で、面接官の方に

XSSCSRFの違いを簡潔に教えてください」

と言われ、答えられなかった苦い経験があり、その時がとても悔しくて、過去発売されていた本を購入して同じページを何度も読んだ記憶があります。

読んでいると、その当時の記憶が蘇り今回もXSS, CSRFの部分は重点的に読んでいたような気がしますw


最近のweb開発は、バックエンドもフロントエンドも、フレームワークを使った開発が主流だと思います。 そして、そのフレームワークに提供されている機能を正しく使えば、この辺の代表的な脆弱性を起こさないような対応が比較的簡単にできるとおもいます。

ただ、自分もフレームワークを使って、「理解したつもり」でいたところを、例の質問によって、理解していたのではないのだということを気付かされました。

過去の自分と同じような、「理解したつもり」でいる人は、ぜひこの本を読んでもらいたいです。