捆绑/artilleryphp

Artillery.io的PHP包装器。

v0.9.1 2023-06-05 07:35 UTC

This package is auto-updated.

Last update: 2024-09-05 21:09:00 UTC


README

Artillery.io是一个现代、强大且易于使用的性能测试工具包。

ArtilleryPhp是一个用于在PHP8中编写和维护Artillery脚本的库。

文档包含

  • 每个类和方法的完整解释。
  • 每个类和大多数方法的示例代码。
  • 链接到Artillery参考文档的每个部分。

目录

安装

您可以通过Composer安装此库。

composer require bundeling/artilleryphp

此库需要symfony/yaml包以将其内部数组渲染为YAML格式。

用法

此示例位于examples/artilleryphp-usage

步骤1:创建一个新的Artillery实例

您可以使用Artillery::new($target)获取一个新实例,并使用流畅的接口设置配置值

use ArtilleryPhp\Artillery;

$artillery = Artillery::new('https://:3000')
    ->addPhase(['duration' => 60, 'arrivalRate' => 5, 'rampTo' => 20], 'Warm up')
    ->addPhase(['duration' => 60, 'arrivalRate' => 20], 'Sustain')
    ->setPlugin('expect')
    ->setEnvironment('live', ['target' => 'https://www.example.com']);

您也可以从完整的或部分数组表示形式创建一个

$artillery = Artillery::fromArray([
    'config' => [
        'target' => 'https://:3000',
        'phases' => [
            ['duration' => 60, 'arrivalRate' => 5, 'rampTo' => 20, 'name' => 'Warm up'],
            ['duration' => 60, 'arrivalRate' => 20, 'name' => 'Sustain'],
        ],
        'plugins' => [
            // To produce an empty object as "{  }", use stdClass.
            // This is automatic when using setPlugin(s), setEngine(s) and setJson(s).
            'expect' => new stdClass(),
        ],
        'environments' => [
            'live' => ['target' => 'https://www.example.com']
        ]
    ]
]);

或从现有的YAML文件,或其他Artillery实例

! 警告:目前对fromYamlmerge方法的支持不是很好;fromYaml主要与该库的输出兼容;如果第二级键已经定义(例如,尝试合并第二个环境),则merge将不执行任何操作。

$config = Artillery::fromYaml(__DIR__ . '/default-config.yml');
$environments = Artillery::fromYaml(__DIR__ . '/default-environments.yml');

// New instance from the config, and merging in environments from another file:
$artillery = Artillery::from($config)->merge($environments);

步骤2:定义场景的流程并将其添加到Artillery实例中

// Create some requests:
$loginRequest = Artillery::request('get', '/login')
    ->addCapture('token', 'json', '$.token')
    ->addExpect('statusCode', 200)
    ->addExpect('contentType', 'json')
    ->addExpect('hasProperty', 'token');
    
$inboxRequest = Artillery::request('get', '/inbox')
    ->setQueryString('token', '{{ token }}')
    ->addExpect('statusCode', 200);

// Create a flow with the requests, and a 500ms delay between:
$flow = Artillery::scenario()
    ->addRequest($loginRequest)
    ->addThink(0.5)
    ->addRequest($inboxRequest);

// Let's loop the flow 10 times:
$scenario = Artillery::scenario()->addLoop($flow, 10);

// Add the scenario to the Artillery instance:
$artillery->addScenario($scenario);

提示

存在复数版本以接受原始数组表示形式的多个条目

$loginRequest = Artillery::request('post', '/login')
    ->setQueryStrings([
        'username' => '{{ username }}',
        'password' => '{{ password }}'])
    ->addCaptures([
        ['json' => '$.token', 'as' => 'token'],
        ['json' => '$.id', 'as' => 'id']]);

注意set和add differentiation之间的区别,以及;
有关原始表示规范,请参阅Artillery参考文档

步骤3:导出到YAML

// Without argument will build the YAML as the same name as the php file:
$artillery->build();

// Maybe even run the script right away (assumes `npm install -g artillery`):
$artillery->run();

这将生成以下readme-example.yml文件

config:
  target: 'https://:3000'
  phases:
    - duration: 60
      arrivalRate: 5
      rampTo: 20
      name: 'Warm up'
    - duration: 60
      arrivalRate: 20
      name: Sustain
  plugins:
    expect: {  }
