Differences

This shows you the differences between two versions of the page.

Link to this comparison view

asc:teme:tema1 [2021/03/18 16:28]
giorgiana.vlasceanu [Tema 1 - Marketplace]
asc:teme:tema1 [2024/04/06 18:12] (current)
eduard.staniloiu [Precizări încărcare]
Line 1: Line 1:
-====== Tema 1 - Marketplace ​====== +====== Tema 1 - Le Stats Sportif ​======
  
 <note important> ​   ​ <note important> ​   ​
-  * **Deadline:​** ​aprilie ​2021, ora 23:55. Primiți un bonus de 10% pentru trimiterea temei cu zile înaintea ​acestui termen, adică înainte de aprilie ​2021, ora 23:55. +  * **Deadline:​** ​<​del>​7 aprilie</​del>​ 14 aprilie ​2024, ora 23:55. Primiți un bonus de 10% pentru trimiterea temei cu zile înaintea ​datei de 7 aprilie, adică înainte de <​del>​5</​del>​ 10 aprilie ​2024, ora 23:55. 
-    * **Deadline hard:​** ​10 aprilie ​2020, ora 23:55. Veți primi o depunctare de 10% din punctajul maxim al temei pentru fiecare zi de întârziere,​ până la maxim 7 zile, adică până pe 10 aprilie ​2021, ora 23:55. +    ​<del>* **Deadline hard:​** ​14 aprilie ​2024, ora 23:55. Veți primi o depunctare de 10% din punctajul maxim al temei pentru fiecare zi de întârziere,​ până la maxim 7 zile, adică până pe 14 aprilie ​2024, ora 23:55.</​del>​ 
-    * **Responsabili:​** [[ barbutudorantonio@gmail.com |Tudor Antonio Barbu]], [[ eduard.staniloiu@cs.pub.ro | Eduard Stăniloiu]],​ [[soareloredana97@gmail.com|Loredana Soare]], [[ giorgiana.vlasceanu@gmail.com | Giorgiana Vlăsceanu]], [[voichita.iancu@cs.pub.ro|Voichița Iancu]] +    * **Responsabili:​** [[ andreicatalin.ouatu@gmail.com | Andrei Ouatu]], [[andreitrifu.acs@gmail.com|Andrei Trifu]], [[ adumitrescu2708@stud.acs.upb.ro| Alexandra Dumitrescu]],​[[eduard.staniloiu@cs.pub.ro | Eduard Stăniloiu]],​ [[ radunichita99@gmail.com | Radu Nichita]], [[ioana.profeanu@gmail.com| ​Ioana Profeanu]], [[giorgiana.vlasceanu@gmail.com Giorgiana Vlăsceanu]]  
-    * **Autori:** [[LucaIstrate@gmail.com|Luca Istrate]], [[adriana.draghici@cs.pub.ro|Adriana Draghici]], [[soareloredana97@gmail.com|Loredana Soare]]+    * **Autori:** [[eduard.staniloiu@cs.pub.ro | Eduard Stăniloiu]], [[giorgiana.vlasceanu@gmail.com | Giorgiana Vlăsceanu]]
 </​note>​ </​note>​
  
 <note tip> <note tip>
-  * Dată publicare: ​19 martie +  * Dată publicare: ​25 martie 
-  * Dată actualizare enunț19 martie+  * Actualizare deadline2 aprilie
 </​note>​ </​note>​
- 
  
 ===== Scopul temei ===== ===== Scopul temei =====
  
   * Utilizarea eficientă a elementelor de sincronizare studiate la laborator   * Utilizarea eficientă a elementelor de sincronizare studiate la laborator
