Skip to content

Commit

Permalink
feat: added store for new request type
Browse files Browse the repository at this point in the history
  • Loading branch information
Tbaile committed Dec 16, 2022
1 parent 012040f commit 10a088b
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 37 deletions.
37 changes: 36 additions & 1 deletion app/Http/Controllers/InstallationController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,14 @@

use App\Http\Requests\IndexInstallationRequest;
use App\Http\Requests\StoreInstallationRequest;
use App\Logic\GeoIpLocator;
use App\Models\Country;
use App\Models\Installation;
use GeoIp2\Exception\AddressNotFoundException;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;

class InstallationController extends Controller
{
Expand Down Expand Up @@ -45,8 +51,37 @@ public function index(IndexInstallationRequest $request): JsonResponse
*
* @return \Illuminate\Http\JsonResponse
*/
public function store(StoreInstallationRequest $request): JsonResponse
public function store(StoreInstallationRequest $request, GeoIpLocator $geoIpLocator): JsonResponse
{
try {
$countryRecord = $geoIpLocator->locate($request->ip() ?: '');
} catch (AddressNotFoundException) {
Log::error('Couldn\'t resolve location for: '.$request->ip().' ('.$request->input('uuid').')');
throw new UnprocessableEntityHttpException();
}

$country = Country::firstOrCreate([
'code' => $countryRecord->isoCode,
], [
'name' => $countryRecord->name,
]);

$installation = Installation::firstOrNew([
'data->uuid' => $request->input('uuid'),
]);

if ($installation->exists) {
$installation->touch();
}

$data = $installation->data;
$data['installation'] = $request->input('installation');
$data['facts'] = $request->input('facts');
$installation->data = $data;

$installation->country()->associate($country);
$installation->save();

return response()->json(status: 201);
}
}
2 changes: 2 additions & 0 deletions app/Models/Installation.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ class Installation extends Model
*/
protected $fillable = [
'data->uuid',
'data->installation',
'data->facts',
];

