Skip to content

Commit

Permalink
Merge branch 'main' into timespan
Browse files Browse the repository at this point in the history
  • Loading branch information
mycroes authored Aug 3, 2023
2 parents 49e4d33 + 7e631a7 commit 55aa06a
Show file tree
Hide file tree
Showing 22 changed files with 581 additions and 103 deletions.
54 changes: 13 additions & 41 deletions .github/workflows/dotnet.yml
Original file line number Diff line number Diff line change
Expand Up @@ -64,77 +64,49 @@ jobs:
${{ env.NuGetDirectory }}/*.snupkg
run_test:
name: test-${{ matrix.os }}-${{ matrix.test-framework }}
name: test-${{ matrix.os }}
runs-on: ${{ matrix.os }}
env:
configuration: Release
artifacts: ${{ github.workspace }}/artifacts
strategy:
matrix:
os: [windows-latest, ubuntu-22.04, macos-latest]
test-framework: [net6.0, net7.0]
include:
- os: ubuntu-22.04
test-framework: net6.0
installSnap7: true
dotnet-sdk: '6.x'
- os: ubuntu-22.04
test-framework: net7.0
installSnap7: true
dotnet-sdk: '7.x'
- os: macos-latest
test-framework: net6.0
installSnap7: true
dotnet-sdk: '6.x'
- os: macos-latest
test-framework: net7.0
installSnap7: true
dotnet-sdk: '7.x'
- os: windows-latest
test-framework: net6.0
dotnet-sdk: '6.x'
- os: windows-latest
test-framework: net7.0
dotnet-sdk: '7.x'
- os: windows-latest
test-framework: net462
dotnet-sdk: '7.x'
os: [windows-latest, ubuntu-20.04, macos-latest]
fail-fast: false

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3

- name: Install Snap7 Linux
if: ${{ matrix.installSnap7 && matrix.os == 'ubuntu-20.04' }}
if: ${{ matrix.os == 'ubuntu-20.04' }}
run: |
sudo add-apt-repository ppa:gijzelaar/snap7
sudo apt-get update
sudo apt-get install libsnap7-1 libsnap7-dev
- name: Install Snap7 MacOs
if: ${{ matrix.installSnap7 && matrix.os == 'macos-latest' }}
if: ${{ matrix.os == 'macos-latest' }}
run: |
brew install snap7
- name: Setup Dotnet
uses: actions/setup-dotnet@v1
uses: actions/setup-dotnet@v3
with:
dotnet-version: ${{ matrix.dotnet-sdk }}
dotnet-version: |
6.x
7.x
- name: Nuget Cache
uses: actions/cache@v2
uses: actions/cache@v3
with:
path: ~/.nuget/packages
# Look to see if there is a cache hit for the corresponding requirements file
key: ${{ runner.os }}-${{ matrix.test-framework }}-nuget-${{ hashFiles('**/packages.lock.json') }}
key: ${{ runner.os }}-nuget-${{ hashFiles('**/packages.lock.json') }}
restore-keys: |
${{ runner.os }}-${{ matrix.test-framework }}-nuget
- name: Restore
run: dotnet restore S7.Net.UnitTest
${{ runner.os }}-nuget
- name: Test
run: dotnet test --no-restore --nologo --verbosity normal --logger GitHubActions --framework ${{ matrix.test-framework }}
run: dotnet test --nologo --verbosity normal --logger GitHubActions

deploy:
# Publish only when creating a GitHub Release
Expand Down
28 changes: 28 additions & 0 deletions S7.Net.UnitTest/CommunicationTests/ConnectionOpen.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using System.Net;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using S7.Net.Protocol;

namespace S7.Net.UnitTest.CommunicationTests;

[TestClass]
public class ConnectionOpen
{
[TestMethod]
public async Task Does_Not_Throw()
{
var cs = new CommunicationSequence {
ConnectionOpenTemplates.ConnectionRequestConfirm,
ConnectionOpenTemplates.CommunicationSetup
};

async Task Client(int port)
{
var conn = new Plc(IPAddress.Loopback.ToString(), port, new TsapPair(new Tsap(1, 2), new Tsap(3, 4)));
await conn.OpenAsync();
conn.Close();
}

await Task.WhenAll(cs.Serve(out var port), Client(port));
}
}
107 changes: 107 additions & 0 deletions S7.Net.UnitTest/CommunicationTests/ConnectionOpenTemplates.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
namespace S7.Net.UnitTest.CommunicationTests;

