ECM3408 Enterprise Computing Continuous Assessment 2024-25 Notes

Design (20%)

  • Effectiveness (10%):
    • The assessment mentions four microservices: "addTrack", "deleteTrack", "listTracks", and "checkFragment".
    • These microservices, when combined, should implement the four user stories (S1-S4) of Shamzam.
    • The provided microservices appear to have the necessary functionality to implement the user stories. (10/10)
  • Elegance (10%):
    • Elegance refers to the cohesiveness and loose coupling of the microservices.
    • "addTrack", "deleteTrack", and "listTracks" are coupled due to their shared database.
    • The "checkFragment" service lacks cohesion as it handles both fragment recognition and database lookup, which should ideally be separated. (4/10)

Implementation (60%)

  • Requirements:
    • The microservices should be implemented using Python modules.
    • Implement the REST API that each endpoint provides
    • REST API implementation using Python modules.
    • SQLite database for storage.
    • Audd.io for audio recognition.
  • Clarity (30%):
    • The assessment emphasizes the importance of well-structured programs with appropriate use of statements, expressions, and functions.
    • The submitted code appears to be a monolithic system, where everything runs as a single Flask app on a single port (3000).
    • This monolith needs to be understood, modified, and deployed as a whole, and a failure in any part affects the entire system.
    • The 120-line program is hard to understand and does not align with the assessment's microservices-oriented goal. (10/30)
  • Correctness (30%):
    • The implementation faces a usability problem: inability to update and record corrections easily.
    • Not a fully RESTful design: The catalogue implements a Store, rather than a Collection.
    • Addition and update should be done with PUT rather than POST.
    • The right verb (e.g., "DELETE") is used but operation name is pointlessly written in the URL (e.g. “/deleteTrack”).
    • Track resource name should appear in the URL and, in the case of addition, in a JSON object.
    • Incorrect response code: A successful deletion should return 204 No Content.
    • API keys should not be included in the source code. (10/30)

Testing (20%)

  • Coverage (20%):
    • Unit tests should cover both "happy paths" (successful operations) and up to three "unhappy paths" (error scenarios).
    • After adding to the catalogue database, verify the record was correctly added by reading the database.
    • After a delete operation, confirm the record is gone by reading the database.
    • Relying solely on response codes and JSON messages is insufficient. (14/20)

Appendix A: A Possible Design

Tracks Microservice

  • Allows creation and updating of music tracks.
  • Creating Tracks (Figure 1):
    • Method: PUT /tracks/id
    • Request Body: JSON object with id (string) and audio (Base64 encoded WAV file).
    • Successful Responses: 201 Created, 204 No Content.
    • Unsuccessful Responses: 400 Bad Request, 500 Internal Server Error.
    • No other responses are possible.
    • The format is the one to be used for database storage.
  • Reading Tracks (Figure 2):
    • Method: GET /tracks/id
    • Successful Response: 200 OK with a JSON object containing id (string) and audio (Base64 encoded WAV file).
    • Unsuccessful Responses: 404 Not Found, 500 Internal Server Error.
    • No other responses are possible.
  • Listing Tracks (Figure 3):
    • Method: GET /tracks
    • Successful Response: 200 OK with a list of strings (track IDs).
    • No other responses are possible.
  • Deleting Tracks (Figure 4):
    • Method: DELETE /tracks/id
    • Successful Response: 204 No Content.
    • Unsuccessful Responses: 404 Not Found, 500 Internal Server Error.
    • No other responses are possible.

Recognize Microservice

  • Allows recognition of music fragments.
  • Recognizing Tracks (Figure 5):
    • Method: POST /recognize
    • Request Body: JSON object with audio (Base64 encoded WAV file fragment).
    • Successful Response: 200 OK with a JSON object containing id (string) of the recognized track.
    • Unsuccessful Responses: 400 Bad Request, 404 Not Found, 500 Internal Server Error.
    • No other responses are possible.

Shamzam Microservice

  • Allows retrieval of music tracks using fragments.
  • Retrieving Tracks (Figure 6):
    • Method: POST /shamzam
    • Request Body: JSON object with audio (Base64 encoded WAV file fragment).
    • Successful Response: 200 OK with a JSON object containing id and audio (Base64 encoded WAV file) of the retrieved track.
    • Unsuccessful Responses: 400 Bad Request, 404 Not Found, 500 Internal Server Error.

Appendix B: A Possible Implementation

database.py

  • This file defines the database interactions.
  • It imports the repository module.
  • An instance of the Repository class is created with the table name "tracks".

recognize.py

  • This file implements the 'recognize' microservice using Flask.
  • It imports necessary libraries such as base64, os, requests, and Flask components.
  • It retrieves the Audd.io API key from environment variables.
  • /recognize Endpoint:
    • This endpoint receives a POST request with a JSON payload containing an "audio" property.
    • It decodes the Base64 encoded audio fragment.
    • It sends a request to the Audd.io API for recognition.
    • If the Audd.io API returns a successful response (status code 200):
      • It calls the unravel function to process the JSON response.
      • If the Audd.io API returns other status codes, it returns a 500 Internal Server Error.
    • If the audio is missing, it returns a 400 Bad Request error.
  • unravel Function:
    • This function processes the JSON response from Audd.io.
    • If the status is "success" and a result is found, it returns a JSON object containing the track title (ID) and a 200 OK status code.
    • If no result is found, it returns a 404 Not Found error.
    • If the status is not "success", it returns a 400 Bad Request error.
  • The app runs on localhost and port 3001.

