myCSharp.de - DIE C# und .NET Community (https://www.mycsharp.de/wbb2/index.php)
- Entwicklung (https://www.mycsharp.de/wbb2/board.php?boardid=3)
-- Entwicklungs- und Laufzeitumgebung (Infrastruktur) (https://www.mycsharp.de/wbb2/board.php?boardid=50)
--- Gitlab-Runner (selfhost) und MSTest - seltsames Verhalten - wo einen Fehler melden? (https://www.mycsharp.de/wbb2/thread.php?threadid=122730)


Geschrieben von Taipi88 am 25.03.2020 um 10:17:
  Gitlab-Runner (selfhost) und MSTest - seltsames Verhalten - wo einen Fehler melden?
Hi,

vorab - für mehr Details - ich hatte bereits im Gitlab-Forum nachgefragt (siehe somit  https://forum.gitlab.com/t/gitlab-runner-trying-to-open-and-listen-on-a-port-using-mstest-netcore-for-smtp/35585)

Grundlegend geht es um Folgendes:
Ich schreibe UnitTests die auch SMTP testen sollen - deshalb verwende ich quasi eine Minimalimplementierung eines SMTP-Servers (nDumbsterCore). Lokal - funkioniert das hervorragend - im Gitlab-Runner gibt's ein Timeout nach dem Entdecken der Tests ohne mir die Möglichkeit zu geben auch nur den geringsten Output zu erhalten.

Ursprünglich dachte ich, dass entweder das öffnen oder das verbinden zu einem so geöffneten Port Ärger mit sich bringt. Wie es scheint - ist das nicht der Fall. Denn das hinzufügen von "-t" zu dotnet test - genügt um den Test laufen zu lassen. Sogar parallelisiert.

Für mich steht fest: Das darf kein solches Problem beheben.

Die Fragen die sich mir nun stellen:
a) Warum behebt dieses Flag das Problem?
b) Stell ich mich selbst doof an?
c) Falls b) nicht zutrifft - wo kann ich ein entsprechendes Issue melden?
Gitlab oder eher Microsoft? (und wo genau?)

Für den Fall, dass jemand die Muße hat mein Problem nachzustellen:
a) Eine kurze C#-Klasse, welche genügt um im Gitlab-Runner ein Timeout auszulösen
Datei: MailTest.cs

C#-Code:
using MailKit.Net.Smtp;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using MimeKit;
using MimeKit.Text;
using nDumbsterCore.smtp;

namespace FluiTec.AppFx.Networking.Mail.Tests
{
    [TestClass]
    public class MailTest
    {
        [TestMethod]
        public void DoMailTest()
        {
            var server = SimpleSmtpServer.Start(25);

            using (var client = new SmtpClient())
            {
                client.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => true; // accepts all certs
                client.Connect("127.0.0.1", 25, false);
                client.AuthenticationMechanisms.Remove("XOAUTH2");
                client.Send(new MimeMessage
                {
                    From = { new MailboxAddress("Test", "[email protected]example.com") },
                    To = { new MailboxAddress("Test", "[email protected]") },
                    Subject = "Subject",
                    Body = new TextPart(TextFormat.Plain)
                });
            }

            server.Stop();
        }
    }
}

b) Eine CI-Yaml-Datei um das Problem zu demonstrieren
Datei: .gitlab-ci.yml

Code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
image: mcr.microsoft.com/dotnet/core/sdk:3.1

stages:
    - build
    - test

variables:
    srcDir: "src"
    
before_script:
    - "cd $srcDir"
    - "dotnet restore"

build:
    stage: build
    script:
        - "dotnet build"
        
test:
    stage: test
    script:
        - "dotnet test" # funktioniert nicht (Timeout)
        - "dotnet test -t" # funktioniert (kein Timeout)

LG


Geschrieben von Abt am 25.03.2020 um 13:14:
 
Zunächst Tipps:

- Deaktivier Restore, wenn Du manuell einen Restore antriggerst
- Deaktivier Auto-Build, wenn Du manuell den Build antriggerst

