Integrações entre Sistemas – Parte 2 – Setup

Objetivo

Nesta parte, veremos como configurar todo o ambiente para executar os testes apresentados na primeira parte.

Configurando banco de dados

Para realizarmos os testes necessários, será necessário primeiro criar um ambiente. O primeiro passo é criar um novo database no SQL Server e as tabelas necessárias:

create table ServiceTable (
  ServiceTableID int not null,
  DescServiceTable varchar(200) not null,
  Value float not null,
  CreationDate datetime not null,
  StringField1 varchar(200),
  StringField2 varchar(200),
  constraint PK_ServiceTable primary key (ServiceTableID) 
)

create table ClientTable (
  ClientTableID int not null,
  DescClientTable varchar(200) not null,
  Value float not null,
  CreationDate datetime not null,
  StringField1 varchar(200),
  StringField2 varchar(200),
  constraint PK_ClientTable primary key (ClientTableID) 
)

Usaremos duas tabelas bem simples, somente para ilustrar o problema. Nosso objetivo não é exercitar conceitos de modelagem de banco de dados.

Esse database e tabelas devem ser criados tanto no cliente quanto no servidor.

Criando uma massa de dados

Para simplificar todo o controle e execução dos programas utilizados nestes exemplos, utilizei o MSBuild, devido à grande quantidade de parâmetros e configurações necessárias.

Para criar a massa de dados, criei uma task MSBuild “DataGeneration”:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;
using Microsoft.Build.Utilities;
using Microsoft.Build.Framework;

namespace IntegrationTests.TestClasses.Util
{
    public class DataGeneration : Task
    {
        [Required]
        public string ConnString
        {
            get;
            set;
        }

        public override bool Execute()
        {
            SqlConnection conn = new SqlConnection(ConnString);
            conn.Open();

            SqlCommand cmd = new SqlCommand("insert into ServiceTable (ServiceTableID, DescServiceTable, Value, CreationDate, StringField1, StringField2)" +
                "values (@ServiceTableID, @DescServiceTable, @Value, @CreationDate, @StringField1, @StringField2)", conn);

            using (conn)
            {

                SqlParameter p1 = cmd.Parameters.Add("@ServiceTableID", SqlDbType.Int);
                SqlParameter p2 = cmd.Parameters.Add("@DescServiceTable", SqlDbType.VarChar, 200);
                SqlParameter p3 = cmd.Parameters.Add("@Value", SqlDbType.Float);
                SqlParameter p4 = cmd.Parameters.Add("@CreationDate", SqlDbType.DateTime);
                SqlParameter p5 = cmd.Parameters.Add("@StringField1", SqlDbType.VarChar, 200);
                SqlParameter p6 = cmd.Parameters.Add("@StringField2", SqlDbType.VarChar, 200);

                Random r = new Random();

                int count = 0;                
                for (int i = 1; i <= 2000000; i++)
                {
                    p1.Value = i;
                    p2.Value = "Server Value " + i.ToString();
                    p3.Value = r.Next();
                    p4.Value = DateTime.Now;
                    p5.Value = "Useless Field 1: " + r.Next().ToString();
                    p6.Value = "Useless Field 1: " + r.Next().ToString();

                    cmd.ExecuteNonQuery();

                    count++;
                    if (count >= 1000)
                    {
                        count = 0;
                        Log.LogMessage("Generated " + i.ToString() + "/2000000 records");
                    }
                }

                return true;
            }
        }
    }
}

O objetivo aqui é simples, gerar 2 milhões de registros para realizar o teste. Esse procedimento precisa ser executado somente na máquina servidora. O batch “generatedata” executa este procedimento. Não esqueça de atualizar a propriedade “ConnString”. Pode ser tanto via parâmetro no arquivo .bat ou dentro do arquivo IntegrationTests.build.

Caso tenha alguma dúvida sobre MSBuild: MSBuild in a Nutshell.

Configurando o serviço WCF

O serviço precisa ser configurado apenas na máquina servidora. Entre na console de administração do IIS (inetmgr). Dentro do seu Default Web Site, crie um novo aplicativo.

  • Alias: integrationtests
  • Pool de aplicativos: DefaultAppPool (v.4.0, Integrated)
  • Caminho físico: Apontar para a raiz do projeto IntegrationTests.WCFServiceApp
  • Habilitar endpoint net.tcp: Entrar em configurações avançadas da nova aplicação, na propriedade “protocolos habilitados”, preencher com http,net.tcp

