Potencia tu flujo de trabajo de desarrollo con Gemini Code Assist

1. Introducción

e5b98fd4e417c877.png

En este codelab, verás cómo Gemini Code Assist puede ayudarte en las etapas clave del ciclo de vida del desarrollo de software (SDLC), como el diseño, la compilación y las pruebas, y la implementación. Diseñaremos y desarrollaremos una aplicación completa, y la implementaremos en Google Cloud.

Compilaremos una API y una aplicación para buscar en las sesiones de un evento técnico. Cada sesión tendrá un título, un resumen, una duración, categorías y uno o más oradores.

Actividades

  • Diseña, compila, prueba e implementa una aplicación web basada en una especificación de OpenAPI desde cero

Qué aprenderás

  • Cómo usar Gemini Code Assist para generar una especificación de OpenAPI
  • Cómo usar las funciones de generación de código de Gemini Code Assist para desarrollar una aplicación de Flask en Python para la especificación de OpenAPI
  • Cómo usar Gemini Code Assist para generar un frontend web para la aplicación de Flask en Python
  • Cómo usar Gemini Code Assist para obtener ayuda sobre cómo implementar la aplicación en Google Cloud Run
  • Usar funciones de Gemini Code Assist, como Explicación de código y Generación de casos de prueba, mientras se compila y prueba la aplicación

Requisitos

  • Navegador web Chrome
  • Una cuenta de Gmail
  • Un proyecto de Cloud con la facturación habilitada
  • Gemini Code Assist habilitado para tu proyecto de Cloud

Este lab está dirigido a desarrolladores de todos los niveles, incluidos principiantes. Aunque la aplicación de muestra está en lenguaje Python, no es necesario que sepas programar en ese lenguaje para entender lo que se hace. Nuestro enfoque será que te familiarices con las capacidades de Gemini Code Assist.

2. Configura Gemini Code Assist

En esta sección, se explica todo lo que debes hacer para comenzar este lab.

Habilita Gemini Code Assist en el IDE de Cloud Shell

Usaremos el IDE de Cloud Shell, un entorno de desarrollo completamente administrado basado en Code OSS, durante el resto del codelab. Debemos habilitar y configurar Code Assist en el IDE de Cloud Shell. Los pasos se indican a continuación:

  1. Visita ide.cloud.google.com. Es posible que el IDE tarde un poco en aparecer, así que ten paciencia y acepta las opciones predeterminadas de configuración. En caso de que veas algunas instrucciones para configurar el IDE, continúa y completa los pasos con la configuración predeterminada.
  2. Haz clic en el botón Cloud Code - Acceder en la barra de estado de la parte inferior como se muestra. Autoriza el complemento según las instrucciones. Si ves "Cloud Code (ningún proyecto)" en la barra de estado, selecciónalo y elige el proyecto específico de Google Cloud de la lista de proyectos con los que planeas trabajar.

6f5ce865fc7a3ef5.png

  1. Haz clic en el botón Code Assist en la esquina inferior derecha como se muestra y selecciona por última vez el proyecto de Google Cloud correcto. Si se te solicita que habilites la API de Cloud AI Companion, hazlo y continúa.
  2. Una vez que selecciones tu proyecto de Google Cloud, asegúrate de que puedas verlo en el mensaje de estado de Cloud Code en la barra de estado y de tener Code Assist habilitado en la barra de estado del lado derecho, como se muestra a continuación:

709e6c8248ac7d88.png

¡Gemini Code Assist está listo para usarse!

3. Configura Firestore

Cloud Firestore es una base de datos de documentos sin servidores completamente administrada que usaremos como backend para los datos de nuestra aplicación. Los datos de Cloud Firestore se estructuran en colecciones de documentos.

Debemos crear una colección llamada sessions en nuestra base de datos predeterminada de Firestore. Esta colección contendrá datos de muestra (documentos) que luego usaremos en nuestra aplicación.

Abre la terminal desde el IDE de Cloud Shell a través del menú principal, como se muestra a continuación:

f1535e14c9beeec6.png

Debemos crear una colección llamada sessions. Este contendrá una lista de documentos de sesión de muestra. Cada documento tendrá los siguientes atributos:

  1. title: cadena
  2. categories: array de cadenas
  3. speakers: array de cadenas
  4. duration: cadena
  5. summary: cadena