-  * Implementarea unei aplicații concurente utilizând o problemă clasică (Multi Producer, Multi Consumer+  * Implementarea unei aplicații concurente utilizând o problemă clasică (client - server
-  * Aprofundarea anumitor elemente din Python (clase, elemente de sintaxă, ​thread-uri, sincronizare,​ precum și folosirea modulelor Python pentru lucrul cu thread-uri)+  * Aprofundarea anumitor elemente din Python (clase, elemente de sintaxă, ​threaduri, sincronizare,​ precum și folosirea modulelor Python pentru lucrul cu threaduri)
  
 ===== Enunț ===== ===== Enunț =====
  
-În cadrul acestei teme veți avea de implementat un Marketplace prin intermediul căruia mai mulți ​**producători** își vor oferi produsele spre vânzare, iar mai mulți **cumpărători** vor achiziționa produsele puse la dispoziție.+În cadrul acestei teme veți avea de implementat un server python care va gestiona o serie de requesturi plecând de la un set de date în format ​*csv(comma separated values). 
 +Serverul va oferi statistici pe baza datelor din csv.
  
-=== Marketplace ​===+=== Setul de date ===
  
-Marketplace-ul este unul destul ​de simplucu **două tipuri de produse (ceai și cafea)** ce vor fi comercializate ​de către ​producătoriAcesta va fi intermediarul dintre producători și consumatori,​ prin el realizându-se achiziția de produse: ​ +[[https://​catalog.data.gov/​dataset/​nutrition-physical-activity-and-obesity-behavioral-risk-factor-surveillance-system|Setul ​de date]] conține informații despre nutrițieactivitatea fizică și obezitate în Statele Unite ale Americii în perioada 2011 - 2022. 
-producătorul ​(producerva produce o anumită cantitate de produse de un anumit tip / mai multe tipuri +Datele au fost colectate ​de către ​U.S. Department of Health & Human Services
-cumpătorul (consumer) va cumpăra o anumită cantitate ​de produse de un tip / de mai multe tipuri. De asemenea, Marketplace-ul va pune la dispoziția fiecărui cumpărător câte un **coș de produse ​(cart)** (acesta va fi folosit pentru rezervarea produselor care se doresc ​fi cumpărate).+Informațiile sunt colectate per stat american ​(ex. California, Utah, New Yorkși spund următorului **set de întrebări**
 +  * '​Percent of adults who engage in no leisure-time physical activity'​ 
 +  * '​Percent of adults aged 18 years and older who have obesity'​ 
 +  * '​Percent of adults aged 18 years and older who have an overweight classification'​ 
 +  * '​Percent of adults who achieve at least 300 minutes a week of moderate-intensity aerobic physical activity or 150 minutes a week of vigorous-intensity aerobic activity ​(or an equivalent combination)
 +  ​'​Percent of adults who achieve at least 150 minutes a week of moderate-intensity aerobic physical activity or 75 minutes a week of vigorous-intensity aerobic physical activity and engage in muscle-strengthening activities on 2 or more days a week'​ 
 +  ​'​Percent of adults who achieve at least 150 minutes ​week of moderate-intensity aerobic physical activity or 75 minutes a week of vigorous-intensity aerobic activity (or an equivalent combination)
 +  * '​Percent of adults who engage in muscle-strengthening activities on 2 or more days a week'​ 
 +  * '​Percent of adults who report consuming fruit less than one time daily'​ 
 +  * '​Percent of adults who report consuming vegetables less than one time daily'
  
-=== Producător ===+Valorile pe care le veți folosi în calculul diverselor statistici la care răspunde aplicația voastră se găsesc în coloana **Data_Value**.
  
-Vor exista mai mulți producători ce vor produce obiectele ​de tip cafea / ceai. Fiecare produs va fi furnizat într-o anumită cantitate. Un producător poate produce atât obiecte de tip cafea, cât și de tip ceai.+===== Detalii ​de implementare =====
  
-=== Consumator ===+Aplicația server pe care o dezvoltați este una multi-threaded. 
 +Atunci când serverul este pornit, trebuie să încărcați fișierul csv și să extrageți informațiile din el a.î. să puteți calcula statisticile cerute la nivel de request.
  
-În momentul în care un client își dorește să cumpere anumite produse dintr-un magazinacesta va avea nevoie ​de un coș de cumpărături pe care să îl folosească în scopul rezervării acestora. Astfel, de fiecare dată când un client își începe cumpărăturile,​ acesta ​va primi din partea Marketplace-ului ​un coș de cumpărăturicăruia îi va fi asociat un //id//. Clientul poate: +Întrucât procesarea datelor din csv poate dura mai mult timpmodelul implementat ​de către server va fi următorul: 
-  * adăuga produse în coș => produsele respective devin indisponibile pentru ceilalțclienți + * un endpoit (ex. '/​api/​states_mean'​) ​care primește requestul ​și va întoarce clientului ​un **job_id** (ex. "​job_id_1"​"​job_id_2",​ ..., "​job_id_n"​) 
-  * șterge produse din coș => produsele respective devin disponibile pentru ceilalți clienți + * endpointul '/api/get_results/job_id'​ care va verifica dacă job_id-ul este valid, rezultatul calculului este gata sau nu și va returna un răspuns corespunzător (detalii mai jos)
-  * plasa o comandă+
  
-===== Descrierea implementării =====+=== Mecanica unui request ​===
  
 +Asociază un job_id requestului,​ pune jobul (closure care încalsulează unitatea de lucru) într-o coadă de joburi care este procesată de către un **Thread pool**, incrementează job_id-ul intern și returnează clientului job_id-ul asociat.
  
-Marketplace-ul ce va trebui implementat ​va simula problema **Multi Producer Multi Consumer ​(MPMC)**. +Un thread ​va prelua un job din coada de joburi, ​va efectua operația asociată ​(ceea ce a fost capturat de către closure) și va scrie rezultatul calculului într-un ​fișier cu numele job_id-ului ​în directorul **results/​**.
-Pentru rezolvarea acestei teme va trebui să completați clasele ''​Marketplace,​ Producer'', ​și ''​Consumer''​ (clase ce vor fi documentate ​în {{:​asc:​teme:​tema1:​tema1-skel.zip|schelet}}) cu o implementare corectă a metodelor deja definite.+
  
-Rezolvarea temei va fi concentrată preponderent ​pe metodele clasei //​Marketplace//,​ metode ce vor fi apelate atât de producător, cât șde cumpărător în clasele aferente ale acestora.+=== Requesturile ​pe care trebuie să le implementațsunt ===
  
-Operația efectuată de către producător este cea de //publicare a produselor sale//. Implementarea metodei ''​publish''​ va fi făcută în clasa //​Marketplace//​.+== /api/states_mean ==
  
-Vor exista doua tipuri de operații pe care clientul le poate efectua asupra coșului de cumpărături: +Primește o întrebare (din **setul ​de întrebări** de mai sus) și calculează media valorilor înregistrate (**Data_Value**) din intervalul total de timp (2011 - 2022) pentru fiecare stat, și sortează crescător după medie.
-  ​''​add_to_cart''​ => adaugă produse într-o anumită cantitate în coș +
-  ​''​remove_from_cart''​ => șterge din coș o anumită cantitate ​de produse +
-Ambele metode ​(''​add_to_cart'' ​și ''​remove_from_cart''​) vor trebui implementate în clasa //​Marketplace//​.+
  
-În momentul în care un consumator adaugă un produs în coșul pentru cumpărături,​ produsul respectiv va deveni indisponibil pentru ceilalți clienți ai Marketplace-ului. Clientul își va putea plasa comanda prin apelarea metodei ''​place_order''​ (din clasa Marketplace). +== /​api/​state_mean ==
-În cazul în care un produs este eliminat din coșul pentru cumpărături,​ acesta devine disponibil pentru ceilalți clienți ai Marketplace-ului.+
  
-Funcționalitatea clasei ''​Producer''​ este să+Primește o întrebare (din **setul de întrebări** de mai sus) și un stat, și calculează media valorilor înregistrate (**Data_Value**) din intervalul total de timp (2011 - 2022).
-  ​furnizeze produselor pe care producătorul le pune la dispoziție+
  
 +== /api/best5 ==
  
-<note important>''​Producer''​ produce secvențial numărul de produse ​și tipul din cadrul fișierului ​de intrare ​și așteaptă după realizarea fiecărui produs un număr de secunde specificat. Informațiile se preiau ​din fișierul ​de intrare și are următorul format pentru produse''​["​id",​ cantitate, ​timp-așteptare]''​.</​note> ​+Primește o întrebare (din **setul ​de întrebări** de mai sus) și calculează media valorilor înregistrate (**Data_Value**) ​din intervalul total de timp (2011 2022) și întoarce primele 5 state.
  
 +== /api/worst5 ==
  
-Funcționalitatea clasei ''​Consumer''​ este să: +Primește o întrebare (din **setul de întrebări** de mai sus) și calculează media valorilor înregistrate (**Data_Value**) ​din intervalul total de timp (2011 - 2022) șîntoarce ultimele 5 state.
-  ​primească id-ului coșului ​de cumpărături +
-  ​adauge / elimine ​din coșul ​de cumpărături anumite cantitățde produse +
-  * plaseze comenzi+
  
-Modulul **Product** conține reprezentările claselor **Coffee** și **Tea**.+<note tip> 
 +În funcție de întrebare, primele state pot să aibă fie cel mai mic sau cel mai mare scor. 
 +De exemplu, pentru întrebarea:​ "​Percent of adults who engage in no leisure-time physical activity",​ primele state (best) vor avea scorurile cele mai mici, iar worst vor avea scorurile cele mai mari. 
 +Pentru întrebarea:​ "​Percent of adults who engage in muscle-strengthening activities on 2 or more days a week", primele state (best) vor avea scorurile cele mai mari, iar worst vor avea scorurile cele mai mici. 
 +</​note>​
  
-Marketplace-ul limitează numărul de produse ce pot fi publicate de către un producător. În momentul în care s-a atins limita, producătorul nu mai poate publica altele până nu sunt cumpărate. El va reîncerca să publice după un timp definit în fișierul de test.+== /​api/​global_mean == 
  
-Dacă un cumpărător nu găsește un produs în marketplace,​ el va încerca ​mai târziu, după un timp definit în fișierul ​de test.+Primește o întrebare (din **setul de întrebări** de mai sus) și calculează media valorilor înregistrate (**Data_Value**) din intervalul total de timp (2011 - 2022) din întregul set de date.
  
-<note important>​Se consideră timp de așteptare după: +== /api/​diff_from_mean ==
-  * adăugarea unui produs +
-  * semnalizarea că nu se găsește un produs +
-  * semnalizarea faptul că este plină coada asociată producătorului +
-</note>+
  
-==== Formatul Testelor ====+Primește o întrebare (din **setul de întrebări** de mai sus) și calculează diferența dintre global_mean și state_mean pentru toate statele.
  
 +== /​api/​state_diff_from_mean ==
  
-Testarea se va face cu ajutorul a  două tipuri de fișiere, cele de input și cele de output ​({id}.in și {id}.out), primul fiind în format JSON. Fișierul ​**{id}.in** va reprezenta fișierul ​de intrare ​și va conține configurările necesare pentru fiecare clasă în parteiar fișierul **{id}.out** va reprezenta fișierul de ieșire prin intermediul căruia se va verifica corectitudinea implementării temei.+Primește o întrebare ​(din **setul de întrebări** de mai sus) și un stat, și calculează diferența dintre global_mean ​și state_mean pentru statul respectiv.
  
-Fișierele de input vor fi fișiere JSON ce vor conține următoarele chei: +== /​api/​mean_by_category ==
-  * marketplace +
-  * products +
-  * producers +
-  * consumers+
  
-Exemplu conținut fișier de intrare ​și fișierul corespunzător de ieșire+Primește o întrebare (din **setul ​de întrebări** de mai sus) și calculează valoarea medie pentru fiecare segment (**Stratification1**) din categoriile (**StratificationCategory1**) fiecărui stat. 
-<spoiler Click pentru ​exemplu> + 
-<​code ​json>+== /​api/​state_mean_by_category == 
 + 
 +Primește o întrebare (din **setul de întrebări** de mai sus) și un stat, și calculează valoarea medie pentru fiecare segment (**Stratification1**) din categoriile (**StratificationCategory1**). 
 + 
 +== /​api/​graceful_shutdown == 
 + 
 +Răspunde la un apel de tipul GET și va duce la notificarea Thread Poolului despre încheierea procesării. 
 +Scopul acesteia este de a închide aplicația într-un mod gracefulnu se mai acceptă requesturi noi, se termină de procesat requesturile înregistrate până în acel moment (drain mode) și apoi aplicația poate fi oprită. 
 + 
 +== /api/jobs == 
 + 
 +Răspunde la un apel de tipul GET cu un JSON care conține toate JOB_ID-urile de până la acel moment și statusul lor. 
 +De exemplu: 
 +<​code>​
 { {
-   "​products":​ { +  "status": "done
-       "​id1":​ { +  "data": [ 
-           "​product_type":​ "​Coffee",​ +    { "job_id_1": "done"}, 
-           "​name":​ "​Arabica",​ +    { "job_id_2": "running"}, 
-           "​price":​ 10, +    { "job_id_3": "running"} 
-           "​acidity":​ 5.1, +  ]
-           "​roast_level":​ "​medium"​ +
-       }, +
-       "​id2":​ { +
-           "​product_type":​ "​Tea",​ +
-           "​name":​ "Earl Grey",​ +
-           "​price":​ 10, +
-           "​type":​ "​Green"​ +
-       } +
-   }, +
-   "consumers": ​+
-       { +
-           "name": "​cons1",​ +
-           "​retry_wait_time":​ 0.1, +
-           ​"carts": [ +
-               [ +
-                   { "type": "add", "​prod":​ "​id1",​ "​qty":​ 2 }, +
-                   ​{ "type": "remove", "​prod":​ "​id1",​ "​qty":​ 1 } +
-               ]+
-               [ +
-                   { "type": "add", "​prod":​ "​id2",​ "​qty":​ 3 +
-               ​] +
-           ] +
-       } +
-   ], +
-   "​producers":​ [ +
-       { +
-           "​name":​ "​prod1",​ +
-           "​products":​ [ +
-               [ "​id1",​ 1, 0.1 ], +
-               [ "​id2",​ 1, 0.1 ] +
-           ], +
-           "​republish_wait_time":​ 0.2 +
-       }, +
-       { +
-           "​name":​ "​prod2",​ +
-           "​products":​ [ +
-               [ "​id2",​ 1, 0.2 ] +
-           ], +
-           "​republish_wait_time":​ 0.2 +
-       } +
-   ], +
-   "​marketplace":​ { +
-       "​queue_size":​ 8 +
-   }+
 } }
 </​code>​ </​code>​
-  
-Conținut fișier de ieșire: 
  
 +== /​api/​num_jobs == 
 +
 +Răspunde la un apel de tipul GET cu numărul joburilor rămase de procesat.
 +După un /​api/​graceful_shutdown și o perioadă de timp, aceasta ar trebui să întoarcă valoarea 0, semnalând astfel că serverul flask poate fi oprit.
 +
 +== /​api/​get_results/<​job_id>​ ==
 +
 +Răspunde la un apel de tipul GET (job_id-ul este parte din URL).
 +Acesta verifică dacă job_id-ul primit este valid și răspunde cu un JSON corespunzător,​ după cum urmează:
 +
 +1. JOB_ID-ul este invalid
 <​code>​ <​code>​
-cons1 bought Coffee(name='​Arabica',​ price=10, acidity=5.1,​ roast_level='​medium'​) +{ 
-cons1 bought Tea(name='​Earl Grey'price=10, type='​Black'​) +  "​status":​ "​error"​
-cons1 bought Tea(name='​Earl Grey', price=10, type='​Black'​) +  "​reason":​ "​Invalid job_id"​ 
-cons1 bought Tea(name='​Earl Grey', price=10, type='​Black'​)+}
 </​code>​ </​code>​
  
 +2. JOB_ID-ul este valid, dar rezultatul procesării nu este gata
 +<​code>​
 +{
 +  "​status":​ "​running",​
 +}
 +</​code>​
 +
 +3. JOB_ID-ul este valid și rezultatul procesării este gata
 +<​code>​
 +{
 +  "​status":​ "​done",​
 +  "​data":​ <​JSON_REZULTAT_PROCESARE>​
 +}
 +</​code>​
 +
 +=== Server ===
 +
 +Implementarea serverului se face folosind framework-ul **flask** și va extinde scheletul de cod oferit.
 +Mai multe detalii despre Flask găsiți mai jos.
 +Deasemeni, un tutorial extensiv (pe care vi-l recomandăm) este [[https://​blog.miguelgrinberg.com/​post/​the-flask-mega-tutorial-part-i-hello-world|The flask mega tutorial]].
 +
 +Python Flask este un micro-framework web open-source care permite dezvoltatorilor să creeze aplicații web ușor și rapid, folosind limbajul de programare Python.
 +Flask este minimalist și flexibil, oferind un set de instrumente de bază pentru crearea unei aplicații web, cum ar fi rutele URL, gestionarea cererilor și a sesiunilor, șablonarea și gestionarea cookie-urilor.
 +Cu Flask, dezvoltatorii pot construi rapid API-uri sau aplicații web de dimensiuni mici și medii.
 +
 +== Instalare și activarea mediului de lucru ==
 +
 +Pentru a instala Flask, creați-vă un mediu virtual (pentru a nu instala pachete global, pe sistem) folosind comanda
 +<​code>​
 +$ python -m venv venv
 +</​code>​
 +
 +Activați mediul virtual
 +<​code>​
 +$ source venv/​bin/​activate
 +</​code>​
 +
 +Și instalați pachetele din fișierul **requirements.txt**
 +<​code>​
 +$ python -m pip install -r requirements.txt
 +</​code>​
 +
 +Pașii de creare a mediului virtual și de instalare a pachetelor se regăsesc în fișierul Makefile.
 +Astfel, pentru a vă crea spațiul de lucru, rulați următoarele comenzi în interpretorul vostru de comenzi (verificat în ''​bash''​ și ''​zsh''​)
 +<​code>​
 +make create_venv
 +source venv/​bin/​activate
 +make install
 +</​code>​
 +
 +== Quickstart ==
 +
 +O rută în cadrul unei aplicații web, cum ar fi în Flask, reprezintă un URL (Uniform Resource Locator) specific către care aplicația web va răspunde cu un anumit conținut sau funcționalitate.
 +Atunci când un client (de obicei un browser web) face o cerere către serverul web care găzduiește aplicația Flask, ruta determină ce cod va fi executat și ce răspuns va fi returnat clientului.
 +În Flask, rutele sunt definite folosind decoratori care leagă funcții Python de URL-uri specifice, permitând astfel aplicației să răspundă în mod dinamic la cereri (requesturi).
 +
 +În Flask, puteți defini o rută care răspunde la un apel de tip **GET** folosind decoratorul **@app.route()** și specificând metoda *HTTP* (**methods=['​GET'​]**).
 +Pentru a răspunde la un apel de tipul **POST** (apel folosit pentru a trimite date de către un client către server) folosim același decorator și specificăm **methods=['​POST'​]**.
 +De exemplu:
 +
 +<​code>​
 +from flask import request
 +
 +@app.route('/',​ methods=['​GET'​])
 +def index():
 +    return '​Aceasta este o rută care răspunde la un apel de tip GET'
 +
 +@app.route('/​post',​ methods=['​POST'​])
 +def post_route():​
 +    data = request.json ​ # Se obțin datele JSON trimise prin POST
 +    return '​Aceasta este o rută care răspunde la un apel de tip POST'
 +</​code>​
 +
 +În cazul API-urilor este un best practice ca datele returnate să fie în format JSON, pentru a fi ușor de prelucrat de către alte servicii în mod programatic.
 +Pentru a returna un obiect JSON în Flask, vom folosi helperul **jsonify()** ca în exemplul de mai jos:
 +
 +<​code>​
 +from flask import request, jsonify
 +
 +@webserver.route('/​api/​post_endpoint',​ methods=['​POST'​])
 +def post_endpoint():​
 +    if request.method == '​POST':​
 +        # Presupunem că metoda conține date JSON
 +        data = request.json
 +        print(f"​got data in post {data}"​)
 +        ​
 +        # Procesăm datele primite
 +        # Pentru exemplu, vom returna datele primite
 +        response = {"​message":​ "​Received data successfully",​ "​data":​ data}
 +        return jsonify(response)
 +    else:
 +        # Nu acceptăm o altă metodă
 +        return jsonify({"​error":​ "​Method not allowed"​}),​ 405
 +</​code>​
 +
 +=== Structura input-ului și a output-ului ===
 +
 +Interacțiunea cu serverul se va face pe bază de mesaje JSON, după cum este descris mai jos.
 +Vă recomandăm să vă uitați în suita de teste, în directoarele input și output pentru a vedea informațiile mult mai detaliat.
 +
 +== Input ==
 +
 +Un input pentru un request care primește doar o întrebare în următorul format:
 +<​code>​
 +{
 +  "​question":​ "​Percent of adults aged 18 years and older who have an overweight classification"​
 +}
 +</​code>​
 +
 +Unul care așteaptă o întrebare și un stat are următorul format:
 +<​code>​
 +{
 +  "​question":​ "​Percent of adults who engage in no leisure-time physical activity",​
 +  "​state":​ "South Carolina"​
 +}
 +</​code>​
 +
 +== Output ==
 +
 +Un răspuns JSON va avea mereu structura:
 +<​code>​
 +{
 +  "​status":​ "​done",​
 +  "​data":​ <​JSON_REZULTAT_PROCESARE>​
 +}
 +</​code>​
 +
 +**JSON_REZULTAT_PROCESARE** este un obiect JSON așa cum se regăsește în directorul output, pentru fiecare endpoint din directorul tests.
 +
 +===== Testare =====
 +
 +Testarea se va realiza folosind atât unitteste, cât și teste funcționale.
 +
 +==== Rularea testelor ====
 +
 +Pentru a rula testele, folosiți fișierul ''​Makefile''​.
 +Într-un shell 1) activați mediul virtual și 2) porniți serverul
 +<​code>​
 +source venv/​bin/​activate
 +make run_server
 +</​code>​
 +
 +Într-un alt shell 1) activați mediul virtual și 2) porniți checkerul
 +<​code>​
 +source venv/​bin/​activate
 +make run_tests
 +</​code>​
 +
 +<note important>​
 +Trebuie să vă asigurați că ați activat mediul virtual înainte de a rula comenzile din make.
 +<​code>​
 +source venv/​bin/​activate
 +</​code>​
 +
 +Dacă nu ați activat mediul virtual, ''​make''​ vă va arunca următoarea eroare (linia, ex 8, poate să difere).
 +<​code>​
 +Makefile:8: *** "You must activate your virtual environment. Exiting..."​. ​ Stop.
 +</​code>​
 +
 +</​note>​
 +
 +==== Unittesting ====
 +
 +Pentru testarea funcțiilor din **server** veți folosi modulul de [[https://​docs.python.org/​3/​library/​unittest.html | unittesting]] al limbajului Python.
 +
 +<spoiler Click pentru sumar despre unittesting>​
 +Pentru a defini un set de unitteste trebuie să vă definiți o clasă care moștenește clasa ''​unittest.TestCase''​
 +<code python demo_unittest.py>​
 +import unittest
 +
 +class TestStringMethods(unittest.TestCase):​
 +
 +    def test_upper(self):​
 +        self.assertEqual('​foo'​.upper(),​ '​FOO'​)
 +</​code>​
 +
 +Pentru a defini un test, numele metodei trebuie să înceapă cu prefixul ''​test_'',​ așa cum puteți observa în exemplul de mai sus: ''​test_upper''​.
 +Verificările din corpul metodei se fac folosind metodele ''​assert*'',​ în exemplul de mai sus a fost folosită metoda ''​assertEqual''​. O listă completă a metodelor de verificare disponibile este prezentată în [[https://​docs.python.org/​3/​library/​unittest.html#​assert-methods | documentație]].
 +
 +Pentru a rula testele, folosim subcomanda unittest:
 +<code bash>
 +$ python3 -m unittest demo_unittest.py
 +$ # puteti folosi optiunea -v pentru mai multe detalii
 +$ python3 -m unittest -v demo_unittest.py
 +</​code>​
 </​spoiler>​ </​spoiler>​
  
-<note warning>​Atât conținutul ​fișierului ​de intrarecât și conținutul fișierului de ieșire sunt descrise în [[https://​bitbucket.org/​ASC-admin/​asc/​src/​fc02748e1a08/​assignments/​1-marketplace/​skel/​test-gen/​README_TESTS.md| README]] </​note>​+Pentru a testa comportamentul definiți în fișierul ''​unittests/​TestWebserver.py''​ o clasă ​de testare numită ''​TestWebserver''​. 
 +Clasa ''​TestWebserver''​ va testa funcționalitatea tuturor rutelor definite de voi. 
 +Dacă definiți alte metodeva trebui să adăugați teste și pentru acestea.
  
-Pentru ​putea compara fișierele de ieșire obținute de voi cu cele de referința, scriptul ​de testare va ordona output-ul rezultat, întrucât avem de-a face cu multithreading.+Vă recomandăm să folosiți metoda [[https://​docs.python.org/​3/​library/​unittest.html#​unittest.TestCase.setUp | setUp]] pentru ​inițializa o instanță clasei testate și orice altceva ce vă ajută în testarea codului. 
 +Un exemplu ​de utilizare a metodei ''​setUp''​ este disponibil în [[https://​docs.python.org/​3/​library/​unittest.html#​organizing-test-code | documentație]].
  
 +===== Logging =====
  
-===== Precizări încărcare ​/ VMChecker ​=====+Vrem să utilizăm fișiere de logging în aplicațiile pe care le dezvoltăm pentru a putea urmări flowul acestora a.î. să ne ajute în procesul de debug. 
 + 
 +Folosind modulul de [[https://​docs.python.org/​3/​library/​logging.html | logging]], trebuie să implementați un fișier de log, numit "​webserver.log",​ în care veți urmări comportamentul serverului. 
 + 
 +În fișierul de log veți nota, folosind nivelul ''​info()'',​ toate intrările și ieșirile în/din rutele implementate. 
 +În cazul metodelor care au parametrii de intrare, informația afișată la intrarea în funcție va afișa și valorile parametrilor. 
 +Fișierul va fi implementat folosind [[https://​docs.python.org/​3/​library/​logging.handlers.html#​logging.handlers.RotatingFileHandler | RotatingFileHandler]]:​ astfel se poate specifica o dimensiune maximă a fișierului de log și un număr maxim de copii istorice. RotatingFileHandler ne permite să ținem un istoric al logurilor, fișierele fiind stocate sub forma "​file.log",​ "​file.log.1",​ "​file.log.2",​ ... "​file.log.max"​. 
 + 
 +Vă încurajăm să folosiți fișierul de log și pentru a înregistra [[https://​docs.python.org/​3/​library/​logging.html#​logging.Logger.error | erori]] detectate. 
 + 
 +În mod implicit, timestamp-ul logurilor folosește timpul mașinii pe care rulează aplicația (local time). Acest lucru nu este de dorit în practică deoarece nu putem compara loguri de pe mașini aflate în zone geografice diferite. Din acest motiv, timestampul este ținut în format UTC/GMT. 
 +Asigurați-vă că folosiți gmtime, și nu localtime. Pentru aceasta trebuie să folosiți metoda [[https://​docs.python.org/​3/​library/​logging.html#​logging.Formatter.formatTime | formatTime]].  
 + 
 +O descriere completă a cum puteți utiliza modului de logging este prezentă în categoria [[https://​docs.python.org/​3/​howto/​logging.html | HOWTO]] a documentației. 
 + 
 +===== Precizări încărcare ===== 
 + 
 +Arhiva temei va fi încărcată pe [[https://​curs.upb.ro/​2023/​mod/​assign/​view.php?​id=157094|moodle]]
  
-TODO Arhiva temei va fi încărcată pe [[|vmchecker]]. 
 /* Arhiva temei (fişier .zip) va fi uploadată pe site-ul cursului şi trebuie să conţină: */ /* Arhiva temei (fişier .zip) va fi uploadată pe site-ul cursului şi trebuie să conţină: */
  
-Arhiva trebuie să conțină:​ +Arhiva ​(fişier .zip) trebuie să conțină:​ 
-  * fișierele temei: ''​marketplace.py'',​ ''​producer.py'',​ ''​consumer.py''​ +  * fișierele temei și alte fișiere ''​.py''​ folosite în dezvoltare ​()
-  * alte fișiere ''​.py''​ folosite în dezvoltare+
   * ''​README''​   * ''​README''​
-  * director ​.git +  * (opțional) fișierul ''​git-log''​ (Îl obțineți rulând comanda ''​git log > git-log''​) 
-<​note ​tip>Pentru a documenta realizarea temei, vă recomandăm să folosiți ​template-ul ​de [[|aici]]+  * un exemplu de conținut al arhivei este mai jos 
 +    <​code>​ 
 +    api_server.py 
 +    app/ 
 +    app/​routes.py 
 +    app/​task_runner.py 
 +    app/​data_ingestor.py 
 +    app/​__init__.py 
 +    README 
 +    unittests/​ 
 +    unittests/​mytests.py 
 +    ​git-log 
 +    </​code> ​    
 + 
 +<​note>​ 
 +Repository-ul pe care îl folosiți ​în procesul ​de implementare este necesar să fie privat.
 </​note>​ </​note>​
 +
 +<note tip>
 +Pentru a documenta realizarea temei, vă recomandăm să folosiți template-ul de [[https://​gitlab.cs.pub.ro/​asc/​asc-public/​-/​blob/​master/​assignments/​README.example.md|aici]]
 +</​note>​
 +
  
 ===== Punctare ===== ===== Punctare =====
Line 187: Line 388:
 Tema se va implementa **Python>​=3.7**. Tema se va implementa **Python>​=3.7**.
  
-Notarea va consta în 100 pct acordate egale între ​teste. Depunctări posibile sunt:+Notarea va consta în 80 pct acordate egale între ​testele funcționale,​ 10 pct acordate pentru unitteste și 10 pct acordate pentru fișierul de logging. Depunctări posibile sunt:
   * folosirea incorectă a variabilelor de sincronizare (ex: lock care nu protejează toate accesele la o variabilă partajată, notificări care se pot pierde) (-2 pct)   * folosirea incorectă a variabilelor de sincronizare (ex: lock care nu protejează toate accesele la o variabilă partajată, notificări care se pot pierde) (-2 pct)
   * prezența print-urilor de debug (maxim -10 pct în funcție de gravitate)   * prezența print-urilor de debug (maxim -10 pct în funcție de gravitate)
Line 203: Line 404:
   * nerespectarea formatului .zip al arhivei (-2 pct)   * nerespectarea formatului .zip al arhivei (-2 pct)
   * alte situaţii nespecificate,​ dar considerate inadecvate având în vedere obiectivele temei; în special situațiile de modificare a interfeței oferite   * alte situaţii nespecificate,​ dar considerate inadecvate având în vedere obiectivele temei; în special situațiile de modificare a interfeței oferite
 +
 +Se acordă bonus 5 pct pentru adăugarea directorului ''​.git''​ și utilizarea versionării în cadrul repository-ului.
  
 <note warning> <note warning>
 Temele vor fi testate împotriva plagiatului. Orice tentativă de copiere va fi depunctată conform [[asc:​regulament|regulamentului]]. Temele vor fi testate împotriva plagiatului. Orice tentativă de copiere va fi depunctată conform [[asc:​regulament|regulamentului]].
 +Rezultatele notării automate este orientativă și poate fi afectată de corectarea manuală.
 </​note>​ </​note>​
  
 ==== Pylint ==== ==== Pylint ====
  
-Vom testa sursele voastre cu [[https://​www.pylint.org/​|pylint]] configurat conform fișierului **''​pylintrc''​** din {{:​asc:​teme:​tema1:​tema1-skel.zip|arhiva ​temei}}. Atenție, __rulăm pylint doar pe modulele completate și adăugate de voi__, nu și pe cele ale testerului. ​+Vom testa sursele voastre cu [[https://​www.pylint.org/​|pylint]] configurat conform fișierului **''​pylintrc''​** din cadrul repo-ului dedicat ​temei. Atenție, __rulăm pylint doar pe modulele completate și adăugate de voi__, nu și pe cele ale testerului. ​
  
 Deoarece apar diferențe de scor între versiuni diferite de pylint, vom testa temele doar cu [[https://​www.pylint.org/#​install| ultima versiune]]. Vă recomandăm să o folosiți și voi tot pe aceasta. Deoarece apar diferențe de scor între versiuni diferite de pylint, vom testa temele doar cu [[https://​www.pylint.org/#​install| ultima versiune]]. Vă recomandăm să o folosiți și voi tot pe aceasta.
  
 Vom face depunctări de până la -5pct dacă verificarea făcută cu pylint vă dă un scor mai mic de 8. Vom face depunctări de până la -5pct dacă verificarea făcută cu pylint vă dă un scor mai mic de 8.
- 
  
 ==== Observații ==== ==== Observații ====
Line 224: Line 427:
   * Bug-urile de sincronizare,​ prin natura lor sunt nedeterministe;​ o temă care conţine astfel de bug-uri poate obţine punctaje diferite la rulări succesive; în acest caz punctajul temei va fi cel dat de tester în momentul corectării   * Bug-urile de sincronizare,​ prin natura lor sunt nedeterministe;​ o temă care conţine astfel de bug-uri poate obţine punctaje diferite la rulări succesive; în acest caz punctajul temei va fi cel dat de tester în momentul corectării
   * Recomandăm testarea temei în cât mai multe situații de load al sistemului și pe cât mai multe sisteme pentru a descoperi bug-urile de sincronizare   * Recomandăm testarea temei în cât mai multe situații de load al sistemului și pe cât mai multe sisteme pentru a descoperi bug-urile de sincronizare
- 
  
 ===== Resurse necesare realizării temei ===== ===== Resurse necesare realizării temei =====
  
-Pentru a clona [[https://bitbucket.org/​ASC-admin/asc/src/​master/ ​| repo-ul]] și a accesa resursele temei 1:+Pentru a clona [[https://gitlab.cs.pub.ro/asc/asc-public ​| repo-ul]] și a accesa resursele temei 1:
  
 <code bash> <code bash>
-student@asc:​~$ git clone https://bitbucket.org/ASC-admin/asc.git +student@asc:​~$ git clone https://gitlab.cs.pub.ro/asc/asc-public.git 
-student@asc:​~$ cd assignments +student@asc:​~$ cd asc/assignments 
-student@asc:​~/​assignments$ cd 1-marketplace+student@asc:​~/​assignments$ cd 1-le_stats_sportif
 </​code>​ </​code>​
 +
  
 ===== Suport, întrebări și clarificări ===== ===== Suport, întrebări și clarificări =====
  
-Pentru întrebări sau nelămuriri legate de temă folosiți [[|forumul temei]]. ​+Pentru întrebări sau nelămuriri legate de temă folosiți [[https://​curs.upb.ro/​2023/​mod/​forum/​view.php?​id=148546|forumul temei]]. ​
  
 <note important>​ <note important>​
Line 246: Line 449:
  
 </​note>​ </​note>​
- 
- 
  
asc/teme/tema1.1616077727.txt.gz · Last modified: 2021/03/18 16:28 by giorgiana.vlasceanu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0