Skip to content

Commit

Permalink
Merge branch 'trunk' into update-htmlunit
Browse files Browse the repository at this point in the history
  • Loading branch information
diemol authored Dec 8, 2023
2 parents 0b10a64 + 6620bce commit b852506
Show file tree
Hide file tree
Showing 9 changed files with 212 additions and 32 deletions.
50 changes: 49 additions & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,12 @@ def dotnet_version
end
end

def python_version
File.foreach('py/BUILD.bazel') do |line|
return line.split('=').last.strip.tr('"', '') if line.include?('SE_VERSION')
end
end

# The build system used by webdriver is layered on top of rake, and we call it
# "crazy fun" for no readily apparent reason.

Expand Down Expand Up @@ -133,7 +139,7 @@ task all: [
:"selenium-java",
'//java/test/org/openqa/selenium/environment:webserver'
]
task all_zip: [:'java-release-zip']
task all_zip: [:'java-release-zip', :'dotnet-release-zip']
task tests: [
'//java/test/org/openqa/selenium/htmlunit:htmlunit',
'//java/test/org/openqa/selenium/firefox:test-synthesized',
Expand Down Expand Up @@ -403,13 +409,55 @@ def read_m2_user_pass
return [user, pass]
end

task :prepare_release do
RELEASE_TARGETS = [
'//java/src/org/openqa/selenium:client-zip',
'//java/src/org/openqa/selenium/grid:server-zip',
'//java/src/org/openqa/selenium/grid:executable-grid',
'//dotnet/src/webdriver:webdriver-pack',
'//dotnet/src/webdriver:webdriver-strongnamed-pack',
'//dotnet/src/support:support-pack',
'//dotnet/src/support:support-strongnamed-pack',
'//javascript/node/selenium-webdriver:selenium-webdriver',
'//py:selenium-wheel',
'//py:selenium-sdist',
]

RELEASE_TARGETS.each do |target|
Bazel::execute('build', ['--config', 'release'], target)
end
Bazel::execute('build', ['--stamp'], '//rb:selenium-webdriver')
end

PYPI_ASSETS = [
"bazel-bin/py/selenium-#{python_version}-py3-none-any.whl",
"bazel-bin/py/selenium-#{python_version}.tar.gz"
]

task 'publish-pypi' do
PYPI_ASSETS.each do |asset|
sh "python3 -m twine upload #{asset}"
end
end

task 'publish-maven': JAVA_RELEASE_TARGETS do
creds = read_m2_user_pass
JAVA_RELEASE_TARGETS.each do |p|
Bazel::execute('run', ['--stamp', '--define', 'maven_repo=https://oss.sonatype.org/service/local/staging/deploy/maven2', '--define', "maven_user=#{creds[0]}", '--define', "maven_password=#{creds[1]}", '--define', 'gpg_sign=true'], p)
end
end

NUGET_RELEASE_ASSETS = [
"./bazel-bin/dotnet/src/webdriver/Selenium.WebDriver.#{dotnet_version}.nupkg",
"./bazel-bin/dotnet/src/webdriver/Selenium.Support.#{dotnet_version}.nupkg"
]

task 'publish-nuget' do
NUGET_RELEASE_ASSETS.each do |asset|
sh "dotnet nuget push #{asset} --api-key #{ENV[:NUGET_API_KEY]} --source https://api.nuget.org/v3/index.json"
end
end

task 'publish-maven-snapshot': JAVA_RELEASE_TARGETS do
creds = read_m2_user_pass
if java_version.end_with?('-SNAPSHOT')
Expand Down
4 changes: 2 additions & 2 deletions dotnet/src/webdriver/IHasDownloads.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public interface IHasDownloads
/// <summary>
/// Retrieves the downloadable files.
/// </summary>
/// <returns>A list of file names available for download.</returns>
List<string> GetDownloadableFiles();
/// <returns>A read-only list of file names available for download.</returns>
IReadOnlyList<string> GetDownloadableFiles();

/// <summary>
/// Downloads a file with the specified file name and returns a dictionary containing the downloaded file's data.
Expand Down
9 changes: 0 additions & 9 deletions dotnet/src/webdriver/Internal/Logging/ConsoleLogHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,5 @@ public void Handle(LogEvent logEvent)
{
Console.Error.WriteLine($"{logEvent.Timestamp:HH:mm:ss.fff} {_levels[(int)logEvent.Level]} {logEvent.IssuedBy.Name}: {logEvent.Message}");
}

/// <summary>
/// Creates a new instance of the <see cref="ConsoleLogHandler"/> class.
/// </summary>
/// <returns>A new instance of the <see cref="ConsoleLogHandler"/> class.</returns>
public ILogHandler Clone()
{
return this;
}
}
}
94 changes: 94 additions & 0 deletions dotnet/src/webdriver/Internal/Logging/FileLogHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.IO;