Copia un archivo que contenga los datos de muestra en un bucket de tu propio proyecto para completar esta colección con datos de muestra. Luego, podrás importar la colección con el comando gcloud firestore import.

Inicialización de la base de datos de Firestore

Visita la página de Firestore en la consola de Cloud.

Si no inicializaste una base de datos de Firestore en el proyecto, crea la base de datos default. Durante la creación de la base de datos, usa los siguientes valores:

  • Modo de Firestore: Native
  • Ubicación: Elige el tipo de ubicación como Region y selecciona la región adecuada para tu aplicación. Anota esta ubicación, ya que la necesitarás en el siguiente paso para la ubicación del bucket.
  • Crea la base de datos.

504cabdb99a222a5.png

Ahora crearemos la colección sessions siguiendo los pasos que se indican a continuación:

  1. Crea un bucket en tu proyecto con el comando gsutil que se indica a continuación. Reemplaza la variable <PROJECT_ID> en el siguiente comando por el ID de tu proyecto de Google Cloud. Reemplaza <BUCKET_LOCATION> por el nombre de una región que corresponda al área geográfica de tu base de datos predeterminada de Firestore (como se indicó en el paso anterior). Podría ser US-WEST1, EUROPE-WEST1 o ASIA-EAST1 :
gsutil mb -l <BUCKET-LOCATION> gs://<PROJECT_ID>-my-bucket
  1. Ahora que se creó el bucket, debemos copiar la exportación de la base de datos que preparamos en este bucket antes de poder importarla a la base de datos de Firebase. Usa el siguiente comando:
gsutil cp -r gs://sessions-master-database-bucket/2024-03-26T09:28:15_95256  gs://<PROJECT_ID>-my-bucket

Ahora que tenemos los datos para importar, podemos pasar al paso final de importar los datos a la base de datos de Firebase (default) que creamos.

  1. Usa el siguiente comando de gcloud:
gcloud firestore import gs://<PROJECT_ID>-my-bucket/2024-03-26T09:28:15_95256

La importación tardará unos segundos y, cuando esté lista, podrás validar tu base de datos y colección de Firestore. Para ello, visita https://console.cloud.google.com/firestore/databases, selecciona la base de datos default y la colección sessions, como se muestra a continuación:

d3e294d46ba29cd5.png

Con esto, se completa la creación de la colección de Firestore que usaremos en nuestra aplicación.

4. Crea la plantilla de aplicación

Crearemos una aplicación de muestra (una aplicación de Flask en Python) que usaremos en el resto del codelab. Esta aplicación buscará en las sesiones que se ofrecen en una conferencia técnica.

Sigue estos pasos:

  1. Haz clic en el nombre del proyecto de Google Cloud en la barra de estado que aparece a continuación.

f151759c156c124e.png

  1. Aparecerá una lista de opciones. Haz clic en Aplicación nueva en la lista que aparece a continuación.

91ea9836f38b7f74.png

  1. Selecciona Cloud Run application (este será el tiempo de ejecución de nuestra app).
  2. Selecciona la plantilla de aplicación Python (Flask): Cloud Run.
  3. Asigna un nombre a la aplicación y guárdala en la ubicación que prefieras.
  4. Una notificación confirmará que se creó tu aplicación y se abrirá una nueva ventana con tu aplicación cargada, como se muestra a continuación. Se abrirá un archivo README.md. Ahora puedes cerrar esa vista.

aaa3725b17ce27cf.png

5. Interactúa con Gemini Code Assist

Para los fines de este lab, usaremos el chat de Gemini Code Assist disponible en el IDE de Cloud Shell como parte de la extensión de Cloud Code en VS Code. Para abrirlo, haz clic en el botón de Code Assist en la barra de navegación izquierda. Busca el ícono de Code Assist a489f98a34898727.png en la barra de herramientas de navegación del lado izquierdo y haz clic en él.

De esa forma, se abrirá el panel de chat de Code Assist en el IDE de Cloud Shell y podrás chatear con Code Assist.

14ad103efaa0ddaa.png