scenarios:
  - flow:
      - loop:
          - get:
              url: /login
              capture:
                - json: $.token
                  as: token
              expect:
                - statusCode: 200
                - contentType: json
                - hasProperty: token
          - think: 0.5
          - get:
              url: /inbox
              qs:
                token: '{{ token }}'
              expect:
                - statusCode: 200
        count: 10

提示

对于非常基本的脚本,您也可以直接将请求(单个或数组)添加到Artillery实例中,以从中创建新的场景

$artillery = Artillery::new()
    ->addScenario(Artillery::request('get', 'http://www.google.com'));

注意

当前实现构建内部数组表示。这意味着对获取特定索引的Scenario实例或取消设置属性的操作支持有限或没有支持。目前请考虑组合,并期待v2。

Artillery类

Artillery类包含与Artillery脚本配置部分相关的所有方法,以及添加场景。

文档:https://bundeling.github.io/ArtilleryPhp/classes/ArtilleryPhp-Artillery

对于自定义配置设置,有一个set(key: string, value: mixed)函数可用。

目标

如果设置了目标,它将用作脚本中所有请求的基本URL。

您可以通过构造函数传递基本URL或使用Artillery实例上的setTarget方法。您还可以完全跳过此步骤,并在每个请求中提供完全限定的URL。

// Base URL in the Scenario with relateve path in the request:
$artillery = Artillery::new('https://:3000')
    ->addScenario(Artillery::request('get', '/home'));

// Without target, and fully qualified URL in Request:
$artillery = Artillery::new()
    ->addScenario(Artillery::request('get', 'https://:3000/home'));
    
// Setting the target when initializing from another source:
$file = __DIR__ . '/default-config.yml';
$default = Artillery::fromYaml($file)
    ->setTarget('http://www.example.com');

$artillery = Artillery::from($default)
    ->setTarget('https://:3000');

环境

可以使用配置覆盖来指定环境,例如目标URL和阶段。

您可以使用另一个Artillery实例的配置,或者使用配置值数组。

$local = Artillery::new('https://:8080')
    ->addPhase(['duration' => 30, 'arrivalRate' => 1, 'rampTo' => 10])
    ->setHttpTimeout(60);

$production = Artillery::new('https://example.com')
    ->addPhase(['duration' => 300, 'arrivalRate' => 10, 'rampTo' => 100])
    ->setHttpTimeout(30);

$artillery = Artillery::new()
    ->setEnvironment('staging', ['target' => 'https://staging.example.com'])
    ->setEnvironment('production', $production)
    ->setEnvironment('local', $local);

静态工厂辅助工具:使用这些来获取新实例并立即调用它们的方法

  • Artillery: new([targetUrl: null|string = null]): Artillery
  • 场景: scenario([name: null|string = null]): Scenario
  • 请求: request([method: null|string = null], [url: null|string = null]): Request
  • Ws请求: wsRequest([method: null|string = null], [request: mixed = null]): WsRequest
  • 任意请求: anyRequest([method: null|string = null], [request: mixed = null]): AnyRequest
$artillery = Artillery::new($targetUrl)
    ->addPhase(['duration' => 60, 'arrivalRate' => 10]);
    
$request = Artillery::request('get', '/login')
    ->addCapture('token', 'json', '$.token');
    
$scenario = Artillery::scenario('Logging in')->addRequest($request);

场景相关方法

您可以添加一个完整构建的场景,或者传递单个请求或请求数组,然后从中创建一个场景。

请参阅场景类以获取更多详细信息。

  • addScenario(scenario: array|RequestInterface|RequestInterface[]|Scenario, [options: mixed[]|null = null])
    • 将场景添加到Artillery脚本的场景部分。
  • setAfter(after: array|RequestInterface|RequestInterface[]|Scenario)
    • 设置在场景部分中的场景完成后要运行的场景。
  • setBefore(before: array|RequestInterface|RequestInterface[]|Scenario)
    • 添加一个场景,在场景部分的任何给定场景之前运行。

处理器 & 函数钩子

场景的流程和请求可以具有JavaScript函数钩子,可以读取和修改上下文,如变量。