namespace OpenQA.Selenium.Internal.Logging
{
/// <summary>
/// Represents a log handler that writes log events to a file.
/// </summary>
public class FileLogHandler : ILogHandler, IDisposable
{
// performance trick to avoid expensive Enum.ToString() with fixed length
private static readonly string[] _levels = { "TRACE", "DEBUG", " INFO", " WARN", "ERROR" };

private FileStream _fileStream;
private StreamWriter _streamWriter;

private readonly object _lockObj = new object();
private bool _isDisposed;

/// <summary>
/// Initializes a new instance of the <see cref="FileLogHandler"/> class with the specified file path.
/// </summary>
/// <param name="path">The path of the log file.</param>
public FileLogHandler(string path)
{
if (string.IsNullOrEmpty(path)) throw new ArgumentException("File log path cannot be null or empty.", nameof(path));

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

_fileStream = File.Open(path, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read);
_fileStream.Seek(0, SeekOrigin.End);
_streamWriter = new StreamWriter(_fileStream, System.Text.Encoding.UTF8)
{
AutoFlush = true
};
}

/// <summary>
/// Handles a log event by writing it to the log file.
/// </summary>
/// <param name="logEvent">The log event to handle.</param>
public void Handle(LogEvent logEvent)
{
lock (_lockObj)
{
_streamWriter.WriteLine($"{logEvent.Timestamp:r} {_levels[(int)logEvent.Level]} {logEvent.IssuedBy.Name}: {logEvent.Message}");
}
}

/// <summary>
/// Disposes the file log handler and releases any resources used.
/// </summary>
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}

/// <summary>
/// Finalizes the file log handler instance.
/// </summary>
~FileLogHandler()
{
Dispose(false);
}

/// <summary>
/// Disposes the file log handler and releases any resources used.
/// </summary>
/// <param name="disposing">A flag indicating whether to dispose managed resources.</param>
protected virtual void Dispose(bool disposing)
{
lock (_lockObj)
{
if (!_isDisposed)
{
if (disposing)
{
_streamWriter?.Dispose();
_streamWriter = null;
_fileStream?.Dispose();
_fileStream = null;
}

_isDisposed = true;
}
}
}
}
}
6 changes: 0 additions & 6 deletions dotnet/src/webdriver/Internal/Logging/ILogHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,5 @@ public interface ILogHandler
/// </summary>
/// <param name="logEvent">The log event to handle.</param>
void Handle(LogEvent logEvent);

/// <summary>
/// Creates a clone of the log handler.
/// </summary>
/// <returns>A clone of the log handler.</returns>
ILogHandler Clone();
}
}
26 changes: 18 additions & 8 deletions dotnet/src/webdriver/Internal/Logging/LogContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,19 +60,16 @@ public ILogContext CreateContext(LogEventLevel minimumLevel)
loggers = new ConcurrentDictionary<Type, ILogger>(_loggers.Select(l => new KeyValuePair<Type, ILogger>(l.Key, new Logger(l.Value.Issuer, minimumLevel))));
}

IList<ILogHandler> handlers = null;
var context = new LogContext(minimumLevel, this, loggers, null);

