Skip to content

Commit

Permalink
Add push and pull handlers (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
Gitii authored Mar 10, 2023
1 parent 4008ec8 commit 439f68b
Show file tree
Hide file tree
Showing 13 changed files with 277 additions and 31 deletions.
2 changes: 2 additions & 0 deletions src/Infra/CommandHandler/CommandHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ public class CommandHandlers: ICommandHandlers
{ Command.SetWindowSize, new SetWindowSizeHandler() },
{ Command.TakeScreenshot, new TakeScreenshotHandler() },
{ Command.ClickOnElement, new ClickHandler() },
{ Command.DevicePushFile, new DevicePushFileHandler() },
{ Command.DevicePullFile, new DevicePullFileHandler() }
};

public object ExecuteCommand(Command command, ISessionManager sessionManager, string sessionId, object req, string elementId)
Expand Down
2 changes: 2 additions & 0 deletions src/Infra/CommandHandler/ICommandHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ public enum Command
MaximizeWindow,
TakeScreenshot,
ClickOnElement,
DevicePushFile,
DevicePullFile
}

public interface ICommandHandlers
Expand Down
46 changes: 46 additions & 0 deletions src/Infra/CommandHandler/SessionHandlers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using WinAppDriver.Infra.Communication;
using WinAppDriver.Infra.Result;
using System;
using System.IO;

namespace WinAppDriver.Infra.CommandHandler
{
Expand Down Expand Up @@ -248,4 +249,49 @@ protected override object ExecuteSessionCommand(ISessionManager sessionManager,
return null;
}
}

public class DevicePushFileHandler : SessionCommandHandlerBase<PathFileReq, object>
{
protected override object ExecuteSessionCommand(ISessionManager sessionManager, ISession session, PathFileReq req, string elementId)
{
if (string.IsNullOrWhiteSpace(req.path))
{
throw new ArgumentException($"Invalid path: Null or whitespace");
}

if (string.IsNullOrWhiteSpace(req.data))
{
throw new ArgumentException($"Invalid file content: Null or whitespace");
}

byte[] fileContent = Convert.FromBase64String(req.data);

string directory = Path.GetDirectoryName(req.path);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}

File.WriteAllBytes(req.path, fileContent);
return null;
}
}

public class DevicePullFileHandler : SessionCommandHandlerBase<PathFileReq, string>
{
protected override string ExecuteSessionCommand(ISessionManager sessionManager, ISession session, PathFileReq req, string elementId)
{
if (string.IsNullOrWhiteSpace(req.path))
{
throw new ArgumentException($"Invalid path: Null or whitespace");
}

if (!File.Exists(req.path))
{
throw new FileNotFoundException("The requested file doesn't exist.", req.path);
}

return Convert.ToBase64String(File.ReadAllBytes(req.path));
}
}
}
8 changes: 4 additions & 4 deletions src/Infra/Infra.csproj
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<RootNamespace>WinAppDriver.Infra</RootNamespace>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.0" />
<PackageReference Include="Microsoft.Windows.Apps.Test" Version="1.0.181205002" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="System.Drawing.Common" Version="5.0.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
<PackageReference Include="System.Drawing.Common" Version="7.0.0" />
</ItemGroup>

</Project>
6 changes: 6 additions & 0 deletions src/Infra/Request/SessionReqs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,10 @@ public class SizeReq

public double height;
}

public class PathFileReq
{
public string path { get; set; }
public string data { get; set; }
}
}
14 changes: 14 additions & 0 deletions src/WinAppDriver/Controllers/SessionController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,20 @@ public IActionResult UnknownDelete(string sessionId)
return ExecuteCommand(Command.UnknownCommand, sessionId, null, null);
}

[HttpPost]
[Route("{sessionId}/appium/device/push_file")]
public IActionResult SessionDevicePushFile(string sessionId, [FromBody] object content)
{
return ExecuteCommand(Command.DevicePushFile, sessionId, content, null);
}