Das sind jeweils die --no-restore und --no-build Argumente.
Besonders bei .NET 2 hat das einige Issues gelöst

Beispiel (jedoch Azure DevOps, ich nutz kein GitLab):

Code (https://github.com/BenjaminAbt/AzureDevOps-YamlBuildSamples/blob/master/DotNetCore-NuGet/build/azure-pipelines-steps.dotnet-nuget.yml):
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
- task: [email protected]
  displayName: "NuGet Restore"
  inputs:
    restoreSolution: '**/*.csproj'
    feedsToUse: config
    nugetConfigPath: NuGet.config

- task: [email protected]
  displayName: ".NET build"
  inputs:
    projects: '**/*.csproj'
    arguments: --configuration ${{ parameters.buildConfiguration }} --no-restore

- task: [email protected]
  displayName: ".NET test"
  inputs:
    command: test
    projects: 'tests/**/*.csproj'
    arguments: --no-restore --no-build

Zitat:
Denn das hinzufügen von "-t" zu dotnet test - genügt um den Test laufen zu lassen. Sogar parallelisiert.

Dein -t (Alias für --list-tests) Parameter führt dazu, dass keine Tests ausgeführt werden.
Das listet nur die Tests auf.

D.h., dass der Fehler selbst im Test sein dürfte; damit nicht Sache von GitLab ist.

Ich würde behaupten, dass client.Connect so nicht funktionieren wird.
Die Methode blockt, weil sie nicht verbinden kann. Das wird demnach 2 potentielle Resultate haben:

- Du rennst in den Connection Timeout, gibt eine Exception
- Du rennst in den Test Timeout, der Prozess wird abgeschossen

Vermutlich ist das Connection Timeout höher; damit greift das Test Timeout und Du bekommst Dein Fehler.

PS: das ist kein Unit Test, sondern ein Integrationstest.
Ein Unit Test hat keine externe Abhängigkeit.

Im Endeffekt hat der Integrationstest kein wirklichen Mehrwert. Die Aussagekraft ist nicht vorhanden.
Nur weil der Integrationstest gegen nDumbsterCore funktioniert, heisst das noch lange nicht, dass das gegen den produktiven SMTP funktioniert.


Geschrieben von Taipi88 am 25.03.2020 um 17:48:
 
Hi,

vielen Dank für die Antwort und die Tipps.

Ok - dass damit keine Tests ausgeführt werden war mir nicht bewusst. Schade.

Nunja - dass der Fehler im Test liegt - ich führe diese ganzen Tests ja auch lokal aus - vollkommen ohne jedes Problem - und alle erfolgreich. (Dort führe ich das ganze per VS/ReShaper aus) Demnach sollte der Fehler doch eher in der Umgebung zu suchen sein. Korrekt? (Ist auch nicht so, als ob ich die Tests nur auf dem Server ausführe...)

Habe mal die Änderungen am CI vorgenommen und ein Timeout für den Client gesetzt.
Vom Grundprinzip hast du Recht - es ist ein Timeout, dass beim Connecten auftritt.
Aber wieso tritt das lokal nicht auf - aber auf diesem Docker-System?

Fehlermeldung:
X DoMailTest [185ms]
Error Message:
Test method FluiTec.AppFx.Networking.Mail.Tests.MailTest.DoMailTest threw exception:
System.IO.IOException: Connection timed out ---> System.Net.Sockets.SocketException: Connection timed out
Stack Trace:
at System.Net.Sockets.Socket.Receive(Byte[] buffer, Int32 offset, Int32 size, SocketFlags socketFlags)
at MailKit.Net.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 count)
--- End of inner exception stack trace ---
at MailKit.Net.NetworkStream.Read(Byte[] buffer, Int32 offset, Int32 count)
at MailKit.Net.Smtp.SmtpStream.ReadAheadAsync(Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpStream.ReadResponseAsync(Boolean doAsync, CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpStream.ReadResponse(CancellationToken cancellationToken)
at MailKit.Net.Smtp.SmtpClient.DataAsync(FormatOptions options, MimeMessage message, Int64 size, Boolean doAsync, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.Net.Smtp.SmtpClient.SendAsync(FormatOptions options, MimeMessage message, MailboxAddress sender, IList`1 recipients, Boolean doAsync, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.Net.Smtp.SmtpClient.Send(FormatOptions options, MimeMessage message, CancellationToken cancellationToken, ITransferProgress progress)
at MailKit.MailTransport.Send(MimeMessage message, CancellationToken cancellationToken, ITransferProgress progress)
at FluiTec.AppFx.Networking.Mail.Tests.MailTest.DoMailTest() in /builds/fluitec/fluitec.appfx.networking/src/tests/FluiTec.AppFx.Networking.Mail.Tests/MailTest.cs:line 23

Am öffnen des Ports scheint es ja nicht zu hapern - warum also beim verbinden?

Was den Integrationstest angeht - ja das ist kein feiner UnitTest - grundlegend hatte ich aber hier die Optionen einen SmtpClient zu mocken (der in meinem Teil der API bislang gar nicht öffentlich zur Verfügung steht) und dort zu validieren - oder eben einen simplen SmtpService anzubieten, der eine Validierung erlaubt.

In anderen Worten: Du empfiehlst somit eher dem Client zu mocken?

LG und Vielen Dank

PS: Nunja - ein funktionierendes Verhalten gegenüber dem nDumbsterCore hat mir durchaus einen Mehrweg gebracht. Hab schnell gesehen, dass ich einige Paramter bei der Weitergabe getauscht hatte. Sicher - das ist kein echter SMTP-Server und soll es auch niemals werden, da ich gar keine Mails verschicken möchte in simplen Tests. Auf der anderen Seite verhält sich auch nicht jeder SMTP-Server wie der andere, womit ein solcher Test besser als nichts - aber auch sicher weniger gut als das Produktivsystem ist...


Geschrieben von Abt am 25.03.2020 um 18:10:
 
Zitat:
Am öffnen des Ports scheint es ja nicht zu hapern - warum also beim verbinden?

Da ich keine Glaskugel hab, kann ich das nicht sagen.
Einfachste Antwort immer: da ist halt was nicht richtig konfiguriert.

Zitat:
In anderen Worten: Du empfiehlst somit eher dem Client zu mocken?

Willst Du ein Unit Test, dann musst Du den Client mocken, richtig.


Geschrieben von david.m am 25.03.2020 um 18:35:
 
Woher weißt Du das es nicht am öffnen des Port liegt?

Versuch mal ein Port größer 1024, kleinere dürfen nur von root geöffnet werden.

 Liste der standardisierten Ports


Geschrieben von Taipi88 am 25.03.2020 um 19:09:
 
@Abt - ich leider auch nicht - ich hatte nur gehofft jemand hätte mal versucht auf dem Standard-MS-Image sich simpel mit einem Port zu verbinden.

@david.m
Hatte es bislang nicht erwähnt - aber mit einer der ersten Tests meinerseits war das simple Öffnen eines Ports, was problemlos durchging. (Auch ohne "-t"^^)
Zusätzlich hatte ich den UnitTest auch mal mit Port 50.000 ausgeführt.
Trotzdem Danke :)

LG

PS:
Ich denke das weitere Verfolgen dieses Anliegens wird hier keinen so großen Zweck haben. Wenn keiner SMTP auf diese Art testet ist das wohl einfach nicht die Art, wie man das Problem angeht. (Wollte ja nur gründlich sein) Hab meine eigentlichen Klassen und UnitTests (diesmal wirklich) nun so umgeschrieben, dass alles was nicht gerade wirklich getestet wird per Moq gemockt wird. (Obwohl ich noch "etwas" an der Verifizierung eines IMailTransport.Send knabbere - das wird aber schon noch)


© Copyright 2003-2020 myCSharp.de-Team | Impressum | Datenschutz | Alle Rechte vorbehalten. | Dieses Portal verwendet zum korrekten Betrieb Cookies. 09.04.2020 19:26