以下是从examples/generating-vu-tokens的一个非常具有说明性的示例。

// This scenario will run once before any main scenarios/virtual users; here we're using a js function 
// from a processor to generate a variable available in all future scenarios and their virtual users:
$before = Artillery::scenario()->addFunction('generateSharedToken');

// One of the main scenarios, which has access to the shared token,
// and here we're generating a token unique to every main scenario that executed.
$scenario = Artillery::scenario()
    ->addFunction('generateVUToken')
    ->addLog('VU id: {{ $uuid }}')
    ->addLog('    shared token is: {{ sharedToken }}')
    ->addLog('    VU-specific token is: {{ vuToken }}')
    ->addRequest(
        Artillery::request('get', '/')
            ->setHeaders([
                'x-auth-one' => '{{ sharedToken }}',
                'x-auth-two' => '{{ vuToken }}'
            ]));

$artillery = Artillery::new('http://www.artillery.io')
    ->setProcessor('./helpers.js')
    ->setBefore($before)
    ->addScenario($scenario);

./helpers.js

module.exports = {
  generateSharedToken,
  generateVUToken
};

function generateSharedToken(context, events, done) {
  context.vars.sharedToken = `shared-token-${Date.now()}`;
  return done();
}

function generateVUToken(context, events, done) {
  context.vars.vuToken = `vu-token-${Date.now()}`;
  return done();
}

请参阅Artillery.io文档以获取必要的函数签名。

配置设置

请参阅文档:https://bundeling.github.io/ArtilleryPhp/classes/ArtilleryPhp-Artillery#methods

  • addEnsureCondition(expression: string, [strict: bool|null = null])
  • addEnsureConditions(thresholds: array[])
  • addEnsureThreshold(metricName: string, value: int)
  • addEnsureThresholds(thresholds: int[][])
  • setEngine(name: string, [options: array|null = null])
  • setEngines(engines: array[]|string[])
  • setEnvironment(name: string, config: array|Artillery)
  • setEnvironments(environments: array[]|Artillery[])
  • addPayload(path: string, fields: array, [options: bool[]|string[] = [...]])
  • addPayloads(payloads: bool[][]|string[][])
  • addPhase(phase: array, [name: null|string = null])
  • addPhases(phases: array[])
  • setPlugin(name: string, [options: array|null = null])
  • setPlugins(plugins: array)
  • setVariable(name: string, value: mixed)
  • setVariables(variables: mixed[])
  • setHttp(key: string, value: bool|int|mixed)
  • setHttps(options: bool[]|int[])
  • setHttpTimeout(timeout: int)
  • setHttpMaxSockets(maxSockets: int)
  • setHttpExtendedMetrics([extendedMetrics: bool = true])
  • setProcessor(path: string)
  • setTarget(url: string)
  • setTls(rejectUnauthorized: bool)
  • setWs(wsOptions: array)

渲染和加载

  • build([file: null|string = null]): Artillery构建脚本并将其保存为YAML文件。
  • toYaml(): string将脚本渲染为Yaml字符串。
  • from(artillery: Artillery): Artillery从给定的Artillery实例创建新的Artillery实例。
  • fromArray(script: array): Artillery从给定的数组数据创建新的Artillery实例。
  • fromYaml(file: string): Artillery从给定的Yaml文件创建新的Artillery实例。
  • toArray(): array获取当前Artillery实例的数组表示。
  • run([reportFile: null|string = null], [debug: null|string = null]): Artillery运行构建的脚本(或构建和运行),并将报告保存到带时间戳的文件中。

场景类

场景类包括与场景及其流程相关的所有方法。

文档:https://bundeling.github.io/ArtilleryPhp/classes/ArtilleryPhp-Scenario

// Imagine we have an already defined Scenario as $defaultScenario
$scenario = Artillery::scenario()  
    ->setName('Request, pause 2 seconds, then default flow.')
    ->addRequest(Artillery::request('GET', '/'))  
    ->addThink(2)  
    ->addFlow($defaultScenario);

方法

文档:https://bundeling.github.io/ArtilleryPhp/classes/ArtilleryPhp-Scenario#methods


自定义场景设置

  • set(key: string, value: mixed)


从另一个场景添加到当前场景的流程

  • addFlow(scenario: Scenario)