Observa el ícono de papelera en la parte superior. Esta es la forma de restablecer el contexto del historial de chat de Code Assist. Ten en cuenta también que esta interacción de chat es contextual para los archivos en los que estás trabajando en el IDE.

6. Diseño de API

Nuestro primer paso será aprovechar la asistencia de Gemini Code Assist durante la fase de diseño. En este paso, generaremos una especificación de OpenAPI para las entidades (sesiones técnicas en un evento) en las que queremos realizar búsquedas.

Dale la siguiente instrucción:

Generate an Open API spec that will allow me to retrieve all sessions, sessions by category, session by id. Each session has the following attributes: id, title, list of speakers, list of categories, summary and duration.

Esto debería generar una especificación de OpenAPI para buscar en las sesiones a través de varios parámetros de búsqueda. A continuación, se muestra la muestra de especificación:

openapi: 3.0.0
info:
 title: Sessions API
 description: This API allows you to retrieve all sessions, sessions by category, and session by id.
 version: 1.0.0
servers:
 - url: https://sessions.example.com
paths:
 /sessions:
   get:
     summary: Get all sessions
     operationId: getSessions
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
 /sessions/{id}:
   get:
     summary: Get session by id
     operationId: getSessionById
     parameters:
       - name: id
         in: path
         required: true
         description: The id of the session
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               $ref: '#/components/schemas/Session'
 /sessions/categories/{category}:
   get:
     summary: Get sessions by category
     operationId: getSessionsByCategory
     parameters:
       - name: category
         in: path
         required: true
         description: The category of the sessions
         schema:
           type: string
     responses:
       '200':
         description: OK
         content:
           application/json:
             schema:
               type: array
               items:
                 $ref: '#/components/schemas/Session'
components:
 schemas:
   Session:
     type: object
     properties:
       id:
         type: string
         description: The id of the session
       title:
         type: string
         description: The title of the session
       speakers:
         type: array
         items:
           type: string
         description: The list of speakers for the session
       categories:
         type: array
         items:
           type: string
         description: The list of categories for the session
       summary:
         type: string
         description: The summary of the session
       duration:
         type: string
         description: The duration of the session

Puedes observar que la especificación tiene lo siguiente:

  • Es un esquema definido para el tipo de sesión.
  • Se definieron varias rutas de acceso a la API:
  • /sessions
  • /sessions/{id}
  • /sessions/categories/{category}

Crea un archivo llamado sessionsapi.yaml en la carpeta superior y copia el contenido de la ventana de chat de Code Assist con la opción "Insertar en el archivo actual" (el botón +) y mantén el archivo abierto en el IDE de Cloud Shell.

En este punto, puedes observar una función interesante de Gemini Code Assist: la citación. Esta información se muestra al desarrollador cuando el código generado cita directamente y de forma extensa otra fuente, como el código fuente abierto existente. Ofrece la fuente y la licencia para que el desarrollador decida qué hacer con ella.

Suponiendo que el contenido generado es adecuado, ahora podemos usar este documento de especificaciones para generar una aplicación de Flask en Python.

7. Genera la aplicación

Ahora le pediremos a Code Assist que genere la aplicación. Dale la siguiente instrucción con el archivo sessionsapi.yaml abierto.

Generate a Python Application using the Flask framework, based on the sessionsapi.yaml file. This application uses a local in memory list of sessions. Do not use any Flask extensions.

Esto debería proporcionarte un esqueleto para la aplicación de Flask de Python que se basa en la funcionalidad y las rutas de acceso que se especificaron en el archivo de especificación de OpenAPI.

El código de la aplicación de Flask en Python que se proporciona debería ser similar al siguiente:

from flask import Flask, jsonify, request

app = Flask(__name__)

sessions = [
    {
        "id": "1",
        "title": "Session 1",
        "speakers": ["Speaker 1", "Speaker 2"],
        "categories": ["Category 1", "Category 2"],
        "summary": "This is a summary of session 1.",
        "duration": "1 hour",
    },
    {
        "id": "2",
        "title": "Session 2",
        "speakers": ["Speaker 3", "Speaker 4"],
        "categories": ["Category 3", "Category 4"],
        "summary": "This is a summary of session 2.",
        "duration": "1 hour 30 minutes",
    },
]

