プロジェクト

全般

プロフィール

シナリオテスター草案 » 履歴 » バージョン 1

K69 天才ぺやんぐさん, 2023/03/16 21:05

1 1 K69 天才ぺやんぐさん
# シナリオテスター草案
2
3
シナリオについては[こちら](#シナリオとは), テストの流れについては[こちら](#テストの流れ), 主な機能については[こちら](#主な機能), シナリオファイルの記述方法については[こちら](#シナリオファイルの記述方法)を参照してください。
4
5
## 簡単な使い方
6
7
1. 当プラグインを導入する
8
2. テスト対象のプラグインの jar にシナリオファイルを埋め込み, ビルドする
9
3. テスト対象のプラグインを導入する
10
4. シナリオが発火し, テストが開始される(構成による <- 後述)
11
5. 開発者が, コンソールでテストの結果を確認する
12
6. 開発者が, テストの結果を修正する
13
14
## 概要
15
16
シナリオテストプラグイン(名前候補:Scenamatica, 以下 当プラグイン)は, PaperMC プラグインのシナリオテストを自動化して高度な支援を提供します。
17
当プラグインを導入したサーバを用意し, テスト対象プラグインにシナリオファイルを置くことで, 自動化したテストを作成します。
18
19
### シナリオファイルの配置場所どうしましょう..?
20
21
シナリオファイルは, 現時点で2つの配置場所を考えています:
22
23
1. `plugins/Scenamatica/scenarios/<プラグイン名>/` に配置する  
24
  この場合, テスト対象のプラグインにシナリオファイルを埋め込む必要がなく, jarの軽量化に繋がります。  
25
  ですが, シナリオファイルの管理やアップデートがめんどうくさくなるでしょう。
26
2. テスト対象のプラグインの jar にシナリオファイルを埋め込む (ぺやんはコチラを推します)  
27
  この場合, テスト対象のプラグインにシナリオファイルを埋め込む必要があり, jarが肥大化する必要があります(Profile で切り替えができると思います).
28
  メリットとしては, シナリオファイルがプラグインに同梱されるため, アップデートが簡単になります。  
29
  また, プラグインと同じリポジトリで管理できるため, プラグインの開発者はシナリオファイルの管理を気にする必要がありません。
30
31
---
32
33
## シナリオとは
34
35
シナリオとは, テスト対象のプラグインの機能をテストするための流れの集合です。  
36
シナリオは, テスト対象のプラグインの機能を発火させるための動作 (Action), 
37
その動作が正しく実行されたかを検証するための動作 (Assertion), およびそれらの動作を実行するための環境の定義 (Context) からなります。
38
39
シナリオファイルの具体的な記述方法およびプロパティの一覧については, [シナリオファイルの記述方法](# シナリオファイルの記述方法) を参照してください。
40
41
---
42
43
## テストの流れ
44
45
シナリオテストは以下の流れで進行します。
46
47
1. テスト対象のプラグインを導入する
48
2. レビュワーがテスト開始をトリガする
49
3. 当プラグインが, シナリオに基づいてテスト対象のプラグインの特定の機能を発火させる
50
4. テスト対象のプラグインが, その機能を実行 (Execution) する(eg. プレイヤーにメッセージを送信, アイテムを与える, ブロックを設置する ...)
51
5. 当プラグインが, シナリオに基づいて, その機能が正しく実行されたかを検証 (Assertion) する
52
6. ステップ 5 で検証に失敗した場合, テストは失敗となりテスト対象のプラグインの開発者に通知される
53
7. 4-6 を繰り返す。
54
8. すべてのシナリオが成功した場合, テストは成功となりテスト対象のプラグインの開発者に通知される
55
56
### テストが成功する条件
57
58
+ すべての Assert が成功する
59
60
### テストが失敗する条件
61
62
+ 1つ以上のシナリオの Assertion が失敗する
63
+ 現在待ち受けている動作よりも先に, 後述された動作が発生する
64
+ シナリオの実行中にエラーが発生する
65
+ シナリオの実行中にタイムアウトが発生する
66
+ シナリオの実行中にプレイヤーがログアウトする
67
68
---
69
70
## 主な機能
71
72
### 疑似プレイヤ (PseudoPlayer) 機能
73
74
当プラグインは, テスト対象のプラグインの機能を発火させるために, 任意数の疑似プレイヤを生成します。  
75
Bukkit の Player インターフェースを実装した疑似プレイヤは, 通常のプレイヤとして認識されます
76
77
#### [mineflyer](https://github.com/PrismarineJS/mineflayer) との相違点
78
79
疑似プレイヤ及び BOT を追加するツールとして[mineflyer](https://github.com/PrismarineJS/mineflayer)が挙げられます。  
80
ですが, 当プラグインは以下の点で mineflyer と異なります。
81
82
+ 外部との通信を行わない  
83
  PaperMC をインジェクションしサーバ内のみで完結するため, 外部とのパケットの送受信を行う必要がありません。  
84
+ 必要数のクライアントを準備しなくてよい  
85
  [mineflyer](https://github.com/PrismarineJS/mineflayer)は, 人数分クライアントで準備する必要があります。  
86
  当プラグインは, 上記の通り内部で完結するためその必要はありません。
87
88
----
89
90
### 動作実行 (Execution) 機能
91
92
疑似プレイヤ及び通常のプレイヤに対して, 任意の動作を行わせられます。  
93
例えば, プレイヤに対して, メッセージを送信させたり, アイテムを使用させたり, ブロックを設置させたりできます。
94
95
対応する予定の動作については, [こちら](#対応する動作の一覧)を参照してください。 
96
97
----
98
99
### 動作検証 (Assertion) 機能
100
101
疑似プレイヤ及び通常のプレイヤに対して, 任意の動作が行われるのを待ち受けます。  
102
タイムアウトを設け, その時間内に動作が行われなかった場合は, そのテストは失敗になります。  
103
また, 後に定義された動作が先行して起きた場合にも, そのテストは失敗になります。(予定)
104
105
対応する予定の動作については, [こちら](#対応する動作の一覧)を参照してください。 
106
107
----
108
109
### 原状回復機能 (できたら)
110
111
テストが終了した際に, ワールドの状態や, エンティティの状態を元に戻します。
112
コスト無茶苦茶高いです。(ブロックやエンティティの状態を記録する必要があるので...)
113
114
---
115
116
## シナリオファイルの記述方法
117
118
シナリオファイルは, YAML 形式で記述され(Java と迷ってます), 拡張子`.yml` または `.yaml` を持つ必要があります。  
119
シンタックスシュガー重視で開発する予定です。
120
121
---
122
123
## シナリオファイルの例
124
125
(未完成・各プロパティの説明は後述された[こちら](#シナリオファイルのプロパティ)を参照してください)
126
127
以下の例では, 「プレイヤが死んだときに豪華にするプラグイン」のシナリオ記述例です。
128
129
テスト項目:
130
+ 発火:PseudoPlayer1 が, PseudoPlayer2 によって殺される 
131
+ 検証:PseudoPlayer1 のスコア「kill」がインクリメントされる
132
+ 検証:PseudoPlayer2 に個人メッセージ「PseudoPlayer1 によって殺されました!」が送信される
133
+ 検証:サーバ全体にブロードキャストメッセージ「PseudoPlayer2 は PseudoPlayer1 によって殺されました!」が表示される
134
+ 実行:PseudoPlayer2 がリスポーンする
135
+ 検証:PseudoPlayer2 がスペクテイターモードになる
136
137
```yaml
138
# シナリオの名前
139
name: "プレイヤが死んだときの正常動作シナリオ"
140
141
# シナリオが発火する条件
142
on:
143
# コマンド実行。コマンドは正規表現で記述できるとよい
144
- type: command_dispatch
145
  with:
146
    command: ^/test$
147
  # 本シナリオを実行する前に必要なシナリオを実行する
148
  before:
149
  - $ref: killPlayer
150
# プラグイン.jar が変更されたとき
151
- type: plugin_modify
152
  before:
153
    - $ref: killPlayer
154
# なんらかの手段で手動実行されたとき
155
- type: trigger_manual
156
  before:
157
    - $ref: killPlayer
158
159
# 使いまわしするスキーマを定義する(OpenAPI のような感じ)
160
schemas:
161
  # JsonSchema の仕様的に, schemas 内の入力補完は厳しい
162
  killPlayer:
163
     type: execute
164
     action: entity_kill
165
     with:
166
       damager: PseudoPlayer1
167
       damagee: PseudoPlayer2
168
  defaultSword:
169
    type: DIAMOND_SWORD
170
    amount: 1
171
    slot: HOTBAR_0
172
  defaultChestPlate:
173
    type: DIAMOND_CHESTPLATE
174
    amount: 1
175
    slot: ARMOR_CHEST
176
    metadata:
177
      name: "§b§lプレイヤーの胸当て"
178
      lores: ["§7プレイヤーが死んだときに", "§7自動的に装備される"]
179
      enchantments:
180
        PROTECTION_ENVIRONMENTAL: 4
181
        DURABILITY: 3
182
183
# シナリオの実行に必要なプレイヤーや, ワールドの状態を定義する
184
context:
185
  # シナリオに実行な疑似プレイヤー
186
  pseudo_players:
187
  - name: PseudoPlayer1
188
    location:
189
      world: world
190
      x: 0
191
      y: 0
192
      z: 0
193
      yaw: 0
194
      pitch: 0
195
    uuid: 00000000-0000-0000-0000-000000000000
196
    inventory:
197
      contents:
198
      # $ref でスキーマを参照する
199
      - $ref: defaultSword
200
      - $ref: defaultChestPlate
201
  - name: PseudoPlayer2
202
    inventory:
203
      contents:
204
      - $ref: defaultSword
205
      - $ref: defaultChestPlate
206
    
207
# シナリオを定義する
208
scenario:
209
# スコアがインクリメントされるか検証する. 起きるまで待つ(要タイムアウト)
210
- type: expect
211
  action: score_change
212
  with: 
213
    name: kill
214
    type: objective
215
    target: PseudoPlayer2
216
    action: increment
217
# プレイヤーに個人メッセージが送信されるか検証する.
218
- type: expect
219
  action: message_private
220
  with: 
221
    content: "PseudoPlayer1 によって殺されました!"
222
    recipient: PseudoPlayer2
223
# サーバ全体にブロードキャストメッセージが表示されるか検証する.
224
- type: expect
225
  action: message_broadcast
226
  with: 
227
    content: "PseudoPlayer2 は PseudoPlayer1 によって殺されました!"
228
# プレイヤーをリスポーンさせる
229
- type: execute
230
  action: respawn
231
  with: 
232
    target: PseudoPlayer2
233
# プレイヤーがスペクテイターモードになるか検証する.
234
- type: expect
235
  action: gamemode_change
236
  with: 
237
    mode: SPECTATOR
238
239
```
240
241
## シナリオファイルのプロパティ
242
243
### `name`: `string` - 必須
244
245
シナリオの人間が読みやすい名前です。
246
247
---
248
249
### `on`: `On[]` - 必須
250
251
シナリオが発火する条件を定義します。
252
すべて省略する場合でも, 実行するには `type: trigger_manual` を指定する必要があります。
253
254
---
255
256
### `schemas`: `Schema[]` - (省略可)
257
258
シナリオの中で使いまわすスキーマを定義します。
259
スキーマは, どこでも `$ref` で参照できます。
260
261
---
262
263
### `context`: `Context` - (省略可)
264
265
シナリオを実行するために必要なプレイヤーや, ワールドの状態を定義します。
266
267
---
268
269
### `scenario`: `Scenario[]` - 必須
270
271
シナリオの実行内容を定義します。
272
273
---
274
275
## `On`: `object`
276
277
シナリオが発火する条件を定義するための構造体です。
278
279
### `type`: `string` - 必須
280
281
シナリオが発火する条件の種類を指定します。対応する動作はシナリオの定義と同じですので, [こちら](#対応する動作の一覧) を参照してください。
282
283
### `with`: `object` - (省略可)
284
285
条件の詳細を指定します。動作によっては必須です。
286
287
### `before`: `Scenario[]` - (省略可)
288
289
シナリオが発火する前に実行するシナリオを定義します。
290
291
---
292
293
## `Schema`: `object`
294
295
シナリオの中で使いまわすスキーマを定義するための構造体です。基本的になんでも入れられます。
296
297
---
298
299
## `Context`: `object`
300
301
シナリオを実行するために必要なプレイヤーや, ワールドの状態を定義するための構造体です。
302
303
304
### `pseudo_players`: `Player[]` | `int` - (省略可)
305
306
シナリオに実行な疑似プレイヤーの数または, それらの定義を指定します。
307
308
### `worlds`: `World[]` | `string` - (省略可)
309
310
シナリオに必要なワールドの定義を指定します。
311
312
---
313
314
## `Scenario`: `object`
315
316
シナリオの実行内容を定義するための構造体です。
317
318
### `type`: `execute` | `expect` - 必須
319
320
シナリオの動作を指定します。
321
322
### `action`: `string` - 必須
323
324
シナリオの動作の種類を指定します。対応する動作は, [こちら](#対応する動作の一覧) を参照してください。
325
326
### `with`: `object` - (省略可)
327
328
動作の詳細を指定します。動作によって異なり, 必須の場合もあります。
329
330
---
331
332
## 対応する動作の一覧
333
334
各動作のプロパティは, `with` に指定します。
335
336
### `event`
337
338
Bukkit のイベントを発火させたり, 発生を検証したりします。 
339
一応, すべてのイベントに対応するつもりです。  
340
基本的には, これだけですべて検証できるはずですが, シンタックスシュガーとして, もっと詳細な動作を定義します。
341
342
#### `event`
343
344
イベントの完全修飾クラス名を指定します。 Bukkit 標準のイベントの場合は, パッケージ名は省略できます。
345
346
----
347
348
### `command_dispatch`
349
350
コマンドを実行したり, 実行されたことを検証したりします。
351
352
#### `command`
353
354
実行するコマンドを**正規表現で**指定します。
355
356
#### `sender`
357
358
コマンドを実行するプレイヤーを指定します。省略した場合は, コンソールから実行されます。
359
360
----
361
362
### `message_broadcast`
363
364
サーバ全体にブロードキャストメッセージを表示したり, 表示されたことを検証したりします。
365
366
#### `content`
367
368
表示されるメッセージを指定します。
369
370
----
371
372
### `message_private`
373
374
プレイヤーに個人メッセージを送信したり, 送信されたことを検証したりします。
375
376
#### `content`
377
378
送信されるメッセージを指定します。
379
380
----
381
382
### `message_chat`
383
384
プレイヤーにチャットメッセージを送信したり, 送信されたことを検証したりします。
385
386
#### `content`
387
388
送信されるメッセージを指定します。
389
390
### (ry)