[HttpPost]
[Route("{sessionId}/appium/device/pull_file")]
public IActionResult SessionDevicePullFile(string sessionId, [FromBody] object content)
{
return ExecuteCommand(Command.DevicePullFile, sessionId, content, null);
}

[HttpPost]
[Route("{sessionId}/moveto")]
public IActionResult SessionMoveTo(string sessionId, [FromBody] object content)
Expand Down
10 changes: 5 additions & 5 deletions src/WinAppDriver/WinAppDriver.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>
<Version Condition=" '$(Version)' == '' ">0.2.2.0</Version>
<AssemblyVersion>$(Version)</AssemblyVersion>
<FileVersion>$(Version)</FileVersion>
Expand All @@ -11,10 +11,10 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.1.9" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="1.3.5" />
<PackageReference Include="NSwag.AspNetCore" Version="13.8.2" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="2.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="6.0.14" />
<PackageReference Include="Microsoft.IO.RecyclableMemoryStream" Version="2.3.2" />
<PackageReference Include="NSwag.AspNetCore" Version="13.18.2" />
<PackageReference Include="Serilog.Extensions.Logging.File" Version="3.0.0" />
</ItemGroup>

<ItemGroup>
Expand Down
2 changes: 1 addition & 1 deletion src/WinAppDriver/publish.bat
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
del /f /q /s bin\Release\netcoreapp3.1\win-x64
del /f /q /s bin\Release\net6.0\win-x64
dotnet publish -c Release -r win-x64
22 changes: 14 additions & 8 deletions test/Infra.UnitTest/Infra.UnitTest.csproj
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="Moq" Version="4.14.7" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="coverlet.collector" Version="1.2.0" />
<PackageReference Include="FluentAssertions" Version="6.10.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="7.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="Moq" Version="4.18.4" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
160 changes: 160 additions & 0 deletions test/WinAppDriver.IntegrationTest/DeviceTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
using FluentAssertions;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor;
using Newtonsoft.Json.Linq;
using WinAppDriver.Infra;
using WinAppDriver.Infra.Request;
using WinAppDriver.Infra.Result;
using Xunit;

