Como parte de nuestro conjunto de pruebas, además de las pruebas unitarias que se burlan de todo y no requieren una conexión a la base de datos, también tenemos pruebas de integración que sí requieren una base de datos.
Las Pruebas de Integración son necesarias porque estamos trabajando con mucho código heredado y nos brinda la posibilidad de realizar pruebas de alto nivel.
LA PUESTA EN MARCHA
La base de datos es un SQL Server 2008 R2, que se ejecuta en un sistema Windows Server 2008 R2 con las últimas actualizaciones de Windows. Tanto para el sistema operativo como para el servidor SQL.
La máquina virtual que ejecuta el servidor de la base de datos es parte de nuestra infraestructura de compilación y se crea recientemente, basándose en una imagen, por supuesto, todas las mañanas a las 6 a. m. y se destruye a las 10 p. m. Entonces sé que el Agente y el Servicio SQL Server son esencialmentenuevoy comencé todos los días. La primera compilación se produce a las 7 a. m., lo que le da a la máquina suficiente tiempo para iniciar y cargar todos los servicios.
El servidor de la base de datos está configurado para permitir un número ilimitado de conexiones y las conexiones TCP y canalizaciones con nombre están habilitadas.
La conexión a la base de datos se realiza mediante elsausuario.
Tenemos una instantánea recortada de nuestra base de datos de producción,a.mdf, que contiene todas las tablas, vistas, procedimientos almacenados y un conjunto mínimo de datos necesarios para realizar las pruebas.
Cuando se ejecuta una prueba de integración, la configuración de la prueba copiaa.mdfa la carpeta DATOS de nuestra instalación de SQL Server comob.mdf. Luego b.mdf se adjunta a la base de datos usando el siguiente comando:
CREATE DATABASE Foo ON (FILENAME = N'Path\To\b.mdf') FOR ATTACH
Las pruebas se ejecutan, realizan operaciones de base de datos y, durante la prueba, se desmonta el dispositivo de prueba, se desconecta la base de datos y se elimina el archivo b.mdf.
Los dos comandos siguientes se ejecutan individualmente para realizar la separación:
ALTER DATABASE Foo SET SINGLE_USER WITH ROLLBACK IMMEDIATE
EXEC master.dbo.sp_detach_db @dbname = N'Foo'
Entonces, en la práctica, tengo un conjunto de dispositivos de prueba con el siguiente diseño:
Setup();
Test_1();
Test_2();
Test_3();
TearDown();
Cada configuración crea una nueva base de datos, ejecuta todas las pruebas y elimina la base de datos para que el siguiente elemento de texto comience con una base de datos limpia y nueva.
En total tengo alrededor de 50 elementos de texto, cada uno con 10 pruebas. Eso es 50 veces que se adjunta y desconecta una base de datos y se ejecutan alrededor de 500 pruebas.
EL PROBLEMA
En las últimas semanas veo un aumento en la cantidad de compilaciones fallidas relacionadas con las pruebas de integración. Sé que mis pruebas están bien porque toda la configuración funciona perfectamente en mi máquina local y en las máquinas de los otros desarrolladores. Es sólo el servidor de compilación el que informa un problema:
SetUp Error : Namespace.Class.Method
SetUp : System.Data.SqlClient.SqlException : Cannot open database "Foo" requested by the login. The login failed.
Login failed for user 'sa'.
Obviamente, busqué en Google y sí, el inicio de sesión es correcto. Lo sé porque no siempre es la misma prueba la que falla. Si ejecuto todo el conjunto de pruebas 10 veces, fallará 8 de cada 10, pero la prueba que informa una falla es diferente cada vez. El mensaje de error es el mismo, dice que no puede iniciar sesión y, a veces, también informa queno hay ningún proceso en el otro extremo de la tubería.
También verifiqué que las conexiones TCP y de canalización con nombre estén habilitadas, verifiqué la cantidad de conexiones permitidas,... Verifiqué el archivo ERRORLOG, pero no contiene nada directamente relacionado con mi base de datos.
Supongo que por alguna extraña razón sucede que es demasiado rápido o demasiado lento y no es capaz de conectar o desconectar correctamente la base de datos, o es la SINGLE_USER
llamada la que causa el problema. Por lo que he recopilado, si una prueba falla debido al inicio de sesión, el archivo b.mdf no se puede eliminar porque parece estar en uso.
Entonces mi pregunta es: ¿hay algo más que pueda probar? ¿Existe algún archivo de registro de errores o un mensaje específico que pueda brindarme más información? ¿Hay algo que pueda hacer para comprobar si la conexión y la separación se realizaron correctamente? (¿Es posible que una desconexión fallida provoque el problema de inicio de sesión?) ¿La operación de desconexión es asincrónica y, por lo tanto, es posible que aún no se haya completado cuando se realice la siguiente llamada?
Respuesta1
Primer problema: error al iniciar sesión.
Lo más probable es que su base de datos aún no esté completamente inicializada cuando se ejecuten las pruebas.
Debería detectar esto en su procedimiento; una forma sencilla de hacerlo es consultar la base de datos maestra para ver si la base de datos de destino está en funcionamiento.
IF (select name from sys.databases
where name = 'foo' and state_desc = 'ONLINE' and is_in_standby = '0') IS NOT NULL
PRINT 'database not found';
Segundo problema: no hay proceso en el otro extremo del tubo.
El error detrás de esto a menudo se oculta si no se conecta a través de TCP/IP.
Podrías intentar habilitar conexiones IP directas, o podrías concentrarte en los otros errores, es probable que sean ellos los que estén causando este.