add test create 3000 users

This commit is contained in:
root
2026-06-08 01:53:27 -04:00
parent 68a5c9edca
commit 8ca24ef03f
4 changed files with 889 additions and 0 deletions
File diff suppressed because one or more lines are too long
+103
View File
@@ -0,0 +1,103 @@
{
"@programName": "ZAP",
"@version": "2.17.0",
"@generated": "Mon, 8 Jun 2026 05:33:02",
"created": "2026-06-08T05:33:02.123437092Z",
"insights":[
{
"level": "Info",
"reason": "Informational",
"site": "http://host.docker.internal:5173",
"key": "insight.code.4xx",
"description": "Percentage of responses with status code 4xx",
"statistic": "100"
},
{
"level": "Info",
"reason": "Informational",
"site": "http://host.docker.internal:5173",
"key": "insight.endpoint.ctype.text/plain",
"description": "Percentage of endpoints with content type text/plain",
"statistic": "100"
},
{
"level": "Info",
"reason": "Informational",
"site": "http://host.docker.internal:5173",
"key": "insight.endpoint.method.GET",
"description": "Percentage of endpoints with method GET",
"statistic": "100"
},
{
"level": "Info",
"reason": "Informational",
"site": "http://host.docker.internal:5173",
"key": "insight.endpoint.total",
"description": "Count of total endpoints",
"statistic": "2"
}
],
"site":[
{
"@name": "http://host.docker.internal:5173",
"@host": "host.docker.internal",
"@port": "5173",
"@ssl": "false",
"alerts": [
{
"pluginid": "10049",
"alertRef": "10049-1",
"alert": "Non-Storable Content",
"name": "Non-Storable Content",
"riskcode": "0",
"confidence": "2",
"riskdesc": "Informational (Medium)",
"desc": "<p>The response contents are not storable by caching components such as proxy servers. If the response does not contain sensitive, personal or user-specific information, it may benefit from being stored and cached, to improve performance.</p>",
"instances":[
{
"id": "3",
"uri": "http://host.docker.internal:5173",
"nodeName": "http:\/\/host.docker.internal:5173",
"method": "GET",
"param": "",
"attack": "",
"evidence": "403",
"otherinfo": ""
},
{
"id": "2",
"uri": "http://host.docker.internal:5173/robots.txt",
"nodeName": "http:\/\/host.docker.internal:5173\/robots.txt",
"method": "GET",
"param": "",
"attack": "",
"evidence": "403",
"otherinfo": ""
},
{
"id": "1",
"uri": "http://host.docker.internal:5173/sitemap.xml",
"nodeName": "http:\/\/host.docker.internal:5173\/sitemap.xml",
"method": "GET",
"param": "",
"attack": "",
"evidence": "403",
"otherinfo": ""
}
],
"count": "3",
"systemic": false,
"solution": "<p>The content may be marked as storable by ensuring that the following conditions are satisfied:</p><p>The request method must be understood by the cache and defined as being cacheable (\"GET\", \"HEAD\", and \"POST\" are currently defined as cacheable)</p><p>The response status code must be understood by the cache (one of the 1XX, 2XX, 3XX, 4XX, or 5XX response classes are generally understood)</p><p>The \"no-store\" cache directive must not appear in the request or response header fields</p><p>For caching by \"shared\" caches such as \"proxy\" caches, the \"private\" response directive must not appear in the response</p><p>For caching by \"shared\" caches such as \"proxy\" caches, the \"Authorization\" header field must not appear in the request, unless the response explicitly allows it (using one of the \"must-revalidate\", \"public\", or \"s-maxage\" Cache-Control response directives)</p><p>In addition to the conditions above, at least one of the following conditions must also be satisfied by the response:</p><p>It must contain an \"Expires\" header field</p><p>It must contain a \"max-age\" response directive</p><p>For \"shared\" caches such as \"proxy\" caches, it must contain a \"s-maxage\" response directive</p><p>It must contain a \"Cache Control Extension\" that allows it to be cached</p><p>It must have a status code that is defined as cacheable by default (200, 203, 204, 206, 300, 301, 404, 405, 410, 414, 501).</p>",
"otherinfo": "",
"reference": "<p>https://datatracker.ietf.org/doc/html/rfc7234</p><p>https://datatracker.ietf.org/doc/html/rfc7231</p><p>https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html</p>",
"cweid": "524",
"wascid": "13",
"sourceid": "1"
}
]
}
],
"sequences":[
]
}
+40
View File
@@ -0,0 +1,40 @@
env:
contexts:
- excludePaths: []
name: baseline
urls:
- http://host.docker.internal:4173
parameters:
failOnError: true
progressToStdout: false
jobs:
- parameters:
enableTags: false
maxAlertsPerRule: 10
type: passiveScan-config
- parameters:
maxDuration: 1
url: http://host.docker.internal:4173
type: spider
- parameters:
maxDuration: 0
type: passiveScan-wait
- parameters:
format: Long
summaryFile: /home/zap/zap_out.json
rules: []
type: outputSummary
- parameters:
reportDescription: ''
reportDir: /zap/wrk/
reportFile: zap-preview.html
reportTitle: ZAP Scanning Report
template: traditional-html
type: report
- parameters:
reportDescription: ''
reportDir: /zap/wrk/
reportFile: zap-preview.json
reportTitle: ZAP Scanning Report
template: traditional-json
type: report
@@ -0,0 +1,125 @@
<?php
namespace Tests\Feature;
use App\Models\Role;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class BulkUserRoleCreationTest extends TestCase
{
use RefreshDatabase;
public function test_it_creates_one_thousand_parents_teachers_and_admins_through_the_api(): void
{
$roles = $this->seedRolesForUserCreation();
$adminActor = $this->createAuthenticatedAdministratorActor($roles['administrator']);
$this->actingAs($adminActor, 'api');
$this->createUsersThroughApi('parent', (int) $roles['parent']->id, 1000);
$this->createUsersThroughApi('teacher', (int) $roles['teacher']->id, 1000);
$this->createUsersThroughApi('admin', (int) $roles['admin']->id, 1000);
$this->assertSame(3000, User::query()->where('email', 'like', 'bulk_api_%')->count());
$this->assertSame(1000, User::query()->hasRoleName('parent')->where('email', 'like', 'bulk_api_parent_%')->count());
$this->assertSame(1000, User::query()->hasRoleName('teacher')->where('email', 'like', 'bulk_api_teacher_%')->count());
$this->assertSame(1000, User::query()->hasRoleName('admin')->where('email', 'like', 'bulk_api_admin_%')->count());
$this->assertDatabaseHas('users', [
'email' => 'bulk_api_parent_0001@example.test',
'status' => 'Active',
'is_verified' => 1,
]);
$this->assertSame(
['parent'],
User::query()->where('email', 'bulk_api_parent_0001@example.test')->firstOrFail()->roleNames()
);
$this->assertSame(
['teacher'],
User::query()->where('email', 'bulk_api_teacher_0001@example.test')->firstOrFail()->roleNames()
);
$this->assertSame(
['admin'],
User::query()->where('email', 'bulk_api_admin_0001@example.test')->firstOrFail()->roleNames()
);
}
/**
* @return array<string, Role>
*/
private function seedRolesForUserCreation(): array
{
return collect([
'administrator' => ['name' => 'administrator', 'slug' => 'administrator', 'priority' => 5],
'admin' => ['name' => 'admin', 'slug' => 'admin', 'priority' => 10],
'teacher' => ['name' => 'teacher', 'slug' => 'teacher', 'priority' => 20],
'parent' => ['name' => 'parent', 'slug' => 'parent', 'priority' => 30],
])->mapWithKeys(function (array $attributes, string $key): array {
return [
$key => Role::query()->create($attributes + [
'description' => ucfirst(str_replace('_', ' ', $key)),
'dashboard_route' => 'administrator/administratordashboard',
'is_active' => 1,
]),
];
})->all();
}
private function createAuthenticatedAdministratorActor(Role $administratorRole): User
{
$adminActor = User::factory()->create([
'email' => 'bulk-api-test-actor@example.test',
'status' => 'Active',
'is_verified' => 1,
]);
$adminActor->roles()->attach($administratorRole->id);
return $adminActor;
}
private function createUsersThroughApi(string $roleName, int $roleId, int $count): void
{
for ($index = 1; $index <= $count; $index++) {
$response = $this->postJson('/api/v1/users', $this->payloadForUser($roleName, $roleId, $index));
$response
->assertCreated()
->assertJsonPath('ok', true);
}
}
/**
* @return array<string, mixed>
*/
private function payloadForUser(string $roleName, int $roleId, int $index): array
{
$number = str_pad((string) $index, 4, '0', STR_PAD_LEFT);
$name = ucfirst($roleName);
return [
'firstname' => "Bulk{$name}",
'lastname' => "User{$number}",
'gender' => $index % 2 === 0 ? 'Female' : 'Male',
'cellphone' => '555' . str_pad((string) $index, 7, '0', STR_PAD_LEFT),
'email' => "bulk_api_{$roleName}_{$number}@example.test",
'address_street' => "{$index} Test Street",
'city' => 'Brooklyn',
'state' => 'NY',
'zip' => '11201',
'accept_school_policy' => true,
'role_id' => $roleId,
'password' => 'password',
'semester' => 'Fall',
'school_year' => '2025-2026',
'school_id' => 1,
'user_type' => 'primary',
'status' => 'Active',
'is_verified' => true,
'is_suspended' => false,
];
}
}