As configurações do serviço WCF modificadas. Foram criados os bindings net.tcp e http e a segurança foi desabilitada para evitar problemas entre as duas máquinas. A configuração proposta foi:

  <system.serviceModel>
    <bindings>
      <netTcpBinding> 
        <binding name="nettcp1" closeTimeout="00:10:00" maxReceivedMessageSize="65536000" transferMode="Buffered">
          <security mode="None">
            <transport clientCredentialType="None" protectionLevel="None" />
            <message clientCredentialType="None" />
          </security>
        </binding>
      </netTcpBinding>

    </bindings>
    <services>
      <service name="IntegrationTests.WCFServiceApp.IntegrationTestsService">
        <endpoint binding="netTcpBinding" bindingConfiguration="nettcp1" name="nettcp1"
          contract="IntegrationTests.WCFServiceApp.IIntegrationTestsService" />
        <endpoint binding="basicHttpBinding" bindingConfiguration="" name="basicHTTP"
          contract="IntegrationTests.WCFServiceApp.IIntegrationTestsService" />
      </service>
    </services>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information, set the value below to false and remove the metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, set the value below to true.  Set to false before deployment to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>

Nada impede dessas configurações serem modificadas para atender requisitos do seu ambiente.

Outro ponto importante é corrigir a conexão de banco de dados na web.config do servidor:

<appSettings>
    <add key="ConnString"  value=""/>
 </appSettings>

Propriedades do MSBuild

O script do MSBuild criado funciona tanto para o servidor quanto o cliente, mas algumas propriedades precisam ser modificadas para refletir as configurações do cliente e do servidor:

  • Máquina servidor
    • ConnString: Configurar apontando para a base criada no início do post, na máquina servidora
    • InputDir: Local onde o servidor vai ficar ouvindo os arquivos de requisição enviados pelo cliente. Configurar um diretório temporário local (Ex.: C:\Shared
    • OutputDir: Local onde o servidor vai jogar os arquivos para o cliente. Configurar para um diretório temporário local (Ex.: C:\Shared)
  • Máquina cliente
    • ConnString: Configurar apontando para a base criada no início do post, na máquina cliente
    • OutputDir: Local onde o cliente vai jogar os arquivos de requisição para o servidor. Configurar para um diretório de rede mapeado para o InputDir da máquina servidora.
    • InputDir: Local onde o cliente vai esperar a resposta do servidor. Configurar para um diretório de rede mapeado para o OutputDir da máquina servidora.
    • WebServiceUri: http://server-ip-address/integrationtests/IntegrationTestsService.svc
    • NetTcpUri: net.tcp://server-ip-address/integrationtests/IntegrationTestsService.svc

Executando testes

Antes de executar, sempre execute o bat runservers (internamente target RunServers) na máquina server antes, senão obviamente o cliente vai ficar esperando um arquivo que nunca vai chegar. Implementei o lado servidor também como uma task MSBuild para o caso dos arquivos. É totalmente inapropriada a implementação que eu fiz, mas pra esse propósito (testar os tempos), funciona bem.

A target MSBuild RunClientTests executa os testes (file transfer, web service linha a linha e web service em lotes) num cenário de 20.000 registros. É bom para saber se está tudo funcionando.

A target MSBuild RunAllClientTestes executa todos os testes, 5 vezes, em cenários de 20.000, 50.000, 500.000 e 1 milhão de registros. É óbvio que o RunAllClientTests vai demorar bem mais, porém, o objetivo dele é tirar métricas mais precisas em execuções constantes dos testes para obter resultados médios. Por questões dos caches de banco de dados, consumo memória, etc., as execuções podem variar.

Código fonte

O código fonte está disponível no git hub: https://github.com/ericlemes/IntegrationTests.

Conclusão

Este post tem objetivo somente fornecer o código fonte e explicar todo o setup de ambiente. Nos posts posteriores, vou explicar em mais detalhes cada uma dos testes realizados para que o método fique mais claro.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s