Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ci-develop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ jobs:

# Unit-tests only (exclude integration markers)
- name: Run unit tests
env:
ENVIRONMENT: test
run: poetry run pytest -m "not integration" --disable-warnings


Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ pip-wheel-metadata/
venv/
ENV/
env/
docker_fs/.env
docker_fs/.env.*

# Poetry-specific
.cache/pypoetry/
Expand Down
11 changes: 0 additions & 11 deletions docker_fs/.env.dev

This file was deleted.

12 changes: 0 additions & 12 deletions docker_fs/.env.test

This file was deleted.

73 changes: 2 additions & 71 deletions DEV_WORKFLOW_GUIDE.md → documentation/DEV_WORKFLOW_GUIDE.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# **Development Workflow & Architecture Guide**

This document outlines the standardized development workflow, repository architecture, and branching strategy for this project. Adhering to these guidelines ensures consistency, maintainability, and a scalable development process.
This document outlines the standardized development workflow, repository architecture, and branching strategy for the backend of the FastSim project. Adhering to these guidelines ensures consistency, maintainability, and a scalable development process.

## 1. Technology Stack

Expand All @@ -13,13 +13,7 @@ The project is built upon the following core technologies:
- **Caching**: Redis
- **Containerization**: Docker

## 2. Architectural Overview: A Multi-Repo Strategy

To promote scalability, team autonomy, and clear separation of concerns, this project adopts a **multi-repo architecture**. Each core component of the system resides in its own dedicated repository. This approach allows for independent development cycles, testing, and deployment.

Our architecture is composed of three main repositories:

### 2.1. Backend Service (`project-backend`)
### 2.1. Backend Service (`FastSim-backend`)

This repository contains all code related to the FastAPI backend service. Its primary responsibility is to handle business logic, interact with the database, and expose a RESTful API.

Expand Down Expand Up @@ -61,69 +55,6 @@ project-backend/
* To be testable in isolation.
* To produce a versioned Docker image (`backend:<tag>`) as its main artifact.

### 2.2. Frontend Service (`project-frontend`)

This repository contains all code for the React web application. Its responsibility is to provide the user interface and interact with the backend via its API.

**Folder Structure:**
```
project-frontend/
├── .github/
│ └── workflows/
│ └── main.yml # CI: Tests and publishes the frontend Docker image
├── public/ # Static assets (index.html, favicon, etc.)
├── src/ # Application source code
│ ├── api/ # Functions for backend API calls
│ ├── components/ # Reusable UI components
│ ├── hooks/ # Custom React hooks
│ ├── mocks/ # Service worker mocks for API (for isolated testing)
│ ├── pages/ # Page components
│ └── index.js # React application entrypoint
├── .env.example
├── .gitignore
├── docker-compose.yml # Base local development definition
├── Dockerfile # Multi-stage build for a lean production image
├── package.json
├── package-lock.json
└── README.md # Setup instructions for the frontend service
```

**Key Responsibilities:**
* To be testable in isolation (using a mocked API).
* To produce a versioned, production-ready Docker image (`frontend:<tag>`), typically served by Nginx.

### 2.3. Infrastructure & E2E Tests (`project-master`)

This repository is the "glue" that holds the system together. It does not contain application code but rather the configuration to orchestrate, test, and deploy the entire system.

**Folder Structure:**
```
project-master/
├── .github/
│ └── workflows/
│ ├── e2e-tests.yml # CI: Runs End-to-End tests on a complete stack
│ └── deploy.yml # CD: Handles deployment to environments
├── e2e-tests/ # End-to-End test suite (e.g., Cypress, Playwright)
│ ├── cypress/ # Test code
│ └── cypress.config.js
├── environments/ # Environment-specific configurations
│ ├── staging/
│ │ ├── docker-compose.yml # Docker Compose file for the Staging environment
│ │ └── .env.example
│ └── production/
│ ├── docker-compose.yml # Docker Compose file for the Production environment
│ └── .env.example
├── scripts/ # Deployment and utility scripts
│ ├── deploy-staging.sh
│ └── deploy-prod.sh
└── README.md # Main project README: explains the overall architecture
```

**Key Responsibilities:**
* To define the composition of services for each environment (Staging, Production).
* To run End-to-End tests that validate the integration between services.
* To manage the Continuous Deployment (CD) process.

## 3. Branching Strategy: Git Flow

To manage code development and releases in a structured manner, we use the **Git Flow** branching model.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
Below is a guided walkthrough of **`tests/unit/simulation/test_sampler_helper.py`**, explaining core ideas and each test’s intent.

---

## File purpose

This file verifies that your three helper functions—

* `uniform_variable_generator`
* `poisson_variable_generator`
* `truncated_gaussian_generator`

—correctly delegate to whatever RNG you pass in, and fall back to NumPy’s default RNG when you don’t provide one.

---

## Key testing patterns

1. **Dependency injection via `rng`**
Each helper takes an `rng` parameter. In production you’ll pass a `np.random.Generator`; in tests we inject a **`DummyRNG`** with predictable outputs to make our tests **deterministic**.