repository.py

  • This file defines the Repository class for database interactions.
  • [Repository Class]
    • __init__(self, table): Initializes the repository with a table name and creates the database file.
    • make(self): Creates the database table if it doesn't exist. The table has columns id (TEXT PRIMARY KEY) and audio (TEXT).
    • clear(self): Deletes all entries from the table.
    • insert(self, js): Inserts a new record into the table with id and audio from the provided JSON object.
    • update(self, js): Updates the audio field of an existing record in the table based on the id from the JSON object.
    • lookup(self, id): Retrieves a record from the table based on the provided id. Returns a dictionary with id and audio if found, otherwise None.
    • delete(self, id): Deletes a record from the table based on the provided id. Returns True if the deletion was successful, False otherwise.
    • list(self): Retrieves all records from the table and returns a list of IDs.

shamzam.py

  • This file implements the 'shamzam' microservice using Flask.
  • It imports necessary libraries such as requests and Flask.
  • It defines the addresses for the tracks and recognize microservices.
  • /shamzam Endpoint:
    • This endpoint receives a POST request with a JSON payload.
    • It forwards the request to the recognize microservice.
    • If the recognize microservice returns a 200 OK status code:
      • It extracts the track ID from the response.
      • It sends a GET request to the tracks microservice to retrieve the full track information.
      • If the tracks microservice returns a 200 OK status code, it returns the track information with a 200 OK status code.
      • If the tracks microservice returns a 404 Not Found error, it returns a 404 Not Found error.
    • If the recognize microservice returns a 404 Not Found error, it returns a 404 Not Found error.
  • The app runs on localhost and port 3002.

tracks.py

  • This file implements the 'tracks' microservice using Flask.
  • It imports necessary libraries such as the database module and Flask components.
  • /tracks/ (PUT):
    • This endpoint handles PUT requests to create or update a track.
    • It retrieves the id and audio from the JSON payload.
    • If the id in the URL matches the id in the JSON payload:
      • If the track already exists (checked using database.db.lookup(id)):
        • It updates the track using database.db.update(js).
        • Returns 204 No Content on success, 500 Internal Server Error on failure.
      • If the track does not exist:
        • It inserts the track using database.db.insert(js).
        • Returns 201 Created on success, 500 Internal Server Error on failure.
      • If the IDs don't match or audio is missing, it returns a 400 Bad Request.
  • /tracks/ (GET):
    • This endpoint handles GET requests to retrieve a track by its ID.
    • It retrieves the track from the database using database.db.lookup(id).
    • If the track is found, it returns the track data with a 200 OK status.
    • If the track is not found, it returns a 404 Not Found error.
  • /tracks/ (DELETE):
    • This endpoint handles DELETE requests to delete a track by its ID.
    • If the track exists (checked using database.db.lookup(id)):
      • It deletes the track using database.db.delete(id).
      • Returns 204 No Content on success, 500 Internal Server Error on failure.
    • If the track does not exist, it returns a 404 Not Found error.
  • /tracks (GET):
    • This endpoint handles GET requests to list all tracks.
    • It retrieves the list of tracks from the database using database.db.list().
    • It returns the list of tracks with a 200 OK status.
  • The app runs on localhost and port 3000.

test-shamzam.py

  • This file contains end-to-end tests for the Shamzam application.
  • It uses the unittest framework.
  • It defines a Testing class that inherits from unittest.TestCase.
  • The tests cover adding tracks, removing tracks, listing tracks, and converting fragments to tracks, covering the four user stories.
  • Each test method does the following:
    • Clears the database.
    • Sets up the necessary data (track ID, audio content).
    • Sends HTTP requests to the microservices.
    • Asserts the status codes and response data.
  • Test 1: User Story 1 (Add Track to Catalogue):
    • Adds a track to the catalogue using a PUT request.
    • Verifies that the response status code is 201 (Created).
    • Retrieves the track using a GET request and asserts the status code is 200 (OK).
    • Asserts that the retrieved track's ID and audio match the original values.
  • Test 2: User Story 1 (Add Track to Catalogue - Update):
    • Adds a track to the catalogue using a PUT request.
    • Verifies that the response status code is 201 (Created).
    • Updates the same tack and assert that the response status code is 204 (No Content).
    • Retrieves the track using a GET request and asserts the status code is 200 (OK).
    • Asserts that the retrieved track's ID and audio match the original values.
  • Test 3: User Story 1 (Add Track to Catalogue - Bad Request):
    • Attempts to insert a track with missing ID and assert that the response status code is 400 (Bad Request).
  • Test 4: User Story 1 (Add Track to Catalogue - Bad Request):
    • Attempts to insert a track with missing auido and assert that the response status code is 400 (Bad Request).
  • Test 5: User Story 2 (Remove Track from Catalogue):
    • Adds a track to the catalogue.
    • Removes the track using a DELETE request.
    • Verifies that the response status code is 204 (No Content).
    • Attempts to retrieve the track using a GET request and asserts the status code is 404 (Not Found).
  • Test 6: User Story 2 (Remove Track from Catalogue - Not Found):
    • Attempts to delete a track that does not exist and ensure the response status code is 404 (Not Found).
  • Test 7: User Story 3 (List Tracks in Catalogue):
    • Adds four tracks to the catalogue.
    • Retrieves the list of tracks using a GET request.
    • Verifies that the response status code is 200 (OK).
    • Asserts that all four track IDs are present in the list.
  • Test 8: User Story 4 (Convert Fragment to Track):
    • Adds a track to the catalogue.
    • Converts a fragment to a track using a POST request.
    • Verifies that the response status code is 200 (OK).
    • Asserts that the retrieved track audio matches the original track audio.