Skip to content

Commit e0d237c

Browse files
authored
Merge pull request #57 from abbastoof/feature/015-game-history-microservice
Feature/015 game history microservice
2 parents c62a26d + 6e751cd commit e0d237c

File tree

13 files changed

+133
-87
lines changed

13 files changed

+133
-87
lines changed

Diff for: .github/workflows/ci-pipeline.yml

+47-9
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,36 @@ jobs:
1616
- name: Check out code
1717
uses: actions/checkout@v2
1818

19-
- name: Build and run linter
20-
uses: docker/build-push-action@v3
19+
- name: Set up Python
20+
uses: actions/setup-python@v2
2121
with:
22-
context: .
23-
file: ./Dockerfile.lint
22+
python-version: '3.11'
23+
24+
- name: Install dependencies
25+
run: |
26+
python -m venv venv
27+
. venv/bin/activate
28+
python -m pip install --upgrade pip
29+
pip install setuptools==58.0.4 wheel
30+
pip install -r requirements.txt
31+
pip install flake8
32+
- name: Create flake8 configuration file
33+
run: |
34+
echo "[flake8]" > .flake8
35+
echo "exclude = venv/*" >> .flake8
36+
echo "max-line-length = 99" >> .flake8
37+
38+
- name: Verify installed packages
39+
run: |
40+
. venv/bin/activate
41+
pip check
42+
43+
- name: Run linters
44+
run: |
45+
. venv/bin/activate
46+
flake8 .
47+
env:
48+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
2449

2550
run-tests:
2651
needs: lint-project
@@ -29,11 +54,24 @@ jobs:
2954
- name: Check out code
3055
uses: actions/checkout@v2
3156

32-
- name: Build and run tests
33-
uses: docker/build-push-action@v3
57+
- name: Set up Python
58+
uses: actions/setup-python@v2
3459
with:
35-
context: .
36-
file: ./Dockerfile.test
60+
python-version: '3.11'
61+
62+
- name: Install dependencies
63+
run: |
64+
python -m venv venv
65+
. venv/bin/activate
66+
python -m pip install --upgrade pip
67+
pip install -r requirements.txt
68+
69+
- name: Run tests
70+
run: |
71+
. venv/bin/activate
72+
pytest --maxfail=1 --disable-warnings
73+
env:
74+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
3775

3876
publish-test-image:
3977
needs: run-tests
@@ -56,7 +94,7 @@ jobs:
5694
uses: docker/build-push-action@v3
5795
with:
5896
context: .
59-
file: ./Dockerfile.publish
97+
file: ./Dockerfile
6098
push: true
6199
tags: ghcr.io/${{ github.repository }}:${{ github.ref_name }}
62100

Diff for: Backend/game_history/game_history/game_data/models.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,17 @@
33

44
class GameHistory(models.Model):
55
game_id = models.AutoField(primary_key=True)
6+
player1_username = models.CharField(max_length=50)
67
player1_id = models.IntegerField()
8+
player2_username = models.CharField(max_length=50)
79
player2_id = models.IntegerField()
810
winner_id = models.IntegerField()
911
start_time = models.DateTimeField()
1012
end_time = models.DateTimeField(null=True, blank=True)
1113
def __str__(self):
12-
return f"Game {self.game_id}: {self.player1_id} vs {self.player2_id} - Winner: {self.winner_id}"
14+
return f"Game {self.game_id}: {self.player1_username} vs {self.player2_username} - Winner: {self.winner_id}"
15+
16+
REQUIRED_FIELDS = ['player1_id', 'player2_id']
1317

1418
class GameStat(models.Model):
1519
game_id = models.OneToOneField(GameHistory, on_delete=models.CASCADE, primary_key=True) # this field is a foreign key to the GameHistory model

Diff for: Backend/game_history/game_history/game_data/serializers.py

+3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,12 @@
44
from .models import GameHistory, GameStat
55

66
class GameHistorySerializer(serializers.ModelSerializer):
7+
game_summary = serializers.SerializerMethodField()
78
class Meta:
89
model = GameHistory
910
fields = '__all__'
11+
def get_game_summary(self, obj):
12+
return str(obj)
1013
class GameStatSerializer(serializers.ModelSerializer):
1114
class Meta:
1215
model = GameStat