@app.route('/sessions', methods=['GET'])
def get_sessions():
    return jsonify(sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
    session = next((session for session in sessions if session['id'] == id), None)
    if session is None:
        return jsonify({}), 404
    return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
    sessions_by_category = [session for session in sessions if category in session['categories']]
    return jsonify(sessions_by_category)

if __name__ == '__main__':
    app.run()

Hay un archivo app.py existente que se generó como parte del paso anterior. Simplemente reemplaza su contenido por el código generado por Code Assist y guarda el archivo.

Nos gustaría cambiar la línea app.run() para usar el puerto 8080, la dirección de host 0.0.0.0 y también ejecutar en modo de depuración durante la ejecución local.Esta es una forma de hacerlo. Primero, destacaremos o seleccionaremos la línea:

app.run()

Luego, en la interfaz de chat de Code Assist, escribe la instrucción: Explain this.

Debería mostrar una explicación detallada de esa línea en particular, como se muestra en el siguiente ejemplo:

58ec896a32a4fb68.png

Ahora, usa la siguiente instrucción:

update the code to run the application on port 8080, host address 0.0.0.0, and in debug mode

El código sugerido generado debería ser el siguiente:

app.run(host='0.0.0.0', port=8080, debug=True)

Recuerda actualizar el archivo app.py con este fragmento.

Ejecuta la aplicación de manera local

Ahora, ejecutemos la aplicación de forma local para validar los requisitos de la aplicación según lo que habíamos comenzado.

El primer paso será crear un entorno virtual de Python con las dependencias del paquete de Python en requirements.txt para que se instalen en el entorno virtual. Para ello, ve a la paleta de comandos (Ctrl + Mayúsculas + P) en el IDE de Cloud Shell y escribe Create Python environment. Sigue los próximos pasos para seleccionar un entorno virtual (venv), un intérprete de Python 3.x y el archivo requirements.txt.

Una vez que se cree el entorno, inicia una nueva ventana de terminal (Ctrl + Mayúsculas +`) y ejecuta el siguiente comando:

python app.py

A continuación, se muestra una ejecución de muestra:

(.venv) romin@cloudshell: $ python app.py 
 * Serving Flask app 'app'
 * Debug mode: on
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on all addresses (0.0.0.0)
 * Running on http://127.0.0.1:8080
 * Running on http://10.88.0.3:8080
Press CTRL+C to quit
 * Restarting with stat
 * Debugger is active!
 * Debugger PIN: 132-247-368

Ahora puedes obtener una vista previa de la API en las siguientes URLs. Suponemos que tu servidor de desarrollo se ejecuta en el puerto 8080. De lo contrario, cámbialo al número de puerto adecuado.

  • https://<host-name>:8080/sessions
  • https://<host-name>:8080/sessions/{id}
  • https://<host-name>:8080/sessions/categories/{category}

Sigue los pasos que se indican a continuación para asegurarte de que puedes recuperar, con estas URLs, los datos JSON que se encuentran en el archivo app.py:

Abre una nueva ventana de terminal y prueba cualquiera de los siguientes comandos:

curl -X GET http://127.0.0.1:8080/sessions
curl -X GET http://127.0.0.1:8080/sessions/<ID>
curl -X GET http://127.0.0.1:8080/sessions/categories/<CATEGORY_NAME> 

8. Refactorización del código

En lugar de que app.py contenga los datos JSON de muestra codificados de forma rígida, probablemente nos gustaría separar o extraer esto en otro módulo, de modo que podamos mantener una separación clara entre el código y los datos. ¡Hagámoslo!

Mantén abierto el archivo app.py y da la siguiente instrucción:

Can I improve this code and separate out the sessions data from this app.py file?

Esto debería darte algunas sugerencias sobre cómo hacerlo. A continuación, se muestra una sugerencia de muestra que obtuvimos y que deberías obtener algo similar:

9b9c56cb527dac4c.png

Sigamos esa sugerencia y separemos nuestros datos en un archivo sessions.py, como sugiere Code Assist.

Crea un archivo nuevo llamado sessions.py.

, cuyo contenido es la lista JSON, según los datos que generamos, se proporciona a continuación:

sessions = [
   {
       "id": "1",
       "title": "Session 1",
       "speakers": ["Speaker 1", "Speaker 2"],
       "categories": ["Category 1", "Category 2"],
       "summary": "This is a summary of session 1.",
       "duration": "1 hour",
   },
   {
       "id": "2",
       "title": "Session 2",
       "speakers": ["Speaker 3", "Speaker 4"],
       "categories": ["Category 3", "Category 4"],
       "summary": "This is a summary of session 2.",
       "duration": "1 hour 30 minutes",
   },
]

El archivo app.py ahora es mucho más simple y se muestra a continuación:

from flask import Flask, jsonify, request
from sessions import sessions

app = Flask(__name__)

@app.route('/sessions', methods=['GET'])
def get_sessions():
   return jsonify(sessions.sessions)

@app.route('/sessions/<id>', methods=['GET'])
def get_session_by_id(id):
   session = next((session for session in sessions.sessions if session['id'] == id), None)
   if session is None:
       return jsonify({}), 404
   return jsonify(session)

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   return jsonify(sessions_by_category)

if __name__ == '__main__':
   app.run(host='0.0.0.0', port=8080, debug=True)

Asegúrate de que aún puedas ejecutar la aplicación de forma local y probar la API con estos cambios refactorizados. Es probable que el servidor de desarrollo de Python siga en ejecución, por lo que solo debes recordar los comandos de curl del paso anterior.

9. Integración con la colección de Firestore

El siguiente paso es dejar de usar la lista JSON local en memoria que tenemos para nuestras sesiones y conectar nuestra aplicación a la colección sessions en la base de datos de Firestore, que creamos al principio de este codelab.

Mantén abierto el archivo sessions.py y da la siguiente instrucción:

Can you further refactor the sessions.py code to read from a Firestore database that has a collection named sessions. The collection has the same attributes as the session object that we have defined. Use the Python module google-cloud-firestore. 

Recibimos la siguiente sugerencia para leer todas las sesiones de la colección de Firestore:

import google.cloud.firestore

# Create a Firestore client
db = google.cloud.firestore.Client()

# Get the sessions collection
sessions_collection = db.collection("sessions")

# Create a list of sessions
sessions = []

# Iterate over the documents and add them to the list
for doc in sessions_collection.stream():
   session = doc.to_dict()
   session["id"] = doc.id
   sessions.append(session)

Incorpora el código en sessions.py.

Si tienes el servidor de desarrollo de Flask ejecutándose de forma local, es posible que tu aplicación se haya cerrado y haya mostrado un mensaje de error que indica que no se encontró el módulo de Python.

Por ejemplo, puedes preguntarle a Code Assist qué módulo de Python se debe agregar al archivo requirements.txt, de la siguiente manera:

Which Python package needs to be installed to make the firestore code work?

Esto te proporcionará el nombre del módulo de Python (p.ej., google-cloud-firestore). Agrégalo al archivo requirements.txt.

Deberás volver a crear el entorno de Python con el módulo agregado recientemente (google-cloud-firestore). Para ello, ejecuta el siguiente comando en la ventana de la terminal existente:

pip install -r requirements.txt

Vuelve a ejecutar la aplicación (reiníciala con python app.py) y visita la URL de /sessions. Ahora deberías obtener los documentos de muestra que agregamos a la colección sessions.

975d05e6518f1a6a.png

Puedes consultar otros URIs para recuperar sesiones específicas o todas las sesiones de una categoría determinada, como se describió en los pasos anteriores.

10. Explicación del código

Ahora es un buen momento para usar la función "Explain this" de Gemini Code Assist para comprender mejor el código. Puedes ingresar a cualquiera de los archivos o seleccionar fragmentos de código específicos y hacerle la siguiente pregunta a Code Assist: Explain this.

Como ejercicio, visita el archivo sessions.py, destaca el código específico de Firestore y obtén una explicación sobre él. También puedes usar esta función en otros archivos de tu proyecto, no solo en código de Python.

11. Genera la aplicación web

Ahora que generamos la API y la integramos con una colección activa de Firestore, generemos un frontend basado en la Web para la aplicación. Por el momento, nuestro frontend web mantendrá su funcionalidad al mínimo, es decir, podrá buscar sesiones que pertenezcan a una categoría específica. Ten en cuenta que tenemos una ruta de API para eso, es decir, /sessions/categories/{category}, por lo que nuestra aplicación web debería invocarla y recuperar los resultados.

Comencemos. Dale la siguiente instrucción a Code Assist:

Generate a web application that allows me to search for sessions by category and uses the Flask application that we created. Please use basic HTML, CSS and JS. Embed all the Javascript and CSS code into a single HTML file only.

Esto generará el HTML de la aplicación web con JavaScript y CSS incorporados. También te pedirá que agregues una ruta nueva al archivo app.py para que a cualquier usuario que visite la URL raíz o base se le muestre la página principal. Si no se menciona esa información, pregunta al respecto o usa el fragmento que se muestra a continuación:

@app.route('/')
def index():
   return render_template('index.html')

Puedes guardar este archivo como index.html, pero es posible que tengas dudas sobre dónde guardarlo (es decir, en qué carpeta). Podemos hacerle una pregunta adicional a Code Assist.

Given that I am using the flask framework, where should I put the index.html file?

Debería proporcionarte información clara de que usa el framework render_template, por lo que el archivo index.html deberá colocarse dentro de la carpeta templates. Encontrarás esta carpeta disponible, ya que generamos una aplicación basada en la plantilla de Flask al comienzo de este codelab. Como resultado, hay un archivo index.html existente, y solo debes reemplazar su contenido por el nuevo que se generó aquí. Code Assist también menciona que debes importar render_template en tu archivo app.py.

Guarda el código de la aplicación web en el archivo index.html y recuerda colocarlo en la carpeta templates.

Ejecuta la aplicación de manera local

Ahora, ejecutemos la aplicación de forma local para validar los requisitos de la aplicación según lo que habíamos comenzado.

Asegúrate de que el servidor local de Flask siga en ejecución y no muestre ningún error. En caso de errores, corrígelos y, luego, inicia el servidor.

Una vez que esté en funcionamiento, visita la URL principal de la aplicación. Debería mostrarte el archivo index.html publicado, como se muestra a continuación:

8ca586acc4536879.png

Proporciona una de las categorías de los datos como entrada (p.ej., AI) y haz clic en el botón Search. Deberían mostrarse las sesiones etiquetadas con la categoría AI.

165faded790a6c.png

Un ejercicio opcional es mostrar metadatos adicionales, como la duración, las categorías, los oradores y el resumen de cada sesión.

12. Generación de casos de prueba

Generamos la API de sesiones y ahora es momento de usar Gemini Code Assist para generar casos de prueba de unidades para las diferentes rutas de acceso a la API.

Mantén abierto el archivo app.py y da la siguiente instrucción:

Generate unit test cases for app routes. Use unittest module.

Obtuvimos la siguiente respuesta:

import unittest
from app import app

class FlaskAppTestCase(unittest.TestCase):

    def test_index(self):
        tester = app.test_client()
        response = tester.get('/')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions(self):
        tester = app.test_client()
        response = tester.get('/sessions')
        self.assertEqual(response.status_code, 200)

    def test_get_session_by_id(self):
        tester = app.test_client()
        response = tester.get('/sessions/1')
        self.assertEqual(response.status_code, 200)

    def test_get_sessions_by_category(self):
        tester = app.test_client()
        response = tester.get('/sessions/categories/category1')
        self.assertEqual(response.status_code, 200)

if __name__ == '__main__':
    unittest.main()

Crea un archivo llamado tests.py con el código anterior.

Nota sobre la generación de casos de prueba

Es posible que veas un listado de código diferente al anterior, lo que podría causar algunos problemas al ejecutar los casos de prueba. Por ejemplo, observamos que, en algunas de nuestras ejecuciones, se omitieron los siguientes fragmentos de código clave:

from app import app

El código anterior es necesario para importar la app de Flask existente con la que invocaremos los casos de prueba.

if __name__ == '__main__':

`unittest.main()`

El código anterior es necesario para ejecutar los casos de prueba.

Te recomendamos que revises cada caso de prueba, verifiques el assertEqual y otras condiciones en el código generado para asegurarte de que funcionará. Dado que los datos son externos en la colección de Firestore, es posible que no tengas acceso a ellos y que uses algunos datos ficticios, por lo que es posible que las pruebas fallen. Por lo tanto, modifica tus casos de prueba según corresponda o comenta algunos de los casos de prueba que tal vez no necesites de inmediato.

Como demostración, ejecutamos los casos de prueba con el siguiente comando (asegúrate de ejecutar el servidor de desarrollo local, ya que se realizarán llamadas a los extremos de la API local):

python tests.py

Obtuvimos el siguiente resultado del resumen:

Ran 4 tests in 0.274s

FAILED (failures=2)

De hecho, es correcto, ya que el ID de sesión no era correcto en la tercera prueba y no hay ninguna categoría llamada category1.

.

Por lo tanto, ajusta los casos de prueba según corresponda y pruébalos.

13. Desarrollo basado en pruebas

Ahora veamos cómo agregar un nuevo método de búsqueda en nuestra API de sesiones siguiendo la metodología de desarrollo basado en pruebas (TDD), que consiste en escribir primero casos de prueba, hacer que fallen debido a la falta de implementación y usar Gemini Code Assist para generar la implementación faltante de modo que la prueba pase.

Ve al archivo tests.py (suponiendo que corregiste el archivo tests.py para que todas las pruebas pasen). Hazle la siguiente pregunta a Code Assist:

Generate a new test case to search for sessions by speaker

Esto nos proporcionó la siguiente implementación de caso de prueba que insertamos debidamente en el archivo tests.py.

  def test_get_sessions_by_speaker(self):
        tester = app.test_client()
        response = tester.get('/sessions/speakers/speaker1')
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.json, [sessions.sessions[0], sessions.sessions[1]])

Si ejecutas las pruebas, deberías ver el siguiente error:

$ python tests.py 
.F.
======================================================================
FAIL: test_get_sessions_by_speaker (__main__.FlaskAppTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/romin/hello-world-5/tests.py", line 21, in test_get_sessions_by_speaker
    self.assertEqual(response.status_code, 200)
AssertionError: 404 != 200

----------------------------------------------------------------------
Ran 3 tests in 0.010s

FAILED (failures=1)

Esto se debe a que el caso de prueba invocó la siguiente ruta (/sessions/speakers/) y no hay ninguna implementación de eso en app.py.

Pidámosle a Code Assist que nos proporcione una implementación. Ve al archivo app.py y dale la siguiente instrucción a Code Assist:

Add a new route to search for sessions by a specific speaker

Code Assist nos sugirió la siguiente implementación, que agregamos al archivo app.py:

@app.route('/sessions/speakers/<speaker>', methods=['GET'])
def get_sessions_by_speaker(speaker):
    sessions_by_speaker = [session for session in sessions.sessions if speaker in session['speakers']]
    return jsonify(sessions_by_speaker)

Vuelve a visitar el archivo tests.py y modificamos nuestro caso de prueba de la siguiente manera para una verificación rápida:

   def test_get_sessions_by_speaker(self):
       tester = app.test_client()
       response = tester.get('/sessions/speakers/Romin Irani')
       self.assertEqual(response.status_code, 200)
       self.assertEqual(len(response.json), 1)

La prueba se ejecutó correctamente. Te dejamos como ejercicio que revises los casos de prueba generados, los modifiques un poco según los datos que puedas tener en Firestore y tengas los métodos assert* adecuados en los casos de prueba de unidades de Python.

14. Implementación en Google Cloud Run

Ahora que nos sentimos satisfechos con la calidad de nuestro desarrollo, el paso final será implementar esta aplicación en Google Cloud Run. Pero, tal vez, para asegurarnos, deberíamos preguntarle a Code Assist si olvidamos algo. Con app.py abierto, envía la siguiente instrucción :

Is there something here I should change before I deploy to production?

Por suerte, preguntaste, ya que olvidamos desactivar la marca de depuración :

2f87ed3a811fb218.png

Como se indicó, desactiva la depuración y continúa pidiéndole ayuda a Gemini Code Assist con el comando gcloud que se puede usar para implementar la aplicación en Cloud Run directamente desde el código fuente (sin tener que compilar un contenedor primero).

Dale la siguiente instrucción:

I would like to deploy the application to Cloud Run directly from source. What is the gcloud command to do that?

Prueba algunas variaciones de la instrucción anterior. Otro que probamos fue el siguiente:

I would like to deploy this application to Cloud Run. I don't want to build a container image locally but deploy directly from source to Cloud Run. What is the gcloud command for that?

Lo ideal sería que obtuvieras el siguiente comando gcloud:

gcloud run deploy sessions --source .

También puedes obtener lo siguiente:

gcloud run deploy <service-name> --source . \
—-platform managed \
—-allow-unauthenticated

Ejecuta el comando anterior desde la carpeta raíz de la aplicación. Cuando se te solicite region, selecciona us-central1 y, cuando se te solicite que permitas unauthenticated invocations, elige Y. Es posible que también se te solicite que habilites las APIs de Google Cloud, como Artifact Registry, Cloud Build y Cloud Run, y que otorgues permiso para crear un repositorio de Artifact Registry. Si es así, otorga el permiso.

El proceso de implementación tardará alrededor de 2 minutos en completarse, así que ten paciencia.

Una vez que se implemente correctamente, verás la URL del servicio de Cloud Run. Visita esa URL pública y deberías ver la misma aplicación web implementada y en ejecución correctamente.

c5322d0fd3e0f616.png

¡Felicitaciones, lo hiciste muy bien!

15. (Opcional) Usa Cloud Logging

Podemos introducir el registro en nuestra aplicación de modo que los registros de la aplicación se centralicen en uno de los servicios de Google Cloud (Cloud Logging). Luego, podemos usar la función Observability Gemini para comprender las entradas de registro también.

Para ello, primero tendremos que usar una biblioteca de Cloud Logging de Python existente de Google Cloud y usarla para registrar mensajes informativos, de advertencia o de error (según el registro o el nivel de gravedad).

Intentemos preguntarle eso primero a Code Assist. Prueba la siguiente instrucción:

How do I use the google-cloud-logging package in Python?

Deberías obtener una respuesta que proporcione información sobre el tema, como se muestra a continuación:

2472e1ccaf8a217d.png

Agreguemos instrucciones de registro a la función que busca sesiones por categoría.

Primero, agrega el paquete de Python google-cloud-logging al archivo requirements.txt.

A continuación, se incluye un fragmento de código que muestra cómo integramos el código para implementar el registro:

...
from google.cloud import logging
...
app = Flask(__name__)

# Create a logger
logger = logging.Client().logger('my-log')

@app.route('/sessions/categories/<category>', methods=['GET'])
def get_sessions_by_category(category):
   logger.log_text(f"Fetching sessions with category {category}")
   sessions_by_category = [session for session in sessions.sessions if category in session['categories']]
   logger.log_text(f'Found {len(sessions_by_category)} sessions with category {category}')
   return jsonify(sessions_by_category)

# # Other App Routes

Vuelve a implementar el servicio en Cloud Run con el mismo comando que en la sección anterior y, una vez que se implemente, ejecuta algunas llamadas al extremo /sessions/categories/<category>.

Ve a Cloud Console → Logs Explorer.

59e297577570695.png

…y deberías poder filtrar estas instrucciones de registro como se muestra a continuación:

914f1fb6cac30a89.png

Puedes hacer clic en cualquiera de las instrucciones de registro, expandirla y, luego, hacer clic en Explain this log entry, que usará Gemini para explicar la entrada de registro. Ten en cuenta que, si no habilitaste Gemini para Google Cloud, se te pedirá que habilites la API de Cloud AI Companion. Sigue las instrucciones.

A continuación, se muestra una respuesta de ejemplo:

7fc9783910fa92cc.png

16. Felicitaciones

¡Felicitaciones! Compilaste correctamente una aplicación desde cero y usaste Gemini Code Assist en varios aspectos del SDLC, incluidos el diseño, la compilación, las pruebas y la implementación.

¿Qué sigue?

Consulta algunos codelabs sobre los siguientes temas:

Documentos de referencia