Como parte de nosso conjunto de testes, ao lado dos Testes de Unidade que simulam tudo e não requerem conexão com banco de dados, também temos Testes de Integração que exigem um banco de dados.
Os Testes de Integração são necessários porque estamos trabalhando com muito código legado e isso nos dá a possibilidade de realizar testes de alto nível.
A CONFIGURAÇÃO
O banco de dados é um SQL Server 2008 R2, executado em um sistema Windows Server 2008 R2 com todas as atualizações mais recentes do Windows. Tanto para o sistema operacional quanto para o SQL Server.
A VM que executa o servidor de banco de dados faz parte de nossa infraestrutura de construção e é recém-criada, com base em uma imagem, é claro, todas as manhãs às 6h e destruída às 22h. Então eu sei que o SQL Server Agent e o Service são essencialmentenovoe começou todos os dias. A primeira compilação ocorre às 7h, o que dá à máquina tempo suficiente para iniciar e carregar todos os serviços.
O servidor de banco de dados está configurado para permitir um número ilimitado de conexões e Pipes Nomeados e conexões TCP estão habilitados.
A conexão com o banco de dados é feita pelosado utilizador.
Temos um instantâneo reduzido de nosso banco de dados de produção,a.mdf, que contém todas as tabelas, visualizações, procedimentos armazenados e um conjunto mínimo de dados necessários para realizar os testes.
Quando um teste de integração é executado, a configuração do teste copiaa.mdfpara a pasta DATA da nossa instalação do SQL Server comob.mdf. b.mdf é então anexado ao banco de dados usando o seguinte comando:
CREATE DATABASE Foo ON (FILENAME = N'Path\To\b.mdf') FOR ATTACH
Os testes são executados, executam operações de banco de dados e, na desmontagem do dispositivo de teste, o banco de dados é desanexado e o arquivo b.mdf é removido.
Os dois comandos a seguir são executados individualmente para realizar a desanexação:
ALTER DATABASE Foo SET SINGLE_USER WITH ROLLBACK IMMEDIATE
EXEC master.dbo.sp_detach_db @dbname = N'Foo'
Então, na prática, tenho um conjunto de equipamentos de teste com o seguinte layout:
Setup();
Test_1();
Test_2();
Test_3();
TearDown();
Cada instalação cria um novo banco de dados, executa todos os testes e remove o banco de dados para que o próximo ajuste de texto comece com um banco de dados limpo e novo.
No total, tenho cerca de 50 anexos de texto, cada um contendo 10 testes. Isso significa 50 vezes que um banco de dados é anexado e desanexado e cerca de 500 testes são executados.
O PROBLEMA
Nas últimas semanas, observei um aumento no número de compilações com falha relacionadas aos testes de integração. Eu sei que meus testes estão OK porque toda a configuração funciona perfeitamente na minha máquina local e nas máquinas dos outros desenvolvedores. É apenas o servidor de compilação que relata um 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 pesquisei no Google e sim, o login está correto. Eu sei disso porque nem sempre é o mesmo teste que falha. Se eu executar todo o conjunto de testes 10 vezes, ele falhará 8 em 10, mas o teste que relata uma falha será diferente a cada vez. A mensagem de erro é a mesma, dizendo que não é possível fazer login e às vezes também informa quenão há processo na outra extremidade do tubo.
Também verifiquei se o pipe nomeado e as conexões TCP estão habilitadas, verifiquei o número de conexões permitidas, ... verifiquei o arquivo ERRORLOG, mas ele não contém nada diretamente relacionado ao meu banco de dados.
Meu palpite é que, por algum motivo estranho, isso acontece muito rápido ou lento e não é capaz de anexar ou desconectar corretamente o banco de dados, ou é a SINGLE_USER
chamada que causa o problema. Pelo que descobri, se um teste falhar devido ao login, o arquivo b.mdf não poderá ser removido porque o arquivo parece estar em uso.
Então minha pergunta é: há mais alguma coisa que eu possa tentar? Existe um arquivo de log de erros ou uma mensagem específica que possa me fornecer mais informações? Há algo que eu possa fazer para verificar se a anexação e desanexação foram bem-sucedidas ou não? (É possível que uma falha na desconexão cause o problema de login?) A operação de desconexão é assíncrona e, portanto, é possível que ainda não tenha sido concluída quando a próxima chamada for feita?
Responder1
Primeiro problema: erro de falha de login.
É provável que seu banco de dados ainda não esteja totalmente inicializado quando os testes forem executados.
Você deve capturar isso em seu procedimento. Uma maneira fácil de fazer isso é consultar o banco de dados mestre para ver se o banco de dados de destino está instalado e funcionando.
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';
Segunda questão: nenhum processo na outra extremidade do tubo.
O erro por trás disso geralmente fica oculto se você não se conectar por meio de TCP/IP.
Você pode tentar ativar conexões IP diretas ou focar nos outros erros, é provável que sejam eles que estão causando esse erro.