杂项

  • setName(name: string) 用于指标报告。
  • setWeight(weight: int) 默认:1。确定与其他场景相比,此场景被选中的概率。


如果没有设置,引擎默认为HTTP请求。要创建WebSocket场景,需要指定此场景的引擎为'ws',并仅使用WsRequest类的实例,这些实例在Artillery::wsRequest()中可用。

  • setEngine(engine: string)


场景级别的JavaScript函数钩子,来自在Artillery实例中定义的setProcessor中的Js文件

  • addAfterScenario(function: array|string|string[])
  • addBeforeScenario(function: array|string|string[])

对于请求,同样有场景级别的在请求前后的钩子

  • addAfterResponse(function: array|string|string[])
  • addBeforeRequest(function: array|string|string[])

有关js函数钩子的更多详细信息,请参阅Artillery.io 文档


流程方法

  • addRequest(request: RequestInterface)
  • addRequests(requests: RequestInterface[])
  • addLoop(loop: array|RequestInterface|RequestInterface[]|Scenario|Scenario[], [count: int|null = null], [over: null|string = null], [whileTrue: null|string = null])
  • addLog(message: string, [ifTrue: null|string = null])
  • addThink(duration: float, [ifTrue: null|string = null])
  • addFunction(function: array|string|string[], [ifTrue: null|string = null])

请求类

文档:https://bundeling.github.io/ArtilleryPhp/classes/ArtilleryPhp-Request

Request类包含与HTTP请求相关的所有方法,以及从RequestBase类继承的一些共享方法。

$getTarget = Artillery::request('get', '/inbox')  
    ->setJson('client_id', '{{ id }}')  
    ->addCapture('first_inbox_id', 'json', '$[0].id');  
$postResponse = Artillery::request('post', '/inbox')  
    ->setJsons(['user_id' => '{{ first_inbox_id }}', 'message' => 'Hello, world!']);

对于WebSocket,可以在Artillery::wsRequest()中找到WsRequest类的粗略实现。

$stringScenario = Artillery::scenario('Sending a string')
    ->setEngine('ws')
    ->addRequest(Artillery::wsRequest('send', 'Artillery'));

对于自定义请求,AnyRequest应与这些函数匿名使用。

  • set(key: string, value: mixed)
  • setMethod(method: string)
  • setRequest(request: mixed)
$emitAndValidateResponse = Artillery::scenario('Emit and validate response')
    ->setEngine('socketio')
    ->addRequest(
        Artillery::anyRequest('emit')
            ->set('channel', 'echo')
            ->set('data', 'Hello from Artillery')
            ->set('response', ['channel' => 'echoResponse', 'data' => 'Hello from Artillery']));

方法

请参阅文档:https://bundeling.github.io/ArtilleryPhp/classes/ArtilleryPhp-Request#methods

  • addAfterResponse(function: array|string|string[])
  • addBeforeRequest(function: array|string|string[])
  • setAuth(user: string, pass: string)
  • setBody(body: mixed)
  • setCookie(name: string, value: string)
  • setCookies(cookies: string[])
  • setFollowRedirect([followRedirect: bool = true])
  • setForm(key: string, value: mixed)
  • setForms(form: array)
  • setFormDatas(formData: array)
  • setFormData(key: string, value: mixed)
  • setGzip([gzip: bool = true])
  • setHeader(key: string, value: string)
  • setHeaders(headers: string[])
  • setIfTrue(expression: string)
  • setJson([key: null|string = null], [value: mixed = null])
  • setJsons(jsons: mixed[])
  • setMethod(method: string)
  • setQueryStrings(key: string, value: mixed)
  • setQueryStrings(qs: array)
  • setUrl(url: string)

继承

  • set(key: string, data: mixed)
  • setMethod(method: string)
  • setRequest(request: mixed)
  • addCapture(as: string, type: string, expression: string, [strict: bool = true], [attr: null|string = null], [index: int|null|string = null])
  • addCaptures(captures: int[][]|string[][])
  • addExpect(type: string, value: mixed, [equals: mixed = null])
  • addExpects(expects: mixed[][])
  • addMatch(type: string, expression: string, value: mixed, [strict: bool = true], [attr: null|string = null], [index: int|null|string = null])
  • addMatches(matches: mixed[][])