2. **Duck typing**
Python doesn’t require `rng` to be a specific class—only that it implements the required methods (`random()`, `poisson(mean)`, `normal(mean, sigma)`). Our `DummyRNG` simply implements those three methods.

3. **`typing.cast` for static typing**
We wrap `DummyRNG` instances in `cast("np.random.Generator", DummyRNG(...))` so mypy sees them as satisfying the generator type, but at runtime they remain our dummy.

---

## Test-by-test breakdown

| Test name | What it checks |
| -------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| **`test_uniform_variable_generator_with_dummy_rng`** | Passing a `DummyRNG(uniform_value=0.75)`, `rng.random()` returns 0.75 → helper must return exactly 0.75. |
| **`test_uniform_variable_generator_default_rng_range`** | Without supplying `rng`, the helper uses `default_rng()`. We call it 100× to ensure it always returns a `float` in \[0.0, 1.0). |
| **`test_poisson_variable_generator_with_dummy_rng`** | With `DummyRNG(poisson_value=3)`, `rng.poisson(mean)` yields 3 → helper returns 3. |
| **`test_poisson_variable_generator_reproducible`** | Two NumPy generators created with the same seed (`12345`) must produce the same Poisson sample for `mean=10.0`. |
| **`test_truncated_gaussian_generator_truncates_negative`** | `DummyRNG(normal_value=-2.7)` forces a negative draw: helper must clamp it to **0**. |
| **`test_truncated_gaussian_generator_truncates_toward_zero`** | `DummyRNG(normal_value=3.9)` forces a positive draw: helper must cast/round toward zero (int(3.9) → **3**). |
| **`test_truncated_gaussian_generator_default_rng_non_negative_int`** | With a real seeded RNG, helper must produce **some** non-negative `int` (verifies default fallback path is valid). |

---

## Why this matters

* **Deterministic behavior**: by forcing the RNG’s output via `DummyRNG`, we can assert exactly how our helpers transform that value (clamping, rounding, type conversion).
* **Fallbacks work**: tests with **no** `rng` verify that calling `default_rng()` still gives valid outputs of the correct type and range.
* **Type safety**: using `cast(...)` silences mypy errors while still executing our dummy logic at runtime—ensuring we meet both static‐typing and functional correctness goals.

With this suite, you have **full confidence** that your sampling helpers behave correctly under both controlled (dummy) and uncontrolled (default) RNG conditions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
Below an explanation for the unit tests in the file `tests/unit/simulation/test_simulation_input.py`

### 1. `test_normal_sets_variance_to_mean`

**Purpose:**
Checks that when you create an `RVConfig` with `distribution="normal"` and omit the `variance` field, the model automatically sets `variance = mean`.

* Verifies the “default variance” logic in the post‐init validator.

---

### 2. `test_poisson_keeps_variance_none`

**Purpose:**
Ensures that if you choose the Poisson distribution (`distribution="poisson"`) and do **not** supply a variance, the model **does not** fill in any default variance (keeps it `None`).

* Confirms that defaulting only applies to “normal”/“gaussian,” not to Poisson.

---

### 3. `test_explicit_variance_is_preserved`

**Purpose:**
Validates that if you explicitly pass a `variance` value—even for a distribution that would normally default—it remains exactly what you provided, and is coerced to float.

* Guards against accidental overwriting of user‐supplied variance.

---

### 4. `test_mean_must_be_numeric`

**Purpose:**
Verifies that giving a non‐numeric `mean` (e.g. a string) raises a `ValidationError` with our custom message `"mean must be a number"`.

* Tests the “before” validator on the `mean` field for type checking and coercion.

---

### 5. `test_missing_mean_field`

**Purpose:**
Ensures that completely omitting the `mean` key triggers a standard “field required” error.

* Confirms that `mean` is mandatory in the schema.

---

### 6. `test_gaussian_sets_variance_to_mean`

**Purpose:**
Exactly like the “normal” test above, but for `distribution="gaussian"`.

* Demonstrates that “gaussian” is treated as an alias for “normal” in the default‐variance logic.

---

### 7. `test_default_distribution_is_poisson`

**Purpose:**
Checks two things simultaneously:

1. When you omit `distribution`, it defaults to `"poisson"`.
2. In that default‐poisson case, `variance` remains `None`.

* Validates both the default distribution and its variance behavior in one test.

---

### 8. `test_explicit_variance_kept_for_poisson`

**Purpose:**
Confirms that even if you supply a `variance` when `distribution="poisson"`, the model preserves it rather than discarding it or forcing it back to `None`.

* Provides symmetry to the “explicit variance” test for non‐Poisson cases.

---

### 9. `test_invalid_distribution_raises`

**Purpose:**
Ensures that passing a value for `distribution` outside of the allowed literals (`"poisson"`, `"normal"`, `"gaussian"`) results in a `ValidationError`.

* Confirms that the `Literal[...]` constraint on `distribution` is enforced.

---

With these nine tests you fully cover:

1. **Defaulting behavior** for both “normal” and “gaussian.”
2. **No‐op behavior** for Poisson defaults.
3. **Preservation** of explicit user input.
4. **Type‐checking** on required fields.
5. **Literal‐constraint** enforcement.
Loading