Fixture
JSON の Fixture ファイルで、テストユーザー、カレンダー、イベント、OAuth クライアントを定義します。
Fixture は、Calendarpit の初期テストデータを定義する JSON ファイルです。テストユーザー、カレンダー、イベント、OAuth クライアントを定義できます。ローカルサーバーやテストスイートを、決まったデータで起動したいときに使います。
Fixture で id を明示すると、ユーザー ID、カレンダー ID、イベント ID、OAuth クライアント ID が固定されます。テストのアサーションでは、生成された値を問い合わせずに、決まった ID をそのまま検証できます。
起動時に Fixture を読み込む
Fixture ファイルのパスは、CLI フラグ --config または環境変数 CALENDARPIT_CONFIG で指定します。
どちらも指定しない場合、Calendarpit は組み込みのデフォルト Fixture を読み込みます。内容はリポジトリの fixtures/default.json と同じで、次のデータを含みます。
- ユーザー
alexとsam - カレンダー
alex-work、alex-personal、sam-work - イベント
planning1 件 - OAuth クライアント
sample-app
CLI で起動する
下の JSON の例を calendarpit.fixture.json として保存し、テスト用に編集してください。インストールで公開状況と必要な環境を確認してから、ファイルを保存したディレクトリで起動します。
calendarpit serve \
--database :memory: --config ./calendarpit.fixture.json--config と CALENDARPIT_CONFIG の相対パスは、起動したディレクトリを基準に解決されます。
Docker・Compose で起動する
Docker では、作成済みのファイルを読み取り専用でマウントし、コンテナ内のパスを指定します。以下は POSIX シェル用のコマンドです。
docker run --rm -p 127.0.0.1:4173:4173 \
--mount "type=bind,source=$PWD/calendarpit.fixture.json,target=/fixtures/startup.json,readonly" \
-e CALENDARPIT_CONFIG=/fixtures/startup.json \
-e CALENDARPIT_DATABASE=:memory: \
ghcr.io/iktakahiro/calendarpit:latestCompose では、サービスに次の 2 点を設定します。
volumesに./calendarpit.fixture.json:/fixtures/startup.json:roを追加します。environmentにCALENDARPIT_CONFIG: /fixtures/startup.jsonを設定します。
ホスト上のファイルは、コンテナの非 root ユーザーが読み取れる必要があります。起動オプションは起動と設定を参照してください。
起動時 Fixture が適用される条件
起動時 Fixture が投入されるのは、新しい空のデータベースだけです。
--database :memory:モード: プロセスを起動するたびにデータベースが新しくなります。そのため、Fixture は毎回適用されます。- 保存済みのデータがある SQLite ファイル: Calendarpit は Fixture を適用せず、警告も表示しません。保存済みのデータと、最初のリセット基準を読み込みます。保存済みのデータには、ユーザーごとのカレンダーリスト設定と、カレンダーの削除済みレコードも含まれます。
Fixture が適用されない場合でも、指定するパスは読み取り可能な JSON ファイルを指している必要があります。そうでない場合は起動に失敗します。この場合、ファイルの内容は検証されません。
詳しくはストレージと再起動を参照してください。
実行中に読み込む・リセットする
テストの合間にデータを切り替えるには、テスト制御 API を使います。
POST /__calendarpit/fixturesは、実行中に別の Fixture を読み込みます。POST /__calendarpit/resetは、リセット基準(起動時の状態)に戻します。起動時 Fixture が復元され、カレンダーリストのエントリは起動時の etag を持つデフォルトの状態に戻ります。
どちらも次のデータを消去します。
- OAuth の接続(grant)とトークン
- ユーザーごとのカレンダーリスト設定
- カレンダーの削除済みレコード
- watch チャネル
- 配信
- リクエスト履歴
- 同期トークン
- 通知
GET /__calendarpit/state の結果には、クライアントシークレット、カレンダーリスト設定、削除済みレコードは含まれません。この結果を Fixture として読み込み直すことはできません。詳しくはテスト制御 APIを参照してください。
ルート構造と例
Fixture ファイルのルートは JSON オブジェクトである必要があります。使えるキーは users、calendars、events、clients の 4 つで、どれも省略できる配列です。空のオブジェクト({})も有効な空の Fixture です。
- キーを指定する場合、値は配列にしてください。違反すると
"<key> must be an array."で検証に失敗します。 - それ以外のキーがあると、
"Unsupported field: <key>"(reason はunsupportedFeature)で検証に失敗します。ルートオブジェクトと、ユーザー・カレンダー・イベント・クライアントの各エントリが対象です。
{
"users": [{ "id": "alex", "name": "Alex", "email": "alex@example.test" }],
"calendars": [
{
"id": "work",
"userId": "alex",
"summary": "Work",
"timeZone": "Asia/Tokyo",
"primary": true
}
],
"events": [
{
"id": "meeting",
"calendarId": "work",
"summary": "Planning",
"start": { "dateTime": "2026-10-19T10:00:00+09:00" },
"end": { "dateTime": "2026-10-19T11:00:00+09:00" }
}
],
"clients": [
{
"id": "sample-app",
"secret": "local-sample-secret",
"redirectUris": ["http://127.0.0.1:4175/callback"]
}
]
}ID のルールと検証
ユーザー、カレンダー、イベント、クライアントの ID は省略できます。ただし、カレンダーを所有するユーザーと、イベントを含むカレンダーには、他のエントリから参照するため明示的な id が必要です。
- 使える文字: ASCII の英字、数字、
@、.、_、-で、最大 128 文字です(^[a-zA-Z0-9@._-]{1,128}$)。 - 予約済み ID:
primaryは予約されているため、ID には使えません。 - 一意性:
users、calendars、clientsの ID は、それぞれの中で一意である必要があります("Duplicate fixture ID.")。イベント ID はカレンダーごとに一意である必要があります("Duplicate event ID.")。カレンダーが違えば、同じイベント ID を使えます。
ID のエラー
id の値 | エラー |
|---|---|
| 空文字列、空白だけの文字列、文字列以外 | "id must be a nonempty string." |
| パターンに合わない、空でない文字列 | "Invalid ID." |
| 129〜10,000 文字 | "Invalid ID." |
| 10,000 文字を超える | "id must be a nonempty string." |
primary | "Invalid ID." |
生成される ID とリセット基準
id を省略すると、Calendarpit は UUID を生成します。
生成された ID とイベントの初期メタデータ(created、updated、etag)は、投入時に起動時のリセット基準として記録されます。そのため、POST /__calendarpit/reset を何度呼んでも同じデータが再現されます。
- SQLite では、このリセット基準がプロセスの再起動後も保持されます。
:memory:モードでは、プロセスを起動するたびに新しい UUID とタイムスタンプが生成されます。
検証に失敗したとき
検証はアトミックに行われます。所有者とカレンダーの参照先は、すべて Fixture 内に存在している必要があります。ルールに違反すると、Calendarpit は最初のエラーで処理を止めます。
- 新しいデータベースで起動したとき:
Calendarpit: <message>を出力し、終了コード1で終了します。 POST /__calendarpit/fixturesのとき:400(invalidParameterまたはunsupportedFeature)を返し、既存のデータは変更しません。
セクションリファレンス
users
テストユーザーを定義します。テストユーザーは同意画面でアクセスを承認でき、カレンダーを所有できます。
| フィールド | 必須 | デフォルト | ルール |
|---|---|---|---|
id | 任意 | 生成された UUID | [a-zA-Z0-9@._-] に一致する 1〜128 文字。primary は不可。users 内で一意。 |
name | 必須 | — | 10,000 文字以内の空でない文字列。 |
email | 必須 | — | ^[^\s@]+@[^\s@]+$ に一致する、10,000 文字以内の空でない文字列(違反時は "Invalid email.")。 |
calendars
Fixture のユーザーが所有するカレンダーを定義します。
- カレンダーを所有するユーザーには、
"primary": trueのカレンダーがちょうど 1 つ必要です。違反すると"Each user with calendars must have exactly one primary calendar."で検証に失敗します。 - カレンダーが 1 つだけのユーザーも同様です。
"primary": trueがなければ検証に失敗します。 - カレンダーを持たないユーザーも定義できます。そのユーザーでは、
primaryカレンダーエイリアスが404を返します。
| フィールド | 必須 | デフォルト | ルール |
|---|---|---|---|
id | 任意 | 生成された UUID | [a-zA-Z0-9@._-] に一致する 1〜128 文字。primary は不可。calendars 内で一意。 |
userId | 必須 | — | users のユーザー id と一致すること(違反時は "Unknown calendar owner.")。 |
summary | 必須 | — | 10,000 文字以内の空でない文字列。 |
timeZone | 任意 | "UTC" | 有効な IANA タイムゾーン名(違反時は "Invalid IANA time zone.")。 |
primary | 任意 | false | 真偽値(違反時は "primary must be boolean.")。 |
投入されたカレンダーは、デフォルト設定(selected: true、colorId: "1")で所有者のカレンダーリストに入ります。
あとで管理 API でカレンダーやユーザーを変更できます(テスト制御 APIを参照)。そのときの動作は次のとおりです。
- プライマリカレンダーを削除する: 残りの所有カレンダーのうち、カレンダーリストに残っている最初のものが新しいプライマリになります。リストに残っているものがない場合は、残りの所有カレンダーの最初のものがプライマリになります。新しいプライマリは必要に応じてリストに戻され、その他のリスト設定は保持されます。
- 別のカレンダーに
"primary": trueを設定する: フラグがアトミックに移ります。そのカレンダーはカレンダーリストに戻され、その他のリスト設定は保持されます。 - カレンダーを削除する: そのリスト設定は消え、削除済みレコードが記録されます。このレコードは、
showDeleted=trueのときにdeleted: trueとデフォルトのリスト設定で返されます。プライマリカレンダーの削除済みレコードはprimary: trueを保持します。削除済みの ID でカレンダーを作り直すと、その削除済みレコードと保存されていたリスト設定は消去されます。 - ユーザーを削除する: そのユーザーの OAuth 接続(grant)が失効し、watch チャネルも停止します。カレンダー、イベント、リスト設定も削除されます。この場合、削除済みレコードは追加されません。
events
初期イベントを定義します。Fixture のイベントでは、Calendar API と同じイベントフィールドと検証ルールに加えて、calendarId を使います。Calendar API の互換性とイベント、繰り返し、時刻の扱いを参照してください。
- 読み取り専用フィールド(
organizer、creator、iCalUID、recurringEventId、originalStartTime)も設定できます。 conferenceDataにはconferenceDataVersionは不要です。- リクエスト専用フィールドの
attendeesOmittedは拒否されます("Unsupported field: attendeesOmitted")。 - 投入時には、API で挿入したときの副作用は発生しません。参加者のカレンダーに招待のコピーは作られません。
conferenceData.createRequestがあっても会議リンクは生成されません。
| フィールド | 必須 | デフォルト | ルール |
|---|---|---|---|
calendarId | 必須 | — | calendars のカレンダー id と一致すること(違反時は "Unknown event calendar.")。 |
id | 任意 | 生成された UUID | [a-zA-Z0-9@._-] に一致する 1〜128 文字。primary は不可。カレンダー内で一意。 |
start, end | 必須 | — | イベントの開始と終了(dateTime または終日イベントの date)。ルールは Calendar API と同じ。 |
organizer, creator | 任意 | カレンダーの所有者 | 通常の API リクエストでは読み取り専用ですが、Fixture では設定できます。 |
iCalUID | 任意 | <id>@calendarpit.local | 通常の API リクエストでは読み取り専用ですが、Fixture では設定できます。 |
recurringEventId, originalStartTime | 任意 | なし | 通常の API リクエストでは読み取り専用ですが、Fixture では設定できます。両方設定するか、どちらも設定しません。 |
sequence | 任意 | 0 | 0 以上の整数(違反時は "Invalid sequence.")。 |
created, updated, etag | 無視 | 投入時に生成 | 指定した値は無視され、Fixture の投入時に生成されます。 |
読み取り専用フィールドは、たとえば外部の主催者や、保存済みの繰り返しの例外を投入するときに使います。recurringEventId と originalStartTime の片方だけを設定すると、"Instances require recurringEventId and originalStartTime." で失敗します。
clients
ローカル OAuthで使う OAuth クライアントを定義します。クライアントごとの scopes フィールドはありません。どのクライアントも、対応しているすべてのスコープを要求できます。
| フィールド | 必須 | デフォルト | ルール |
|---|---|---|---|
id | 任意 | 生成された UUID | [a-zA-Z0-9@._-] に一致する 1〜128 文字。primary は不可。clients 内で一意。 |
secret | 必須 | — | 10,000 文字以内の空でない文字列。 |
redirectUris | 必須 | — | http または https の絶対 URL(各 10,000 文字以内)の空でない配列。フラグメントと認証情報は含められません。/oauth/authorize では完全一致で照合されます。 |