Skip to content

Commit

Permalink
Feat/assignment testing (#457)
Browse files Browse the repository at this point in the history
* fix(ci): helm chart release (#407)

* fix(ci): helm chart release action version (#404)

* Bump guzzlehttp/guzzle from 7.7.0 to 7.8.0 (#403)

Bumps [guzzlehttp/guzzle](https://github.com/guzzle/guzzle) from 7.7.0 to 7.8.0.
- [Release notes](https://github.com/guzzle/guzzle/releases)
- [Changelog](https://github.com/guzzle/guzzle/blob/7.8/CHANGELOG.md)
- [Commits](guzzle/guzzle@7.7.0...7.8.0)

---
updated-dependencies:
- dependency-name: guzzlehttp/guzzle
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* Bump axios from 1.4.0 to 1.5.0 (#402)

Bumps [axios](https://github.com/axios/axios) from 1.4.0 to 1.5.0.
- [Release notes](https://github.com/axios/axios/releases)
- [Changelog](https://github.com/axios/axios/blob/v1.x/CHANGELOG.md)
- [Commits](axios/axios@v1.4.0...v1.5.0)

---
updated-dependencies:
- dependency-name: axios
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* fix(ci): helm chart release (#406)

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* create division logger and offer env var for log file path

* create controller and routes to use division logger

* add logging to divisions and fix assignLeftover bug

* create testing seeder and add config values for it

* enable logging for both divisions

* remove unused functions from GBD

* additional checks for optimization and fixing leftover assignment

* renamed seeder config to testingSeeder

* remove logging routes, disable logging by default, rename logging env var

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: Simon Ostendorf <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 9, 2023
1 parent 78bc372 commit 5e25add
Show file tree
Hide file tree
Showing 9 changed files with 278 additions and 48 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,6 @@ VITE_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"

OCTANE_HTTPS=false
OCTANE_WORKERS=4
OCTANE_MAX_REQUESTS=512
OCTANE_MAX_REQUESTS=512

DIVISION_DEBUG_LOG=
102 changes: 102 additions & 0 deletions app/Helpers/DivisionLogger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
<?php

namespace App\Helpers;

use App\Models\Course;
use App\Models\Event;
use App\Models\Group;

class DivisionLogger
{
public string $logFilePath;
public int $writeFlags;

public function __construct($logFilePath, $writeFlags = FILE_APPEND)
{
$this->logFilePath = $logFilePath;
$this->writeFlags = $writeFlags;
}

/**
* Logs current state of specified event
*
* @param Event $event The event that will be logged
* @return void
*/
public function logEvent(Event $event)
{
$groupsTotal = $event->groups()->count();
$regsTotal = $event->registrations()->count();
$nonDrinkerRegsTotal = $event->registrations()->where('drinks_alcohol', '=', false)->count();

$line = sprintf('Event %d :: %d groups, %d total regs, %d non-drinker regs (%d %%)', $event->id, $groupsTotal, $regsTotal, $nonDrinkerRegsTotal, $nonDrinkerRegsTotal/$regsTotal * 100);

$line .= "\n";
foreach (Course::all() as $course) {
$regs = $event->registrations()->get();
$regsOfCourse = $regs->toQuery()
->join('users', 'registrations.user_id', '=', 'users.id')
->where('users.course_id', '=', $course->id)
->get();
$regsCount = $regsOfCourse->count();
$nonDrinkerRegsCount = $regsOfCourse->where('drinks_alcohol', '=', false)->count();

$line .= sprintf('%s : [ %d t (%d %%), %d nd ] ;', $course->abbreviation, $regsCount, $regsCount/$regsTotal * 100, $nonDrinkerRegsCount);
}

$this->logMsg($line . "\n-----\n");

foreach ($event->groups as $group) {
$this->logGroup($group);
}

$this->logMsg("-----\n");
}

/**
* Logs current state of specified group
*
* @param Group $group The group that will be logged
* @return void
*/
public function logGroup(Group $group)
{
$regsTotal = $group->registrations()->count();
$nonDrinkerRegsTotal = $group->registrations()->where('drinks_alcohol', '=', false)->count();

$line = sprintf('Group %d :: %d total, %d non-drinker -- ', $group->id, $regsTotal, $nonDrinkerRegsTotal);

if ($regsTotal == 0) {
$line .= "\n";
$this->logMsg($line);
return;
}

$this->logMsg($line);

$line = "";
foreach (Course::all() as $course) {
$regs = $group->registrations()->get();
$regsOfCourse = $regs->toQuery()
->join('users', 'registrations.user_id', '=', 'users.id')
->where('users.course_id', '=', $course->id)
->get();
$regsCount = $regsOfCourse->count();
$nonDrinkerRegsCount = $regsOfCourse->where('drinks_alcohol', '=', false)->count();

$line .= sprintf('%s : [ %d t (%d %%), %d nd ] ;', $course->abbreviation, $regsCount, $regsCount/$regsTotal * 100, $nonDrinkerRegsCount);
}
$this->logMsg($line . "\n");
}

/**
* Logs a single message
*
* @param string $msg
* @return void
*/
public function logMsg(string $msg)
{
file_put_contents($this->logFilePath, $msg, $this->writeFlags);
}
}
49 changes: 4 additions & 45 deletions app/Helpers/GroupBalancedDivision.php
Original file line number Diff line number Diff line change
Expand Up @@ -156,51 +156,6 @@ protected function assignUntilSatisfies()
$this->assignBalanced($unassignedRegs, $this->registrations);
}

// TODO If confident that this is not necessary anymore, just delete
protected function assignLeftoverTo(Collection $leftoverRegs, Collection $groups)
{
// Sort groups by how many registrations are assigned to it
$sortedGroups = $groups->sortBy(function ($group) {
return $group->registrations()->count();
});

// Assign registrations to the groups
$i = 0;
$amountOfGroups = $sortedGroups->count();
foreach ($leftoverRegs as $registration) {
if ($i >= $amountOfGroups) {
$i = 0;
}

$registration->group_id = $sortedGroups[$i]->id;
$registration->save();
$i++;
}
}

// TODO If confident that this is not necessary anymore, just delete
public function assignLeftoverAlt()
{
// Get only registrations that have yet to be assigned a group
$unassignedRegs = $this->getUnassignedRegs();

if ($this->assignByAlc) {
$unassignedNonDrinkers = $unassignedRegs->where('drinks_alcohol', '=', false);
$groupsWithNonDrinkers = $this->groups->filter(function ($val, $key) {
return $val->registrations()
->where('drinks_alcohol', '=', false)
->count() > 0;
});

$this->assignLeftoverTo($unassignedNonDrinkers, $groupsWithNonDrinkers);
}

// Refresh in case non-drinkers got assigned
$unassignedRegs = $unassignedRegs->where('group_id', '=', null);

$this->assignLeftoverTo($unassignedRegs, $this->groups);
}

/**
* {@inheritDoc}
*/
Expand All @@ -212,11 +167,15 @@ public function assign()
});

if ($groupsNotAssigned) {
$this->loggingEnabled ? $this->logCurrState("Pre-assignInitial") : 0;
$this->assignInitial();
$this->loggingEnabled ? $this->logCurrState("Post-assignInitial") : 0;
}
$this->loggingEnabled ? $this->logCurrState("Pre-assignLeftover") : 0;
$this->assignLeftover();
if ($this->maxGroupSize > 0) {
$this->updateQueuePos($this->getUnassignedRegs()->sortBy('queue_position'));
}
$this->loggingEnabled ? $this->logCurrState("Post-assignLeftover") : 0;
}
}
4 changes: 4 additions & 0 deletions app/Helpers/GroupCourseDivision.php
Original file line number Diff line number Diff line change
Expand Up @@ -98,11 +98,15 @@ public function assign()
});

if ($courseNotAssigned) {
$this->loggingEnabled ? $this->logCurrState("Pre-assignInitial") : 0;
$this->assignInitial();
$this->loggingEnabled ? $this->logCurrState("Post-assignInitial") : 0;
}
$this->loggingEnabled ? $this->logCurrState("Pre-assignLeftover") : 0;
$this->assignLeftover();
if ($this->maxGroupSize > 0) {
$this->updateQueuePos($this->getUnassignedRegs()->sortBy('queue_position'));
}
$this->loggingEnabled ? $this->logCurrState("Pre-assignLeftover") : 0;
}
}
46 changes: 44 additions & 2 deletions app/Helpers/GroupDivision.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ abstract class GroupDivision

protected int $minNonDrinkers;

protected bool $loggingEnabled;
protected string $loggingFilePath;

public function __construct(Event $event, bool $assignByAlc, int $maxGroups = 0, int $maxGroupSize = 0, int $minNonDrinkers = 3)
{
$this->event = $event;
Expand All @@ -31,6 +34,37 @@ public function __construct(Event $event, bool $assignByAlc, int $maxGroups = 0,
$this->maxGroups = $maxGroups;
$this->maxGroupSize = $maxGroupSize;
$this->minNonDrinkers = $minNonDrinkers;

$this->loggingEnabled = false;
$this->loggingFilePath = storage_path('logs/' . env('DIVISION_DEBUG_LOG', 'division.log'));
}

/**
* Enables detailed logging for this division to a specified file path. Use before calling "assign()"
*
* @param string $logFilePath Path where the logs will be written
* @return void
*/
public function enableLogging(string $logFilePath = "")
{
$this->loggingEnabled = true;
if ($logFilePath) $this->loggingFilePath = $logFilePath;
}

/**
* Logs current state of this division (meaning groups with info on their assigned registrations) if logging is enabled
*
* @param string $statename Describes what state the division is in at the time of logging
* @return void
*/
public function logCurrState(string $statename)
{
if ($this->loggingEnabled == false) return;

$logger = new DivisionLogger($this->loggingFilePath);

$logger->logMsg("-----\n DIVISION STATE: " . $statename . "\n-----\n");
$logger->logEvent($this->event);
}

/**
Expand Down Expand Up @@ -100,8 +134,10 @@ protected function assignInitial()
{
if ($this->assignByAlc) {
$this->assignNonDrinkers();
$this->loggingEnabled ? $this->logCurrState("Post-assignNonDrinkers") : 0;
}
$this->assignUntilSatisfies();
$this->loggingEnabled ? $this->logCurrState("Post-assignUntilSatisfies") : 0;
if ($this->maxGroupSize > 0) {
$this->updateQueuePos($this->getUnassignedRegs());
}
Expand Down Expand Up @@ -144,10 +180,16 @@ public function assignLeftover()

$cycleAssignByAlc = $this->assignByAlc; // Determines if this assign cycle should consider alcohol consumption at any given time

foreach ($unassignedRegs as $registration) {
while ($unassignedRegs->isNotEmpty()) {
$group = $groupsWithOpenSpots->first();

if ($cycleAssignByAlc) {
// If there are no non-drinkers left, the following assign cycles can safely skip alcohol considerations
if ($cycleAssignByAlc && $unassignedRegs->where('drinks_alcohol', '=', false)->count() == 0)
$cycleAssignByAlc = false;

$registration = $unassignedRegs->pop();

if ($cycleAssignByAlc && $registration->drinks_alcohol) {
$group = $groupsWithOpenSpots->filter(function ($val, $key) {
return $val->registrations()
->where('drinks_alcohol', '=', false)
Expand Down
39 changes: 39 additions & 0 deletions app/Http/Controllers/DivisionLoggingController.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace App\Http\Controllers;

use App\Helpers\GroupBalancedDivision;
use App\Helpers\DivisionLogger;
use App\Models\Event;
use App\Models\Group;

class DivisionLoggingController extends Controller
{
public function logGrp(int $groupId)
{
$logPath = 'logs/' . env('DIVISION_DEBUG_LOG', 'division.log');
$logger = new DivisionLogger(storage_path($logPath));

$group = Group::find($groupId);

if (! $group) return sprintf('DIVISION_LOGGER_ERROR: Could not find group with ID %&d', $groupId);

$logger->logGroup($group);

return sprintf('DIVISION_LOGGER: Wrote group log (%s)', storage_path($logPath));
}

public function logEvt(int $eventId)
{
$logPath = 'logs/' . env('DIVISION_DEBUG_LOG', 'division.log');
$logger = new DivisionLogger(storage_path($logPath));

$event = Event::find($eventId);

if (! $event) return sprintf('DIVISION_LOGGER_ERROR: Could not find event with ID %&d', $eventId);

$logger->logEvent($event);

return sprintf('DIVISION_LOGGER: Wrote event log (%s)', storage_path($logPath));
}
}
19 changes: 19 additions & 0 deletions config/database.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,25 @@

'migrations' => 'migrations',

/*
|--------------------------------------------------------------------------
| Testing Seeder Values
|--------------------------------------------------------------------------
|
| These values can be used to dynamically configure the testing seeder.
| For example, we can decide for what course and how many registrations
| (drinker and non-drinker) the seeder should create.
|
*/

'testingSeeder' => [
'event_id' => env('SEEDER_EVENT_ID', 1),
'course_id' => env('SEEDER_COURSE_ID', 1),
'slot_id' => env('SEEDER_SLOT_ID', null),
'regs_total' => env('SEEDER_TOTAL', 1),
'regs_nd' => env('SEEDER_NONDRINKERS', 1)
],

/*
|--------------------------------------------------------------------------
| Redis Databases
Expand Down
Loading

0 comments on commit 5e25add

Please sign in to comment.