internal static class ConnectionOpenTemplates
{
public static RequestResponsePair ConnectionRequestConfirm { get; } = new RequestResponsePair(
"""
// TPKT
03 // Version
00 // Reserved
00 16 // Length
// CR
11 // Number of bytes following
E0 // CR / Credit
00 00 // Destination reference, unused
__ __ // Source reference, unused
00 // Class / Option
// Source TSAP
C1 // Parameter code
02 // Parameter length
TSAP_SRC_CHAN // Channel
TSAP_SRC_POS // Position
// Destination TSAP
C2 // Parameter code
02 // Parameter length
TSAP_DEST_CHAN // Channel
TSAP_DEST_POS // Position
// PDU Size parameter
C0 // Parameter code
01 // Parameter length
0A // 1024 byte PDU (2 ^ 10)
""",
"""
// TPKT
03 // Version
00 // Reserved
00 0B // Length
// CC
06 // Length
D0 // CC / Credit
00 00 // Destination reference
00 00 // Source reference
00 // Class / Option
"""
);

public static RequestResponsePair CommunicationSetup { get; } = new RequestResponsePair(
"""
// TPKT
03 // Version
00 // Reserved
00 19 // Length
// Data header
02 // Length
F0 // Data identifier
80 // PDU number and end of transmission
// S7 header
32 // Protocol ID
01 // Message type job request
00 00 // Reserved
PDU1 PDU2 // PDU reference
00 08 // Parameter length (Communication Setup)
00 00 // Data length
// Communication Setup
F0 // Function code
00 // Reserved
00 03 // Max AMQ caller
00 03 // Max AMQ callee
03 C0 // PDU size (960)
""",
"""
// TPKT
03 // Version
00 // Reserved
00 1B // Length
// Data header
02 // Length
F0 // Data identifier
80 // PDU number and end of transmission
// S7 header
32 // Protocol ID
03 // Message type ack data
00 00 // Reserved
PDU1 PDU2 // PDU reference
00 08 // Parameter length (Communication Setup)
00 00 // Data length
00 // Error class
00 // Error code
// Communication Setup
F0 // Function code
00 // Reserved
00 03 // Max AMQ caller
00 03 // Max AMQ callee
03 C0 // PDU size (960)
"""
);
}
57 changes: 57 additions & 0 deletions S7.Net.UnitTest/CommunicationTests/ReadPlcStatus.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Net;
using System.Threading.Tasks;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using S7.Net.Protocol;

namespace S7.Net.UnitTest.CommunicationTests;

[TestClass]
public class ReadPlcStatus
{
[TestMethod]
public async Task Read_Status_Run()
{
var cs = new CommunicationSequence {
ConnectionOpenTemplates.ConnectionRequestConfirm,
ConnectionOpenTemplates.CommunicationSetup,
{
"""
// TPKT
03 00 00 21
// COTP
02 f0 80
// S7 SZL read
32 07 00 00 PDU1 PDU2 00 08 00 08 00 01 12 04 11 44
01 00 ff 09 00 04 04 24 00 00
""",
"""
// TPKT
03 00 00 3d
// COTP
02 f0 80
// S7 SZL response
32 07 00 00 PDU1 PDU2 00 0c 00 20 00 01 12 08 12 84
01 02 00 00 00 00 ff 09 00 1c 04 24 00 00 00 14
00 01 51 44 ff 08 00 00 00 00 00 00 00 00 14 08
20 12 05 28 34 94
"""
}
};

async Task Client(int port)
{
var conn = new Plc(IPAddress.Loopback.ToString(), port, new TsapPair(new Tsap(1, 2), new Tsap(3, 4)));
await conn.OpenAsync();
var status = await conn.ReadStatusAsync();

Assert.AreEqual(0x08, status);
conn.Close();
}

await Task.WhenAll(cs.Serve(out var port), Client(port));
}
}
7 changes: 7 additions & 0 deletions S7.Net.UnitTest/Framework/IsExternalInit.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
using System.ComponentModel;

namespace System.Runtime.CompilerServices
{
[EditorBrowsable(EditorBrowsableState.Never)]
internal record IsExternalInit;
}
82 changes: 82 additions & 0 deletions S7.Net.UnitTest/Infrastructure/CommunicationSequence.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
using System;
using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace S7.Net.UnitTest;

internal class CommunicationSequence : IEnumerable<RequestResponsePair>
{
private readonly List<RequestResponsePair> _requestResponsePairs = new List<RequestResponsePair>();

public void Add(RequestResponsePair requestResponsePair)
{
_requestResponsePairs.Add(requestResponsePair);
}

public void Add(string requestPattern, string responsePattern)
{
_requestResponsePairs.Add(new RequestResponsePair(requestPattern, responsePattern));
}

public IEnumerator<RequestResponsePair> GetEnumerator()
{
return _requestResponsePairs.GetEnumerator();
}

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

public Task Serve(out int port)
{
var socket = CreateBoundListenSocket(out port);
socket.Listen(0);

async Task Impl()
{
await Task.Yield();
var socketIn = socket.Accept();

var buffer = ArrayPool<byte>.Shared.Rent(1024);
try
{
foreach (var pair in _requestResponsePairs)
{
var bytesReceived = socketIn.Receive(buffer, SocketFlags.None);

var received = buffer.Take(bytesReceived).ToArray();
Console.WriteLine($"=> {BitConverter.ToString(received)}");

var response = Responder.Respond(pair, received);

Console.WriteLine($"<= {BitConverter.ToString(response)}");
socketIn.Send(response);
}
}
finally
{
ArrayPool<byte>.Shared.Return(buffer);
}

socketIn.Close();
}

return Impl();
}

private static Socket CreateBoundListenSocket(out int port)
{
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var endpoint = new IPEndPoint(IPAddress.Loopback, 0);

socket.Bind(endpoint);

var localEndpoint = (IPEndPoint)socket.LocalEndPoint!;
port = localEndpoint.Port;

return socket;
}
}
3 changes: 3 additions & 0 deletions S7.Net.UnitTest/Infrastructure/RequestResponsePair.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
namespace S7.Net.UnitTest;

internal record RequestResponsePair(string RequestPattern, string ResponsePattern);
Loading

0 comments on commit 55aa06a

Please sign in to comment.