Diff for: Backend/game_history/game_history/game_history/tests/conftest.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,11 @@
1313
DATABASES={
1414
"default": {
1515
"ENGINE": "django.db.backends.postgresql",
16-
"NAME": "postgres",
16+
"NAME": "game_history",
17+
"HOST": "postgresql",
1718
"USER": "root",
1819
"PASSWORD": "root",
1920
"PORT": "5432",
20-
"HOST": "localhost",
2121
"ATOMIC_REQUESTS": True,
2222
"TEST": {
2323
"NAME": "mytestdatabase",
@@ -95,7 +95,7 @@
9595
django.setup()
9696

9797
@pytest.fixture(scope='session', autouse=True)
98-
def django_db_setup():
98+
def django_db_modify_db_settings():
9999
settings.DATABASES['default'] = settings.DATABASES['default']['TEST']
100100

101101
@pytest.fixture(scope='session')

Diff for: Backend/game_history/game_history/game_history/tests/test_game_history.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,9 @@ def api_client():
1414
def test_create_game_history(api_client):
1515
url = reverse('game-history-list') # reverse() is used to generate the URL for the 'game-history-list' view
1616
data = {
17+
'player1_username': 'player1',
1718
'player1_id': 1,
19+
'player2_username': 'player2',
1820
'player2_id': 2,
1921
'winner_id': 1,
2022
'start_time': '2024-07-03T12:00:00Z'
@@ -23,7 +25,9 @@ def test_create_game_history(api_client):
2325
assert response.status_code == status.HTTP_201_CREATED
2426
assert GameHistory.objects.count() == 1 # Objects count should be 1 after creating a new GameHistory object in the database
2527
game_history = GameHistory.objects.first() # Get the first GameHistory object from the database (there should be only one) because we just created it
28+
assert game_history.player1_username == 'player1'
2629
assert game_history.player1_id == 1 # The player1_id should be 1 because we set it to 1 in the data
30+
assert game_history.player2_username == 'player2'
2731
assert game_history.player2_id == 2 # The player2_id should be 2 because we set it to 2 in the data
2832
assert game_history.winner_id == 1 # The winner_id should be 1 because we set it to 1 in the data
2933
assert game_history.start_time.isoformat() == '2024-07-03T12:00:00+00:00' # The start_time should be '2024-07-03T12:00:00+00:00' because we set it to that value in the data
@@ -68,18 +72,22 @@ def test_retrieve_game_history(api_client):
6872

6973
@pytest.mark.django_db
7074
def test_update_game_history(api_client):
71-
game = GameHistory.objects.create(player1_id=1, player2_id=2, winner_id=1, start_time=now())
75+
game = GameHistory.objects.create(player1_username='player1', player1_id=1, player2_username='player2', player2_id=2, winner_id=1, start_time=now())
7276

7377
url = reverse('game-history-detail', args=[game.pk])
7478
data = {
79+
'player1_username': 'player1_updated',
7580
'player1_id': 1,
81+
'player2_username': 'player2_updated',
7682
'player2_id': 2,
7783
'winner_id': 2,
7884
'start_time': game.start_time.isoformat().replace('+00:00', 'Z')
7985
}
8086
response = api_client.put(url, data, format='json')
8187
assert response.status_code == status.HTTP_200_OK
8288
game.refresh_from_db()
89+
assert game.player1_username == 'player1_updated'
90+
assert game.player2_username == 'player2_updated'
8391
assert game.winner_id == 2
8492

8593
@pytest.mark.django_db
@@ -108,9 +116,10 @@ def test_create_game_history_validation_error(api_client):
108116
def test_primary_key_increment(api_client):
109117
initial_count = GameHistory.objects.count()
110118

111-
# Create a new game history entry
112119
data = {
120+
'player1_username': 'player1',
113121
'player1_id': 1,
122+
'player2_username': 'player2',
114123
'player2_id': 2,
115124
'winner_id': 1,
116125
'start_time': '2024-07-03T12:00:00Z',
@@ -119,13 +128,11 @@ def test_primary_key_increment(api_client):
119128
response = api_client.post('/game-history/', data, format='json')
120129
assert response.status_code == 201
121130

122-
# Check the count after insertion
123131
new_count = GameHistory.objects.count()
124132
assert new_count == initial_count + 1
125133

126-
# Get the latest entry and check the primary key
127134
latest_entry = GameHistory.objects.latest('game_id')
128-
print(latest_entry.game_id) # This will print the latest primary key value
135+
print(latest_entry.game_id)
129136

130137
@pytest.mark.django_db
131138
def test_create_game_stat(api_client):
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
2-
from rest_framework import serializers
3-
from .models import UserTokens
42
import asyncio
53

64
class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
@@ -10,20 +8,15 @@ def get_token(cls, user) -> dict:
108
"""
119
Get token method to generate tokens for the user.
1210
13-
This method overrides the get_token method of TokenObtainPairSerializer to generate tokens for the user.
11+
This method overrides the get_token method of TokenObtainPairSerializer to generate tokens for the user.
1412
It generates the tokens for the user and returns the tokens.
1513
1614
Args:
1715
user: The user object.
18-
16+
1917
Returns:
2018
dict: The dictionary containing the tokens.
2119
"""
2220
token = super().get_token(user)
2321
token["custom_claims"] = {"username": user.username, "password": user.password}
2422
return token
25-
26-
class UserTokenModelSerializer(serializers.ModelSerializer):
27-
class Meta:
28-
model = UserTokens
29-
fields = "__all__"

Diff for: Backend/token_service/token_service/token_service/settings.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,8 @@
5959
SIMPLE_JWT = {
6060
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
6161
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
62-
"ROTATE_REFRESH_TOKENS": False, # If True, refresh tokens will rotate, meaning that a new token is returned with each request to the refresh endpoint. for example, if a user is logged in on multiple devices, rotating refresh tokens will cause all devices to be logged out when the user logs out on one device.
63-
"BLACKLIST_AFTER_ROTATION": True, # If True, the refresh token will be blacklisted after it is used to obtain a new access token. This means that if a refresh token is stolen, it can only be used once to obtain a new access token. This is useful if rotating refresh tokens is enabled, but can cause problems if a refresh token is shared between multiple clients.
62+
"ROTATE_REFRESH_TOKENS": False,
63+
"BLACKLIST_AFTER_ROTATION": True,
6464
"AUTH_HEADER_TYPES": ("Bearer",),
6565
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
6666
"TOKEN_OBTAIN_SERIALIZER": "token_app.serializers.CustomTokenObtainPairSerializer"

Diff for: Backend/user_service/user_service/user_app/rabbitmq_utils.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import pika
33
from django.conf import settings
44

5-
# Singleton pattern for managing RabbitMQ connection
5+
66
class RabbitMQManager:
77
_connection = None
88

Diff for: Dockerfile

-27
This file was deleted.

Diff for: Dockerfile.lint

+7-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
11
FROM alpine:3.20
22

33
# Install Python and pip
4-
RUN apk add --no-cache python3 py3-pip && \
5-
python3 -m ensurepip && \
6-
ln -sf python3 /usr/bin/python
4+
RUN apk add --no-cache python3 py3-pip
75

8-
ENV PYTHONDONTWRITEBYTECODE 1
9-
ENV PYTHONUNBUFFERED 1
6+
# Create and activate virtual environment
7+
RUN python3 -m venv /venv
108

9+
# Copy requirements and install within virtual environment
1110
COPY ./requirements.txt /requirements.txt
12-
RUN python -m pip install --upgrade pip
13-
RUN pip install setuptools==58.0.4 wheel
14-
RUN pip install flake8
11+
RUN /venv/bin/pip install --no-cache-dir -r /requirements.txt
12+
RUN /venv/bin/pip install --no-cache-dir flake8
1513

1614
WORKDIR /app
1715

@@ -22,4 +20,4 @@ RUN addgroup -S www-data && adduser -S www-data -G www-data && \
2220

2321
USER www-data
2422

25-
CMD ["flake8", "."]
23+
CMD ["/venv/bin/flake8", "."]

Diff for: Dockerfile.publish

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
FROM alpine:3.20
22

33
# Install Python and pip
4-
RUN apk add --no-cache python3 py3-pip && \
5-
python3 -m ensurepip && \
6-
ln -sf python3 /usr/bin/python
4+
RUN apk add --no-cache python3 py3-pip
75

8-
ENV PYTHONDONTWRITEBYTECODE 1
9-
ENV PYTHONUNBUFFERED 1
6+
# Create and activate virtual environment
7+
RUN python3 -m venv /venv
108

9+
# Copy requirements and install within virtual environment
1110
COPY ./requirements.txt /requirements.txt
12-
RUN python -m pip install --upgrade pip
13-
RUN pip install setuptools==58.0.4 wheel
14-
RUN pip install -r /requirements.txt
11+
RUN /venv/bin/pip install --no-cache-dir -r /requirements.txt
1512

1613
WORKDIR /app
1714

@@ -24,4 +21,4 @@ USER www-data
2421

2522
EXPOSE 8000
2623

27-
CMD ["python", "manage.py", "runserver", "0.0.0.0:8000"]
24+
CMD ["/venv/bin/python", "manage.py", "runserver", "0.0.0.0:8000"]

Diff for: Dockerfile.test

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,14 @@
11
FROM alpine:3.20
22

33
# Install Python and pip
4-
RUN apk add --no-cache python3 py3-pip && \
5-
python3 -m ensurepip && \
6-
ln -sf python3 /usr/bin/python
4+
RUN apk add --no-cache python3 py3-pip
75

8-
ENV PYTHONDONTWRITEBYTECODE 1
9-
ENV PYTHONUNBUFFERED 1
6+
# Create and activate virtual environment
7+
RUN python3 -m venv /venv
108

9+
# Copy requirements and install within virtual environment
1110
COPY ./requirements.txt /requirements.txt
12-
RUN python -m pip install --upgrade pip
13-
RUN pip install setuptools==58.0.4 wheel
14-
RUN pip install -r /requirements.txt
11+
RUN /venv/bin/pip install --no-cache-dir -r /requirements.txt
1512

1613
WORKDIR /app
1714

@@ -22,4 +19,4 @@ RUN addgroup -S www-data && adduser -S www-data -G www-data && \
2219

2320
USER www-data
2421

25-
CMD ["pytest", "--maxfail=1", "--disable-warnings"]
22+
CMD ["/venv/bin/pytest", "--maxfail=1", "--disable-warnings"]

0 commit comments

Comments
 (0)