速くて軽量なAPI、Starletteを使ってGCPにデプロイする Part4
今回すすめるトピック
追加機能のテスト作成とテストデータベースを準備
GUIアプリで新たにDBを作成、コピしてもよいですし、初期データとして用意していたfixtureをデータベース名の部分だけ変えて、コマンドで流しても作成するのでも良いです。まずはテスト用のデータベースを用意しましょう。
#!/bin/bash
psql -U docker -d docker << EOL
create database docker;
create table robots (id int PRIMARY KEY, name varchar, created_at timestamp);
insert into robots (id, name, created_at) values (1, 'GUIDO', '2020-01-01');
EOL
次に、新たに追加したGETメソッドのAPI、参照カウント数を1増やす機能のテストを追加しましょう。新たに追加したエンドポイントにGETでリクエストすると200を返すこと、モデルをインスタンスして、参照数+1カウントさせて、新しいインスタンスのカウント数が等しいことを確認します。
ここではstore内でセットしているDBから向き先を先程作ったDBへ変更してから接続しています。この内容であればわざわざ作らなくても良いと思いますが、誤って本番DBに接続していたなんてことが無いよう、書いておいたほうが心配しなくていいので安心です。
--- a/tests.py
+++ b/tests.py
@@ -1,8 +1,9 @@
import pytest
from starlette.testclient import TestClient
+from databases import Database, DatabaseURL
from main import app
-from src import store
+from src import store, config
class TestView:
@@ -14,12 +15,30 @@ class TestView:
)
assert response.status_code == 200
+ def test_retrieve(self):
+ with TestClient(app) as client:
+ response = client.get("/v1/robots/1")
+ assert response.status_code == 200
+
class TestModel:
+ def setup_method(self, method):
+ store.database.url = DatabaseURL(config.TEST_DATABASE_URL)
+ self.test_db: Database = store.database
+
@pytest.mark.asyncio
async def test_retrieve(self):
- await store.database.connect()
+ await self.test_db.connect()
res = await store.Robot.retrieve({'robot_id': 1})
assert res.name == 'GUIDO'
- await store.database.disconnect()
+ await self.test_db.disconnect()
+
+ @pytest.mark.asyncio
+ async def test_count(self):
+ await self.test_db.connect()
+ old_robot = await store.Robot.retrieve({'robot_id': 1})
+ await old_robot.count_ref()
+ new_robot = await store.Robot.retrieve({'robot_id': 1})
+ assert old_robot.count + 1 == new_robot.count
+ await self.test_db.disconnect()
コードを実装したらテストを実行してみましょう。
(starlette-cloudrun) __ksh__@macbook-pro starlette-cloudrun % pytest -v -s
======================================================================================================================= test session starts =======================================================================================================================
platform darwin -- Python 3.7.6, pytest-5.3.5, py-1.8.1, pluggy-0.13.1 -- /Users/__ksh__/.local/share/virtualenvs/starlette-cloudrun-Dn0VzN5Q/bin/python
cachedir: .pytest_cache
rootdir: /Users/__ksh__/workspace/starlette-cloudrun, inifile: pytest.ini
plugins: asyncio-0.10.0
collected 4 items
tests.py::TestView::test_repair PASSED
tests.py::TestView::test_retrieve PASSED
tests.py::TestModel::test_retrieve PASSED
tests.py::TestModel::test_count PASSED
======================================================================================================================= 4 passed in 12.42s ========================================================================================================================
無事にテストをパスできましたか?
物足りない方は、住所、為替、国、都市などのAPIを作ってみるのもいいかもしれませんね。このあとのGCPサービスCloudRunで、過剰なアクセスがなければ毎月無料か、10円くらいで運用できると思うので、作成して公開してみるのも楽しいと思います😍
GitへプッシュしたタイミングでCI/CDを行う
それではCI/CDを行うために、まずはさきほどのテストDBの向き先を変えているので、CIでデータ参照できるようにTEST_DATABASE_URLをcloudbuild.yamlに追加しましょう。
BuildステップではfixtureでDB名がdockerと指定しているので、向き先をテスト実行したときにdockerになるようにします。そして、テストに使う初期データも仕様変更があったので編集しましょう。
--- a/cloudbuild.yaml
+++ b/cloudbuild.yaml
@@ -13,6 +13,7 @@ steps:
env:
- DEBUG=1
- DATABASE_URL=postgresql://docker:docker@postgres/docker
+ - TEST_DATABASE_URL=postgresql://docker:docker@postgres/docker
- id: "DEPLOY"
name: "gcr.io/cloud-builders/gcloud"
args:
--- a/src/fixtures/000-sample-data.sh
+++ b/src/fixtures/000-sample-data.sh
@@ -1,6 +1,6 @@
#!/bin/bash
psql -U docker -d docker << EOL
create database docker;
-create table robots (id int PRIMARY KEY, name varchar, created_at timestamp);
-insert into robots (id, name, created_at) values (1, 'GUIDO', '2020-01-01');
+create table robots (id int PRIMARY KEY, name varchar, count bigint, created_at timestamp);
+insert into robots (id, name, count, created_at) values (1, 'GUIDO', 0, '2020-01-01');
EOL
CloudBuildにリポジトリを接続してトリガーを作る
リポジトリを接続をクリックして次へ遷移する。
リポジトリ一覧から自分で作ったリポを選んでください。
保存したら一覧に戻って、該当のトリガーを実行するか、再度Gitになにか変更を加えてプッシュしてください。そうするとビルドが始まってステップが実行されます。
正常にビルドが進めば、テストをクリアしてデプロイは成功するものの、データベース接続エラーでアプリが正常でないため失敗になりますが、CloudRunの画面を見るとサービスが作成されているのが確認できます。
少し寄り道になりますが、GCPでRDBを使う場合はCloudSQLがオススメです。
CloudRunから簡単に接続できます。一旦デプロイ自体を成功してアプリを動かしたい場合はDBを使わない構成にして試してみるといいでしょう。もしくはCloudSQLでPostgreSQL11.6の最安プランで運用か、既存のDBからあればDATABASE_URLを接続情報を書き換えて接続してください。
最後にCloudRun画面から「新しいバージョンをデプロイ」を押して、接続設定を行い、稼働させましょう。
イメージの下らへんにあるCloudSQLへの接続と、アプリの環境変数を追加して、デプロイを行えば完了です。
CloudRunはエラー、ログ、メトリックス、課金もリクエスト毎で安いため、最も利用頻度の高いGCPサービスです。また、AnthosをGKEに追加することで、Kubernetes内のコンテナとして利用することもできますし、Appengine2nd,フレキシブルと違って、Knativeなのでデプロイがとても速く、Dockerさえ理解していれば扱えるので非常に便利です。
また、スケールアウトも自動ですし、バージョンへのトラフィックの移行、配分もできるAppengineの上位互換といったサービスかなと思います。
複数回、ご拝読ありがとうございました。次は最も得意なDjangoのノウハウやKubernetes,Istio関連の記事を単発で書いてみたいと思っています、興味があったら是非読んでみてください🤔
今回の内容はこちらにコミットしています。