namespace WinAppDriver.IntegrationTest
{
[Collection("Sequential")]
public class DeviceTest: IDisposable
{
public readonly string _tempDirectory;
public readonly string _uniqueTempDirectory;

public DeviceTest()
{
_tempDirectory = Path.GetTempPath();
_uniqueTempDirectory = Path.Combine(_tempDirectory, Guid.NewGuid().ToString());

Directory.CreateDirectory(_uniqueTempDirectory);
}

[Theory]
[InlineData("file.bin")]
[InlineData("foo\\bar\\file.bin")]
public async Task Test_PushFile_UploadFileToRemote(string partialFilePath)
{
using (var client = new TestClientProvider().Client)
{
var sessionId = await Helpers.CreateNewSession(client, AppIds.WinVer);
sessionId.Should().NotBeNullOrEmpty();

try
{
var fileContent = Guid.NewGuid().ToByteArray();
var filePath = Path.Combine(_uniqueTempDirectory, partialFilePath);

var res = await Helpers.PostSessionMessage<object, PathFileReq>(client, sessionId, "appium/device/push_file",
new PathFileReq() { data = Convert.ToBase64String(fileContent), path = filePath });

res.statusCode.Should().Be(HttpStatusCode.OK);

File.Exists(filePath).Should().BeTrue();
(await File.ReadAllBytesAsync(filePath)).Should().BeEquivalentTo(fileContent);
}
finally
{

await Helpers.DeletSession(client, sessionId);
}
}
}

[Theory]
[InlineData("", "content", "Invalid path: Null or whitespace")] // path empty
[InlineData("C:\\file.bin", "", "Invalid file content: Null or whitespace")] // empty content
[InlineData("C:\\file.bin", "???????", "The input is not a valid Base-64 string as it contains a non-base 64 character, more than two padding characters, or an illegal character among the padding characters.")] // invalid content
public async Task Test_PushFile_InvalidPayload(string filePath, string fileContent, string errorMessage)
{
using (var client = new TestClientProvider().Client)
{
var sessionId = await Helpers.CreateNewSession(client, AppIds.WinVer);
sessionId.Should().NotBeNullOrEmpty();

try
{
var res = await Helpers.PostSessionMessage<object, PathFileReq>(client, sessionId, "appium/device/push_file",
new PathFileReq() { data = fileContent, path = filePath });

res.statusCode.Should().Be(HttpStatusCode.InternalServerError);
res.value.Should().BeOfType<JObject>();

var resValue = (JObject)res.value;

resValue.Value<string>("error").Should().BeEquivalentTo("UnknownError");
resValue.Value<string>("message").Should().BeEquivalentTo(errorMessage);
}
finally
{
await Helpers.DeletSession(client, sessionId);
}
}
}

[Fact]
public async Task Test_PullFile_DownloadFileFromRemote()
{
using (var client = new TestClientProvider().Client)
{
var sessionId = await Helpers.CreateNewSession(client, AppIds.WinVer);
sessionId.Should().NotBeNullOrEmpty();

try
{
var fileContent = Guid.NewGuid().ToByteArray();
var filePath = Path.Combine(_uniqueTempDirectory, "file.bin");
File.WriteAllBytes(filePath, fileContent);

var res = await Helpers.PostSessionMessage<object, PathFileReq>(client, sessionId, "appium/device/pull_file",
new PathFileReq() { path = filePath });

res.statusCode.Should().Be(HttpStatusCode.OK);
res.value.Should().BeEquivalentTo(Convert.ToBase64String(fileContent));
}
finally
{

await Helpers.DeletSession(client, sessionId);
}
}
}

[Theory]
[InlineData("", "Invalid path: Null or whitespace")] // path empty
[InlineData("C:\\file.bin", "The requested file doesn't exist.")] // file doesn't exist
public async Task Test_PullFile_InvalidPayload(string filePath, string errorMessage)
{
using (var client = new TestClientProvider().Client)
{
var sessionId = await Helpers.CreateNewSession(client, AppIds.WinVer);
sessionId.Should().NotBeNullOrEmpty();

try
{
var res = await Helpers.PostSessionMessage<object, PathFileReq>(client, sessionId, "appium/device/pull_file",
new PathFileReq() { path = filePath });

res.statusCode.Should().Be(HttpStatusCode.InternalServerError);
res.value.Should().BeOfType<JObject>();

var resValue = (JObject)res.value;

resValue.Value<string>("error").Should().BeEquivalentTo("UnknownError");
resValue.Value<string>("message").Should().BeEquivalentTo(errorMessage);
}
finally
{
await Helpers.DeletSession(client, sessionId);
}
}
}

public void Dispose()
{
if (Directory.Exists(_uniqueTempDirectory))
{
Directory.Delete(_uniqueTempDirectory, true);
}
}
}
}
1 change: 1 addition & 0 deletions test/WinAppDriver.IntegrationTest/Helpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class AppIds
public const string Edge = "Microsoft.MicrosoftEdge_8wekyb3d8bbwe!MicrosoftEdge";
public const string AlarmClock = "Microsoft.WindowsAlarms_8wekyb3d8bbwe!App";
public const string Notepad = "c:\\windows\\system32\\notepad.exe";
public const string WinVer = "C:\\Windows\\System32\\winver.exe";
}
class Helpers
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
<TargetFramework>net6.0</TargetFramework>

<IsPackable>false</IsPackable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="FluentAssertions" Version="5.10.3" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="3.1.9" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
<PackageReference Include="xunit" Version="2.4.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
<PackageReference Include="FluentAssertions" Version="6.10.0" />
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="6.0.14" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.5.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
Expand Down
Loading

0 comments on commit 439f68b

Please sign in to comment.