if (Handlers != null)
{
handlers = new List<ILogHandler>(Handlers.Select(h => h.Clone()));
}
else
{
handlers = new List<ILogHandler>();
foreach (var handler in Handlers)
{
context.Handlers.Add(handler);
}
}

var context = new LogContext(minimumLevel, this, loggers, Handlers);

Log.CurrentContext = context;

return context;
Expand Down Expand Up @@ -137,6 +134,19 @@ public ILogContext SetLevel(Type issuer, LogEventLevel level)

public void Dispose()
{
// Dispose log handlers associated with this context
// if they are hot handled by parent context
if (Handlers != null && _parentLogContext != null && _parentLogContext.Handlers != null)
{
foreach (var logHandler in Handlers)
{
if (!_parentLogContext.Handlers.Contains(logHandler))
{
(logHandler as IDisposable)?.Dispose();
}
}
}

Log.CurrentContext = _parentLogContext;
}
}
Expand Down
6 changes: 3 additions & 3 deletions dotnet/src/webdriver/Remote/RemoteWebDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -471,10 +471,10 @@ public DevToolsSession GetDevToolsSession(int protocolVersion)
}

/// <summary>
/// Retrieves the downloadable files as a map of file names and their corresponding URLs.
/// Retrieves the downloadable files.
/// </summary>
/// <returns>A list containing file names as keys and URLs as values.</returns>
public List<string> GetDownloadableFiles()
/// <returns>A read-only list of file names available for download.</returns>
public IReadOnlyList<string> GetDownloadableFiles()
{
var enableDownloads = this.Capabilities.GetCapability(CapabilityType.EnableDownloads);
if (enableDownloads == null || !(bool) enableDownloads) {
Expand Down
6 changes: 3 additions & 3 deletions dotnet/test/common/DownloadsTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void CanListDownloadableFiles()
{
DownloadWithBrowser();

List<string> names = ((RemoteWebDriver) driver).GetDownloadableFiles();
IReadOnlyList<string> names = ((RemoteWebDriver) driver).GetDownloadableFiles();
Assert.That(names, Contains.Item("file_1.txt"));
Assert.That(names, Contains.Item("file_2.jpg"));
}
Expand All @@ -52,7 +52,7 @@ public void CanDownloadFile()
{
DownloadWithBrowser();

List<string> names = ((RemoteWebDriver) driver).GetDownloadableFiles();
IReadOnlyList<string> names = ((RemoteWebDriver) driver).GetDownloadableFiles();
string fileName = names[0];
string targetDirectory = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());

Expand All @@ -72,7 +72,7 @@ public void CanDeleteFiles()

((RemoteWebDriver)driver).DeleteDownloadableFiles();

List<string> names = ((RemoteWebDriver) driver).GetDownloadableFiles();
IReadOnlyList<string> names = ((RemoteWebDriver) driver).GetDownloadableFiles();
Assert.IsEmpty(names, "The names list should be empty.");
}

Expand Down
43 changes: 43 additions & 0 deletions dotnet/test/common/Internal/Logging/FileLogHandlerTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using NUnit.Framework;
using System;
using System.IO;

namespace OpenQA.Selenium.Internal.Logging
{
public class FileLogHandlerTest
{
[Test]
[TestCase(null)]
[TestCase("")]
public void ShouldNotAcceptIncorrectPath(string path)
{
var act = () => new FileLogHandler(path);

Assert.That(act, Throws.ArgumentException);
}

[Test]
public void ShouldHandleLogEvent()
{
var tempFile = Path.GetTempFileName();

try
{
using (var fileLogHandler = new FileLogHandler(tempFile))
{
fileLogHandler.Handle(new LogEvent(typeof(FileLogHandlerTest), DateTimeOffset.Now, LogEventLevel.Info, "test message"));
}

Assert.That(File.ReadAllText(tempFile), Does.Contain("test message"));
}
catch (Exception)
{
throw;
}
finally
{
File.Delete(tempFile);
}
}
}
}

0 comments on commit b852506

Please sign in to comment.