/**
Expand Down
2 changes: 1 addition & 1 deletion tests/Feature/CompatibilityTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@
$response = $this->getJson('/api/installation?interval=7')
->assertOk()
->assertJson([]);
});
})->skip(fn () => config('database.default') == 'sqlite', 'Cannot run on sqlite.');

test('check if interval works', function () {
$installation = Installation::factory()->create();
Expand Down
148 changes: 113 additions & 35 deletions tests/Feature/InstallationTest.php
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
<?php

use App\Logic\GeoIpLocator;
use App\Models\Installation;
use GeoIp2\Exception\AddressNotFoundException;
use GeoIp2\Record\Country;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Log;
use Mockery\MockInterface;

uses(RefreshDatabase::class)->group('installation');
uses(RefreshDatabase::class)
->group('installation')
->beforeEach(function () {
$this->mock(GeoIpLocator::class);
});

const SCHEMA_2022_12 = 'https://schema.nethserver.org/facts/2022-12.json';

Expand Down Expand Up @@ -72,7 +82,7 @@
'uuid' => $uuid,
'installation' => $installation,
'facts' => [
'cluster' => (object) [],
'cluster' => [],
'nodes' => [
'1' => [
'distro' => [
Expand All @@ -82,7 +92,7 @@
'version' => '8.0.0',
],
],
'modules' => (object) [],
'modules' => [],
],
];
$this->postJson('/api/installation', $request)
Expand All @@ -107,7 +117,7 @@
'uuid' => fake()->uuid(),
'installation' => 'nethserver',
'facts' => [
'cluster' => (object) [],
'cluster' => [],
'nodes' => [
'1' => [
'distro' => [
Expand All @@ -117,7 +127,7 @@
'version' => $version,
],
],
'modules' => (object) [],
'modules' => [],
],
];
$this->postJson('/api/installation', $request)
Expand Down Expand Up @@ -164,51 +174,119 @@
]);

it('saves correctly new nethserver installation', function (string $schema) {
$request = [
$installation = Installation::factory()->nethserver()->make();
$request = array_merge($installation->data, [
'$schema' => $schema,
'uuid' => fake()->uuid(),
'installation' => 'nethserver',
'facts' => [
'cluster' => (object) [],
'nodes' => [
'1' => [
'distro' => [
'name' => 'rocky',
'version' => '9.1',
],
'version' => fake()->numerify('#.#.#'),
],
],
'modules' => (object) [],
],
];
]);
$this->mock(GeoIpLocator::class, function (MockInterface $mock) {
$country = $this->mock(Country::class);
$country->name = 'Italy';
$country->isoCode = 'IT';
$mock->shouldReceive('locate')
->once()
->andReturn($country);
});
$this->postJson('/api/installation', $request)
->assertCreated()
->assertJson([]);

$this->assertDatabaseCount('installations', 0);
$this->assertDatabaseCount('installations', 1);
$this->assertDatabaseHas('installations', [
'data->uuid' => $request['uuid'],
'data->installation' => $request['installation'],
'data->facts' => json_encode($request['facts']),
]);
})->with([
SCHEMA_2022_12,
]);

it('saves correctly new nextsecurity installation', function (string $schema) {
$request = [
$installation = Installation::factory()->nextsecurity()->make();
$request = array_merge($installation->data, [
'$schema' => $schema,
'uuid' => fake()->uuid(),
'installation' => 'nextsecurity',
'facts' => [
'distro' => [
'name' => 'rocky',
'version' => '9.1',
],
'version' => fake()->numerify('#.#.#'),
],
];
]);

$this->mock(GeoIpLocator::class, function (MockInterface $mock) {
$country = $this->mock(Country::class);
$country->name = 'Italy';
$country->isoCode = 'IT';
$mock->shouldReceive('locate')
->once()
->andReturn($country);
});

$this->postJson('/api/installation', $request)
->assertCreated()
->assertJson([]);

$this->assertDatabaseCount('installations', 1);
$this->assertDatabaseHas('installations', [
'data->uuid' => $request['uuid'],
'data->installation' => $request['installation'],
'data->facts' => json_encode($request['facts']),
]);
})->with([
SCHEMA_2022_12,
]);

it('updates installation', function (string $schema, string $type) {
$installation = Installation::factory()->$type()->create();
$newInstallation = Installation::factory()->$type()->make();

$request = array_merge($newInstallation->data, [
'$schema' => $schema,
]);
$request['uuid'] = $installation->data['uuid'];

$this->mock(GeoIpLocator::class, function (MockInterface $mock) {
$country = $this->mock(Country::class);
$country->name = 'Italy';
$country->isoCode = 'IT';
$mock->shouldReceive('locate')
->once()
->andReturn($country);
});

$this->postJson('/api/installation', $request)
->assertCreated()
->assertJson([]);

$this->assertDatabaseCount('installations', 1);
$this->assertDatabaseHas('installations', [
'id' => $installation->id,
'data->uuid' => $request['uuid'],
'data->installation' => $request['installation'],
'data->facts' => json_encode($request['facts']),
]);
})->with([
SCHEMA_2022_12,
])->with([
'nethserver',
'nextsecurity',
]);

it('fails to resolve location', function (string $schema, string $type) {
$installation = Installation::factory()->$type()->make();

$request = array_merge($installation->data, [
'$schema' => $schema,
]);

$this->mock(GeoIpLocator::class, function (MockInterface $mock) {
$mock->shouldReceive('locate')
->once()
->andThrow(new AddressNotFoundException());
});

$this->postJson('/api/installation', $request)
->assertUnprocessable();

Log::shouldReceive('error')
->with('Couldn\'t resolve location for: 127.0.0.1 ('.$request['uuid'].')');

$this->assertDatabaseCount('installations', 0);
})->with([
SCHEMA_2022_12,
])->with([
'nethserver',
'nextsecurity',
]);

0 comments on commit 10a088b

Please sign in to comment.