C'est un mémorandum parce que j'ai construit un environnement comme un titre dans mon travail et j'ai trébuché à divers endroits.
--Je voulais écrire un test unitaire pour un programme batch qui se connecterait à la base de données Oracle (oracle12c) avec sqlalchemy et viderait les informations requises. ―― Puisque SQL a été écrit directement dans ce code produit, j'ai essayé de construire et de vérifier l'environnement SQLite sur le test unitaire, mais j'ai vu une opinion raisonnable qu'il est préférable d'avoir le client DB dans l'environnement de test unitaire et l'environnement de production. Par conséquent, j'ai décidé de créer un environnement oracle12c même dans un environnement de test unitaire. ――Il est raisonnable de dire qu'il n'est pas bon d'écrire directement SQL, mais pour refactoriser cela, vous devez d'abord écrire un test unitaire.
Puisqu'il n'y a pas d'environnement de test unitaire en premier lieu, nous avons d'abord construit un environnement de test unitaire localement. Tout comme la création d'un environnement de test unitaire à l'aide d'une base de données commune, vous pouvez exécuter le test unitaire tout en démarrant db avec docker-compose.
Cliquez ici pour créer une image de menu fixe pour oracle12c.
docker-compose.yml
version: '2'
services:
oracle-database:
image: oracle/database:12.1.0.2-ee
container_name: oracle-database
ports:
- 1521:1521
volumes:
- ./startup:/opt/oracle/scripts/startup
environment:
- ORACLE_SID=SID
- ORACLE_PWD=passw0rd
- ORACLE_PDB=pdb
Une certaine préparation est nécessaire pour se connecter à cette base de données.
Dans le cas d'une base de données Oracle, la base de données sera créée dans l'utilisateur (schéma), il est donc nécessaire de créer d'abord l'utilisateur. Il est fastidieux d'écrire du code créé par l'utilisateur dans le code de test à chaque fois, alors laissez l'utilisateur être créé au démarrage de la base de données.
startup/startup.sql
ALTER SESSION SET container = pdb;
GRANT DBA TO PDBADMIN;
GRANT UNLIMITED TABLESPACE TO PDBADMIN;
CREATE USER testuser
IDENTIFIED BY passw0rd
DEFAULT TABLESPACE users
TEMPORARY TABLESPACE temp;
GRANT DBA TO testuser;
GRANT UNLIMITED TABLESPACE TO testuser;
L'image docker de la base de données Oracle exécute le fichier sql dans le dossier de démarrage en tant qu'utilisateur sysdb, modifiez donc la session pour ajouter l'utilisateur sur la base de données enfichable (PDB). Aussi, dans l'état initial, PDBADMIN n'a pas l'autorité équivalente à admin (pourquoi?), Donc l'autorité est accordée.
Ici, l'utilisateur est créé en tant que testuser / passw0rd. Comme il n'est utilisé que pour les tests unitaires, cet utilisateur dispose également de privilèges d'administrateur équivalents.
tests/test.py
import unittest
import cx_Oracle
import sqlalchemy
class Test(unittest.TestCase):
def setUp(self):
self.sut = ... #Instance testée
dsn = cx_Oracle.makedsn("oracle-database", 1521, service_name = "pdb")
self.testuser = sqlalchemy.create_engine(f"oracle+cx_oracle://testuser:passw0rd@{dsn}")
self.create_testtable()
def tearDown(self):
self.drop_testtable()
def test__testmethod__describe(self):
# SetUp
expected = ...
# Exercise
self.sut.testmethod(...)
# Verify
actual = ...
self.assertEqual(expected, actual)
def create_testtable(self):
self.testuser.execute(f"""
CREATE TABLE testtable (
... define columns ...
)
""")
def drop_testtable(self):
self.testuser.execute("DROP TABLE testtable")
if __name__ == "__main__":
unittest.main()
Je pense qu'il existe différentes manières d'écrire un test, donc à titre d'exemple. La partie importante ici est la partie connectée à oracle12c avec la méthode setUp. Créez un DSN et utilisez ces informations pour créer une URL de connexion et créer un moteur de connexion. Il existe différentes méthodes de connexion décrites dans sqlalchemy, mais pour vous connecter à PDB, vous devez vous connecter par ServiceName (et non par SID), et vous devez créer un DSN pour cela. Faites correspondre le nom d'hôte dans le DSN avec le nom du conteneur défini dans docker-compose.yml
.
Si vous préparez «__init __. Py» dans les tests, le test unitaire sera exécuté en exécutant «pytest» à la racine.
docker-compose up -d
pytest
Pour le moment, cela mettra en place l'environnement minimum. Cependant, il y a des problèmes avec cet environnement.
Comme vous pouvez le voir, après docker-compose up
, la construction de la base de données initiale prend un temps considérable et il faut environ 5 à 10 minutes pour que la base de données s'ouvre enfin (= se connecter). De plus, la construction initiale de la base de données échoue rarement (même si elle est construite avec Docker). Considérant l'environnement comme un test unitaire, la manipulation est assez mauvaise.
Sauvegardez la base de données initiale pour résoudre ce problème. Il y a une raison de dire «sauvegarde» ici. En effet, cette base de données initiale sera mise à jour régulièrement sous la forme d'une sauvegarde par écrasement après la connexion à partir du SGBD. Il en va de même lorsque la base de données devient sale en exécutant un test unitaire, mais même si rien n'est fait, la taille du fichier augmente et la base de données devient de plus en plus "sale". Puisqu'il est indéniable que le test peut échouer en raison de tels facteurs externes, il est nécessaire de restaurer la base de données initiale qui a été sauvegardée immédiatement avant docker-compose up
afin de construire un environnement de test stable. y a-t-il.
Une certaine technique est nécessaire pour créer la base de données initiale et préparer une sauvegarde. Un exemple est montré ici.
Commencez par créer une image de base de données Oracle pour créer la base de données initiale. L'exemple utilise docker-compose, mais vous pouvez utiliser une commande docker similaire.
docker-compose-oradata.yml
version: '2'
services:
oracle-database:
image: oracle/database:12.1.0.2-ee
container_name: oracle-database
ports:
- 1521:1521
volumes:
- ./oradata:/opt/oracle/oradata
environment:
- ORACLE_SID=SID
- ORACLE_PWD=passw0rd
- ORACLE_PDB=pdb
docker-compose -f docker-compose-oradata.yml up
Après exécution, la base de données initiale sera construite dans le dossier oradata. Cette construction prend environ 5 à 10 minutes. Dans l'exemple ci-dessus, il n'est pas en mode détaché afin de vérifier le moment où il est terminé ou non.
À partir de là, il est important d'arrêter la base de données avec Ctrl + C immédiatement après la fin de la construction. Si vous vous penchez sur cela, la base de données initiale deviendra en surpoids (environ 1,5 Go). Vous pouvez toujours le monter, mais cela n'a pas de sens si les fichiers que vous sauvegardez sont inutilement volumineux, alors fermez-les immédiatement après la construction.
Starting oracle-database ... done
Attaching to oracle-database
oracle-database | ORACLE PASSWORD FOR SYS, SYSTEM AND PDBADMIN: passw0rd
oracle-database |
oracle-database | LSNRCTL for Linux: Version 12.1.0.2.0 - Production on 15-OCT-2020 12:03:40
oracle-database |
oracle-database | Copyright (c) 1991, 2014, Oracle. All rights reserved.
oracle-database |
oracle-database | Starting /opt/oracle/product/12.1.0.2/dbhome_1/bin/tnslsnr: please wait...
oracle-database |
oracle-database | TNSLSNR for Linux: Version 12.1.0.2.0 - Production
oracle-database | System parameter file is /opt/oracle/product/12.1.0.2/dbhome_1/network/admin/listener.ora
oracle-database | Log messages written to /opt/oracle/diag/tnslsnr/bf429c874900/listener/alert/log.xml
oracle-database | Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1)))
oracle-database | Listening on: (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))
oracle-database |
oracle-database | Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1)))
oracle-database | STATUS of the LISTENER
oracle-database | ------------------------
oracle-database | Alias LISTENER
oracle-database | Version TNSLSNR for Linux: Version 12.1.0.2.0 - Production
oracle-database | Start Date 15-OCT-2020 12:03:40
oracle-database | Uptime 0 days 0 hr. 0 min. 0 sec
oracle-database | Trace Level off
oracle-database | Security ON: Local OS Authentication
oracle-database | SNMP OFF
oracle-database | Listener Parameter File /opt/oracle/product/12.1.0.2/dbhome_1/network/admin/listener.ora
oracle-database | Listener Log File /opt/oracle/diag/tnslsnr/bf429c874900/listener/alert/log.xml
oracle-database | Listening Endpoints Summary...
oracle-database | (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1)))
oracle-database | (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=0.0.0.0)(PORT=1521)))
oracle-database | The listener supports no services
oracle-database | The command completed successfully
oracle-database | Cleaning up failed steps
oracle-database | 4% complete
oracle-database | Copying database files
oracle-database | 5% complete
oracle-database | 6% complete
oracle-database | 30% complete
oracle-database | Creating and starting Oracle instance
oracle-database | 32% complete
oracle-database | 35% complete
oracle-database | 36% complete
oracle-database | 37% complete
oracle-database | 41% complete
oracle-database | 44% complete
oracle-database | 45% complete
oracle-database | 48% complete
oracle-database | Completing Database Creation
oracle-database | 50% complete
oracle-database | 53% complete
oracle-database | 55% complete
oracle-database | 63% complete
oracle-database | 66% complete
oracle-database | 74% complete
oracle-database | Creating Pluggable Databases
oracle-database | 79% complete
oracle-database | 100% complete
oracle-database | Look at the log file "/opt/oracle/cfgtoollogs/dbca/SID/SID0.log" for further details.
oracle-database |
oracle-database | SQL*Plus: Release 12.1.0.2.0 Production on Thu Oct 15 12:11:34 2020
oracle-database |
oracle-database | Copyright (c) 1982, 2014, Oracle. All rights reserved.
oracle-database |
oracle-database |
oracle-database | Connected to:
oracle-database | Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
oracle-database | With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
oracle-database |
oracle-database | SQL>
oracle-database | System altered.
oracle-database |
oracle-database | SQL>
oracle-database | Pluggable database altered.
oracle-database |
oracle-database | SQL> Disconnected from Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production
oracle-database | With the Partitioning, OLAP, Advanced Analytics and Real Application Testing options
oracle-database | The Oracle base remains unchanged with value /opt/oracle
oracle-database | #########################
oracle-database | DATABASE IS READY TO USE!
oracle-database | #########################
oracle-database | The following output is now a tail of the alert.log:
oracle-database | Completed: alter pluggable database PDB open
oracle-database | Thu Oct 15 12:11:33 2020
oracle-database | CREATE SMALLFILE TABLESPACE "USERS" LOGGING DATAFILE '/opt/oracle/oradata/SID/PDB/PDB_users01.dbf' SIZE 5M REUSE AUTOEXTEND ON NEXT 1280K MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO
oracle-database | Completed: CREATE SMALLFILE TABLESPACE "USERS" LOGGING DATAFILE '/opt/oracle/oradata/SID/PDB/PDB_users01.dbf' SIZE 5M REUSE AUTOEXTEND ON NEXT 1280K MAXSIZE UNLIMITED EXTENT MANAGEMENT LOCAL SEGMENT SPACE MANAGEMENT AUTO
oracle-database | ALTER DATABASE DEFAULT TABLESPACE "USERS"
oracle-database | Completed: ALTER DATABASE DEFAULT TABLESPACE "USERS"
oracle-database | Thu Oct 15 12:11:34 2020
oracle-database | ALTER SYSTEM SET control_files='/opt/oracle/oradata/SID/control01.ctl' SCOPE=SPFILE;
oracle-database | ALTER PLUGGABLE DATABASE PDB SAVE STATE
oracle-database | Completed: ALTER PLUGGABLE DATABASE PDB SAVE STATE
^CERROR: Aborting.
Sauvegardez le dossier oradata quelque part afin que le contenu de ce dossier oradata soit restauré avant d'exécuter docker-compose up
avant d'exécuter le test (dans les affaires réelles, le contenu de oradata doit être restauré. zip compressé et sauvegardé sur S3). Le fichier docker-compose.yml d'origine doit monter le dossier oradata.
docker-compose.yml
version: '2'
services:
oracle-database:
image: oracle/database:12.1.0.2-ee
container_name: oracle-database
ports:
- 1521:1521
volumes:
- ./oradata:/opt/oracle/oradata
- ./startup:/opt/oracle/scripts/startup
environment:
- ORACLE_SID=SID
- ORACLE_PWD=passw0rd
- ORACLE_PDB=pdb
En faisant cela, le temps nécessaire pour ouvrir la base de données pourrait être réduit à environ 1 à 2 minutes.
Le sujet principal.
Lorsque vous utilisez une base de données pour des tests unitaires sur GitLab CI, c'est une voie royale d'utiliser les services
. Cependant, l'image de la base de données Oracle doit être gérée par une sorte de référentiel privé, je n'ai jamais mis en place de référentiel privé dans les services et j'ai fait d'autres images de docker dans la pratique, donc ici j'utiliserai Docker dans Docker (dind) J'ai construit un environnement.
Il y a un problème lors de la création d'un environnement dind avec GitLab CI. Autrement dit, le répertoire dans lequel le volume est monté devient le répertoire hôte. Normalement (non limité à GitLab CI) l'exécution du travail elle-même se fait dans le conteneur docker, donc si vous exécutez docker-compose comme celui-ci, les dossiers oradata et startup seront dans le conteneur docker où le travail a été exécuté. Au lieu de cela, vous finissez par spécifier le dossier sur l'hôte qui exécute ce docker.
Il existe différentes solutions à cela, mais cette fois je l'ai évité en créant une image docker qui inclut des oradata. Étant donné que l'image de la base de données oracle doit être placée dans un référentiel privé en premier lieu, l'image contenant oradata n'est préparée que là-bas, de sorte que l'environnement local ne change pas beaucoup.
Le Dockerfile qui crée l'image de la base de données oracle, y compris l'oradata créé précédemment, ressemble à ceci.
Dockerfile
FROM oracle/database:12.1.0.2-ee
ENV ORACLE_SID SID
ENV ORACLE_PWD passw0rd
ENV ORACLE_PDB pdb
COPY --chown=oracle:dba oradata/ /opt/oracle/oradata/
COPY startup/ /opt/oracle/scripts/startup/
docker build -t oracle/database:12.1.0.2-ee-with-oradata
Il y a deux points à noter.
Tout d'abord, oradata dépend des variables d'environnement ORACLE_SID, ORACLE_PWD et ORACLE_PDB, alors ajoutez également ces variables d'environnement à votre Dockerfile. Si ceux-ci changent, recréez également les oradata.
L'autre consiste à changer le propriétaire en oracle: dba
lors de la copie d'oradata. Si vous le copiez tel quel, il deviendra l'utilisateur root et l'utilisateur oracle ne pourra pas monter la base de données initiale.
Ensuite, utilisez cette image et exécutez-la dans .gitlab-ci.yml.
docker-compose.yml
version: '2'
services:
oracle-database:
image: oracle/database:12.1.0.2-ee-with-oradata
container_name: oracle-database
ports:
- 1521:1521
yml:.gitlab-ci.yml
pytest:
stage: test
image: docker:dind
script:
- apk update && apk add bash python3 python3-dev py3-pip docker-compose
- python3 -m pip install pytest
- docker-compose up -d
- sleep 120s
- pytest
(Je ne suis pas sûr de créer un environnement d'exécution pour pytest, je le vérifierai plus tard)
Puisqu'il faut du temps pour ouvrir la base de données initiale, nous utilisons «sleep 120s» comme exemple ici.
Pour le moment, en faisant quelque chose comme ça, il est devenu possible d'exécuter des tests unitaires en utilisant la base de données Oracle à la fin de GitLab CI.
Recommended Posts