diff --git a/.gitignore b/.gitignore index a9fa766f9c8..07b440048d0 100644 --- a/.gitignore +++ b/.gitignore @@ -15,4 +15,6 @@ test-output /dist /lang/java/compiler/nbactions.xml /lang/java/compiler/nb-configuration.xml -/lang/java/compiler/nbproject/ \ No newline at end of file +/lang/java/compiler/nbproject/ +/*.DS_Store +*.DS_Store diff --git a/lang/csharp/.gitignore b/lang/csharp/.gitignore index b8e088c6160..ee17d887280 100644 --- a/lang/csharp/.gitignore +++ b/lang/csharp/.gitignore @@ -23,13 +23,48 @@ # User-specific files *.suo *.user +*.userosscache *.sln.docstates +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + # Build results [Dd]ebug/ +[Dd]ebugPublic/ [Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + *_i.c *_p.c +*_i.h *.ilk *.meta *.obj @@ -43,10 +78,413 @@ *.tli *.tlh *.tmp +*.tmp_proj +*.log *.vspscc +*.vssscc .builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool *.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages *.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config +#NuGet +packages/ -#Test results -TestResult.xml +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Microsoft Azure ApplicationInsights config file +ApplicationInsights.config + +# Windows Store app package directory +AppPackages/ +BundleArtifacts/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe + +# FAKE - F# Make +.fake/ + +#============================================================================== +### Windows ### +# Windows image file caches +Thumbs.db +ehthumbs.db + +# Folder config file +Desktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msm +*.msp + +#============================================================================== +#Ignore email files delivered to specified pickup directory +*.eml + +#Allow NuGet.exe (do not ignore) +!NuGet.exe + +#Ignore WebDeploy publish profiles +*.Publish.xml + +#Ignore Azure build csdef & Pubxml files +ServiceDefinition.build.csdef +*.azurePubxml + +#Allow ReSharper .DotSettings (for non-namespace-provider properties) +!*.csproj.DotSettings + +#Ignore private folder +/Private/ + +#============================================================================== +# SQL Server files +App_Data/*.mdf +App_Data/*.ldf + +*App_Data/*.mdf +*App_Data/*.ldf + +#Visual Studio DB Project +*.dbmdl +[Ss]ql/ + + + +#============================================================================== +# HolisticWare +# +# http://www.gitignore.io/. +# +# https://github.com/github/gitignore/blob/master/VisualStudio.gitignore +# http://stackoverflow.com/questions/2143956/gitignore-for-visual-studio-projects-and-solutions +# + + +#---------------------------------------------- +# MacOSX +**/*.DS_Store +**/.DS_Store +**/._* +**/__MACOSX +#---------------------------------------------- + +#---------------------------------------------- +# source control +**/.svn* +**/.git.* +**/.git.*/* +#---------------------------------------------- + +#---------------------------------------------- +# Cake Build system +tools/ +**/tools/ +#---------------------------------------------- + +#---------------------------------------------- +# Xamarin Components and nuget packages +**/Components/ +**/packages/ +src/samples/Components/** +source/samples/Components/** +#---------------------------------------------- + +#---------------------------------------------- +# sensitive data +**/*.hidden.cs +**/*.hidden.md +**/*.hidden.sh +**/*.hidden.bat +**/*.hidden.cmd +**/*.secure*.cs +**/*.secure*.md +**/*.secure*.sh +**/*.secure*.bat +**/*.secure*.cmd +**/*.secret*.cs +**/*.secret*.md +**/*.secret*.sh +**/*.secret*.bat +*/*.secret*.cmd + +**/*.data.bat +**/*.data.sh +**/*.secure.data.md +**/*.data.md +**/*.secured.md +**/*.secured.md +**/*.secure* +**/*.data.* +#---------------------------------------------- + +#---------------------------------------------- +# Xamarin Studio +**/*.userprefs +#---------------------------------------------- + +#---------------------------------------------- +# Xamarin.Android +# Security (project id etc) +# **/AndroidManifest.xml + +**/Resource.designer.cs +#---------------------------------------------- + +#---------------------------------------------- +# Xamarin.Android sharpen +docs/workspace/sharpen/** +#---------------------------------------------- + +#---------------------------------------------- +# Xamarin.Android Eclipse +*.pydevproject +.metadata +.gradle +bin/ +tmp/ +*.tmp +*.bak +*.swp +*~.nib +local.properties +.settings/ +.loadpath + +# External tool builders +.externalToolBuilders/ + +# Locally stored "Eclipse launch configurations" +*.launch + +# CDT-specific +.cproject + +# PDT-specific +.buildpath + +# sbteclipse plugin +.target + +# TeXlipse plugin +.texlipse +/Tools/Eclipse.Workspace/*.DS_Store +#---------------------------------------------- +# Xamarin.Android sharpen + +**/UpgradeLog.htm +#..................................................... + +/docs/ubertesters.sdk.ios % + + +#------------------------------------------ +# Android +**/Resources/Resource.[Dd]esigner.cs +**/Resource.Designer.cs +**/*.csproj.bak + +# ignore Xamarin.Android Resource.Designer.cs files +**/[Rr]esource.[Dd]esigner.cs +**/*.Droid/**/[Rr]esource.[Dd]esigner.cs +**/*.Android/**/[Rr]esource.[Dd]esigner.cs +**/Android/**/[Rr]esource.[Dd]esigner.cs +#------------------------------------------ + +#------------------------------------------ +# Xamarin.iOS build files +**DerivedData** +**build** +lib/** +#------------------------------------------ + +#------------------------------------------ +# iOS build files +**DerivedData** +**build** +lib/** +#------------------------------------------ + +#------------------------------------------ +# .net Core +**/project.lock.json +#------------------------------------------ + +#------------------------------------------ +# JetBrains IntelliJ Rider IDE +**/.idea/ +#------------------------------------------ + +#------------------------------------------ +# Cake Build +tools/** +#------------------------------------------ + +#------------------------------------------ +# Xamarin CI project structure +output/** +#------------------------------------------ + + +#------------------------------------------ +# Universal Windows Platform +**/project.lock.json +#------------------------------------------ + +#============================================================================== +df-post.txt +df-pre.txt diff --git a/lang/csharp/.vscode/launch.json b/lang/csharp/.vscode/launch.json new file mode 100644 index 00000000000..01f80d29ede --- /dev/null +++ b/lang/csharp/.vscode/launch.json @@ -0,0 +1,47 @@ +{ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + // If you have changed target frameworks, make sure to update the program path. + "program": "${workspaceFolder}/src/apache/test.dotnetcore/bin/Debug/netcoreapp2.0/Avro.test.dotnetcore.dll", + "args": [], + "cwd": "${workspaceFolder}/src/apache/test.dotnetcore", + // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window + "console": "internalConsole", + "stopAtEntry": false, + "internalConsoleOptions": "openOnSessionStart" + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + , + { + "name": ".NET Core Launch (console)", + "type": "coreclr", + "request": "launch", + "preLaunchTask": "build", + "program": "${workspaceFolder}/src/apache/test.dotnetcore/bin/Debug/netcoreapp2.0/Avro.test.dotnetcore.dll", + "args": [], + "cwd": "${workspaceFolder}/src/apache/test.dotnetcore", + "console": "internalConsole", + "stopAtEntry": false, + "internalConsoleOptions": "openOnSessionStart" + }, + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} \ No newline at end of file diff --git a/lang/csharp/.vscode/tasks.json b/lang/csharp/.vscode/tasks.json new file mode 100644 index 00000000000..a38427e25b3 --- /dev/null +++ b/lang/csharp/.vscode/tasks.json @@ -0,0 +1,25 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/src/apache/test.dotnetcore/Avro.test.dotnetcore.csproj" + ], + "problemMatcher": "$msCompile" + }, + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}/src/apache/test.dotnetcore/Avro.test.dotnetcore.csproj" + ], + "problemMatcher": "$msCompile" + } + ] +} \ No newline at end of file diff --git a/lang/csharp/Avro.sln b/lang/csharp/Avro.sln index 58687b2622a..f6e6c0d5281 100644 --- a/lang/csharp/Avro.sln +++ b/lang/csharp/Avro.sln @@ -1,95 +1,67 @@  -Microsoft Visual Studio Solution File, Format Version 11.00 -# Visual Studio 2010 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.main", "src\apache\main\Avro.main.csproj", "{A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}" +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.27130.2027 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avro.main", "src\apache\main\Avro.main.csproj", "{C17F6AF2-F200-4421-855B-13F4E97E9716}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.test", "src\apache\test\Avro.test.csproj", "{911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avro.codegen", "src\apache\codegen\Avro.codegen.csproj", "{D968A52A-E3E5-472F-A8EA-C15427521901}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.codegen", "src\apache\codegen\Avro.codegen.csproj", "{BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avro.ipc", "src\apache\ipc\Avro.ipc.csproj", "{D4074E5D-38B1-4A67-877B-E8E6BF45CE09}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.ipc", "src\apache\ipc\Avro.ipc.csproj", "{3B05043A-DC6C-49B6-85BF-9AB055D0B414}" - ProjectSection(ProjectDependencies) = postProject - {AEB22F94-4ECF-4008-B159-389B3F05D54B} = {AEB22F94-4ECF-4008-B159-389B3F05D54B} - EndProjectSection +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avro.msbuild", "src\apache\msbuild\Avro.msbuild.csproj", "{B6134269-6E02-43FF-BC0E-7FB43FBAA641}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.msbuild", "src\apache\msbuild\Avro.msbuild.csproj", "{AEB22F94-4ECF-4008-B159-389B3F05D54B}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.test", "src\apache\test\Avro.test.csproj", "{6C461AC0-8C0F-4538-9256-454F752DD821}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.perf", "src\apache\perf\Avro.perf.csproj", "{AC4E1909-2594-4D01-9B2B-B832C07BAFE5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avro.perf.dotnetcore", "src\apache\perf.dotnetcore\Avro.perf.dotnetcore.csproj", "{C94DEBC9-5D6B-4C7F-AE35-057BB111CDA1}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Avro.perf.netfx", "src\apache\perf.netfx\Avro.perf.netfx.csproj", "{0D707008-7466-4407-8A80-C26DECAB18DB}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Avro.test.dotnetcore", "src\apache\test.dotnetcore\Avro.test.dotnetcore.csproj", "{35CC4865-174C-4398-B99B-626EE6DFEBEE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU - Debug|Mixed Platforms = Debug|Mixed Platforms - Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU - Release|Mixed Platforms = Release|Mixed Platforms - Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Debug|Any CPU.Build.0 = Debug|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Debug|x86.ActiveCfg = Debug|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Release|Any CPU.ActiveCfg = Release|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Release|Any CPU.Build.0 = Release|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0}.Release|x86.ActiveCfg = Release|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Debug|Any CPU.Build.0 = Debug|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Debug|x86.ActiveCfg = Debug|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Release|Any CPU.ActiveCfg = Release|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Release|Any CPU.Build.0 = Release|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA}.Release|x86.ActiveCfg = Release|Any CPU - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Debug|Any CPU.Build.0 = Debug|Any CPU - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Debug|x86.ActiveCfg = Debug|x86 - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Debug|x86.Build.0 = Debug|x86 - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Release|Any CPU.ActiveCfg = Release|Any CPU - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Release|Any CPU.Build.0 = Release|Any CPU - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Release|Mixed Platforms.ActiveCfg = Release|x86 - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Release|Mixed Platforms.Build.0 = Release|x86 - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Release|x86.ActiveCfg = Release|x86 - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8}.Release|x86.Build.0 = Release|x86 - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Debug|Any CPU.Build.0 = Debug|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Debug|x86.ActiveCfg = Debug|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Release|Any CPU.ActiveCfg = Release|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Release|Any CPU.Build.0 = Release|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414}.Release|x86.ActiveCfg = Release|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Debug|x86.ActiveCfg = Debug|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Release|Any CPU.Build.0 = Release|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B}.Release|x86.ActiveCfg = Release|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Debug|x86.ActiveCfg = Debug|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|Any CPU.Build.0 = Release|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|Mixed Platforms.Build.0 = Release|Any CPU - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5}.Release|x86.ActiveCfg = Release|Any CPU + {C17F6AF2-F200-4421-855B-13F4E97E9716}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C17F6AF2-F200-4421-855B-13F4E97E9716}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C17F6AF2-F200-4421-855B-13F4E97E9716}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C17F6AF2-F200-4421-855B-13F4E97E9716}.Release|Any CPU.Build.0 = Release|Any CPU + {D968A52A-E3E5-472F-A8EA-C15427521901}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D968A52A-E3E5-472F-A8EA-C15427521901}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D968A52A-E3E5-472F-A8EA-C15427521901}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D968A52A-E3E5-472F-A8EA-C15427521901}.Release|Any CPU.Build.0 = Release|Any CPU + {D4074E5D-38B1-4A67-877B-E8E6BF45CE09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D4074E5D-38B1-4A67-877B-E8E6BF45CE09}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D4074E5D-38B1-4A67-877B-E8E6BF45CE09}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D4074E5D-38B1-4A67-877B-E8E6BF45CE09}.Release|Any CPU.Build.0 = Release|Any CPU + {B6134269-6E02-43FF-BC0E-7FB43FBAA641}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B6134269-6E02-43FF-BC0E-7FB43FBAA641}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B6134269-6E02-43FF-BC0E-7FB43FBAA641}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B6134269-6E02-43FF-BC0E-7FB43FBAA641}.Release|Any CPU.Build.0 = Release|Any CPU + {6C461AC0-8C0F-4538-9256-454F752DD821}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C461AC0-8C0F-4538-9256-454F752DD821}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C461AC0-8C0F-4538-9256-454F752DD821}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C461AC0-8C0F-4538-9256-454F752DD821}.Release|Any CPU.Build.0 = Release|Any CPU + {C94DEBC9-5D6B-4C7F-AE35-057BB111CDA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C94DEBC9-5D6B-4C7F-AE35-057BB111CDA1}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C94DEBC9-5D6B-4C7F-AE35-057BB111CDA1}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C94DEBC9-5D6B-4C7F-AE35-057BB111CDA1}.Release|Any CPU.Build.0 = Release|Any CPU + {0D707008-7466-4407-8A80-C26DECAB18DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D707008-7466-4407-8A80-C26DECAB18DB}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D707008-7466-4407-8A80-C26DECAB18DB}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D707008-7466-4407-8A80-C26DECAB18DB}.Release|Any CPU.Build.0 = Release|Any CPU + {35CC4865-174C-4398-B99B-626EE6DFEBEE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {35CC4865-174C-4398-B99B-626EE6DFEBEE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {35CC4865-174C-4398-B99B-626EE6DFEBEE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {35CC4865-174C-4398-B99B-626EE6DFEBEE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D75C209E-BD5C-4A16-B905-5290EF91CC29} + EndGlobalSection EndGlobal diff --git a/lang/csharp/build.sh b/lang/csharp/build.sh old mode 100755 new mode 100644 diff --git a/lang/csharp/lib/main/Castle.Core.dll b/lang/csharp/lib/main/Castle.Core.dll deleted file mode 100644 index ccc7d5ff62e..00000000000 Binary files a/lang/csharp/lib/main/Castle.Core.dll and /dev/null differ diff --git a/lang/csharp/lib/main/Newtonsoft.Json.dll b/lang/csharp/lib/main/Newtonsoft.Json.dll deleted file mode 100644 index 4703b89058a..00000000000 Binary files a/lang/csharp/lib/main/Newtonsoft.Json.dll and /dev/null differ diff --git a/lang/csharp/lib/main/log4net.dll b/lang/csharp/lib/main/log4net.dll deleted file mode 100644 index ffc57e11254..00000000000 Binary files a/lang/csharp/lib/main/log4net.dll and /dev/null differ diff --git a/lang/csharp/lib/test/nunit.framework.dll b/lang/csharp/lib/test/nunit.framework.dll deleted file mode 100644 index 639dbb0dce5..00000000000 Binary files a/lang/csharp/lib/test/nunit.framework.dll and /dev/null differ diff --git a/lang/csharp/src/apache/Clean.ps1 b/lang/csharp/src/apache/Clean.ps1 new file mode 100644 index 00000000000..f1caa87f77a --- /dev/null +++ b/lang/csharp/src/apache/Clean.ps1 @@ -0,0 +1,2 @@ +# Useful when switching between windows and linux (bash on windows) +Get-ChildItem -Include bin,obj -Recurse | Remove-Item -Recurse -Force \ No newline at end of file diff --git a/lang/csharp/src/apache/clean.sh b/lang/csharp/src/apache/clean.sh new file mode 100644 index 00000000000..8838257722a --- /dev/null +++ b/lang/csharp/src/apache/clean.sh @@ -0,0 +1,7 @@ +#!/usr/bin/env bash + +# Useful if using the same folder for windows + linux (on windows) +# since intermediate files can interfere. Sometimes you have to manually +# delete these files too (reason unknown) +find . -name "obj" -type d -exec rm -r "{}" \; +find . -name "bin" -type d -exec rm -r "{}" \; diff --git a/lang/csharp/src/apache/codegen/Avro.codegen.csproj b/lang/csharp/src/apache/codegen/Avro.codegen.csproj index 695929efc2a..bf0d7ccccc7 100644 --- a/lang/csharp/src/apache/codegen/Avro.codegen.csproj +++ b/lang/csharp/src/apache/codegen/Avro.codegen.csproj @@ -1,4 +1,4 @@ - + - - Debug - AnyCPU - 8.0.30703 - 2.0 - {BF0D313C-1AA3-4900-B277-B0F5F9DDCDA8} - Exe - Properties - Avro.codegen - avrogen - v3.5 - 512 - false - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - true - - - - AnyCPU - true - full - false - ..\..\..\build\codegen\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - none - true - ..\..\..\build\codegen\Release\ - - - prompt - 4 - - - true - ..\..\..\build\codegen\Debug\ - DEBUG;TRACE - full - AnyCPU - ..\..\..\build\codegen\Debug\avrogen.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - true - ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - true - Off - - - ..\..\..\build\codegen\Release\ - - - true - none - AnyCPU - ..\..\..\build\codegen\Release\avrogen.exe.CodeAnalysisLog.xml - true - GlobalSuppressions.cs - prompt - MinimumRecommendedRules.ruleset - ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\\Rule Sets - false - ;C:\Program Files\Microsoft Visual Studio 10.0\Team Tools\Static Analysis Tools\FxCop\\Rules - false - Off - - - ..\..\..\build\codegen\Release\ + netstandard2.0 + + + + - true + false ..\..\..\Avro.snk + Avro.codegen + Avro.codegen - - - - - - - - - - - - - - - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0} - Avro.main - - - - - False - Microsoft .NET Framework 3.5 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - - - - \ No newline at end of file + diff --git a/lang/csharp/src/apache/codegen/app.config b/lang/csharp/src/apache/codegen/app.config deleted file mode 100755 index ae24790609c..00000000000 --- a/lang/csharp/src/apache/codegen/app.config +++ /dev/null @@ -1,19 +0,0 @@ - - - - diff --git a/lang/csharp/src/apache/ipc/Avro.ipc.csproj b/lang/csharp/src/apache/ipc/Avro.ipc.csproj index 9d738c928f7..231cbcf4f51 100644 --- a/lang/csharp/src/apache/ipc/Avro.ipc.csproj +++ b/lang/csharp/src/apache/ipc/Avro.ipc.csproj @@ -1,108 +1,29 @@ - - - - - Debug - AnyCPU - {3B05043A-DC6C-49B6-85BF-9AB055D0B414} - Library - Properties - Avro.ipc - Avro.ipc - v3.5 - 512 - - - - true - full - false - ..\..\..\build\ipc\Debug\ - DEBUG;TRACE - prompt - 4 - AllRules.ruleset - - - pdbonly - true - ..\..\..\build\ipc\Release\ - TRACE - prompt - 4 - - - true - - - ..\..\..\Avro.snk - - - - ..\..\..\lib\main\Castle.Core.dll - - - ..\..\..\lib\main\log4net.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {a0a5ca3c-f58c-4d07-98b0-2c7b62ab20f0} - Avro.main - - - - - - - - - \ No newline at end of file + + + + netstandard2.0 + false + + + + + + + + + + + + + + + + + false + + + ..\..\..\Avro.snk + Avro.ipc + Avro.ipc + + diff --git a/lang/csharp/src/apache/main/Avro.main.csproj b/lang/csharp/src/apache/main/Avro.main.csproj index 7f41e3ff928..ac51371899c 100644 --- a/lang/csharp/src/apache/main/Avro.main.csproj +++ b/lang/csharp/src/apache/main/Avro.main.csproj @@ -1,180 +1,32 @@ - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0} - Library - Properties - Avro - Avro - v3.5 - 512 - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - true - full - false - ..\..\..\build\main\Debug\ - DEBUG;TRACE - prompt - 4 - Off - - - none - true - ..\..\..\build\main\Release\ - - - prompt - 4 - Off + netstandard2.0 + false + + + + + + + + + + + + + + + + + - true + false ..\..\..\Avro.snk + Avro + Avro - - - ..\..\..\lib\main\log4net.dll - - - ..\..\..\lib\main\Newtonsoft.Json.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - \ No newline at end of file + diff --git a/lang/csharp/src/apache/main/Properties/Settings.Designer.cs b/lang/csharp/src/apache/main/Properties/Settings.Designer.cs deleted file mode 100644 index dc7cb6df807..00000000000 --- a/lang/csharp/src/apache/main/Properties/Settings.Designer.cs +++ /dev/null @@ -1,44 +0,0 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// Runtime Version:4.0.30319.1 -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -namespace Avro.Properties { - - - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] - internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { - - private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); - - public static Settings Default { - get { - return defaultInstance; - } - } - } -} diff --git a/lang/csharp/src/apache/msbuild/Avro.msbuild.csproj b/lang/csharp/src/apache/msbuild/Avro.msbuild.csproj index f1dd6f8f734..454598c01a0 100644 --- a/lang/csharp/src/apache/msbuild/Avro.msbuild.csproj +++ b/lang/csharp/src/apache/msbuild/Avro.msbuild.csproj @@ -1,74 +1,21 @@ - - - - - Debug - AnyCPU - {AEB22F94-4ECF-4008-B159-389B3F05D54B} - Library - Properties - Avro.msbuild - Avro.msbuild - v3.5 - 512 - - - - true - full - false - ..\..\..\build\msbuild\Debug\ - DEBUG;TRACE - prompt - 4 + netstandard2.0 - - pdbonly - true - ..\..\..\build\msbuild\Release\ - TRACE - prompt - 4 - - - - - - - - + - - + - - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0} - Avro.main - + - - - \ No newline at end of file + + false + + + ..\..\..\Avro.snk + Avro.msbuild + Avro.msbuild + + diff --git a/lang/csharp/src/apache/msbuild/Properties/AssemblyInfo.cs b/lang/csharp/src/apache/msbuild/Properties/AssemblyInfo.cs deleted file mode 100644 index e46675b1313..00000000000 --- a/lang/csharp/src/apache/msbuild/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -/** - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyTitle("Avro.msbuild")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Apache")] -[assembly: AssemblyProduct("Avro.msbuild")] -[assembly: AssemblyCopyright("Copyright © Apache 2013")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] -[assembly: Guid("A7982FA5-F369-457F-894E-4F90262E4638")] -[assembly: AssemblyVersion("0.9.0.0")] -[assembly: AssemblyFileVersion("0.9.0.0")] \ No newline at end of file diff --git a/lang/csharp/src/apache/perf.dotnetcore/Avro.perf.dotnetcore.csproj b/lang/csharp/src/apache/perf.dotnetcore/Avro.perf.dotnetcore.csproj new file mode 100644 index 00000000000..9aaf8e5cfea --- /dev/null +++ b/lang/csharp/src/apache/perf.dotnetcore/Avro.perf.dotnetcore.csproj @@ -0,0 +1,13 @@ + + + + Exe + netcoreapp2.0 + false + + + + + + + diff --git a/lang/csharp/src/apache/perf/PerfTest.cs b/lang/csharp/src/apache/perf.dotnetcore/PerfTest.cs similarity index 100% rename from lang/csharp/src/apache/perf/PerfTest.cs rename to lang/csharp/src/apache/perf.dotnetcore/PerfTest.cs diff --git a/lang/csharp/src/apache/perf/com/foo/A.cs b/lang/csharp/src/apache/perf.dotnetcore/com/foo/A.cs similarity index 100% rename from lang/csharp/src/apache/perf/com/foo/A.cs rename to lang/csharp/src/apache/perf.dotnetcore/com/foo/A.cs diff --git a/lang/csharp/src/apache/perf/com/foo/Complex.cs b/lang/csharp/src/apache/perf.dotnetcore/com/foo/Complex.cs similarity index 100% rename from lang/csharp/src/apache/perf/com/foo/Complex.cs rename to lang/csharp/src/apache/perf.dotnetcore/com/foo/Complex.cs diff --git a/lang/csharp/src/apache/perf/com/foo/MyEnum.cs b/lang/csharp/src/apache/perf.dotnetcore/com/foo/MyEnum.cs similarity index 100% rename from lang/csharp/src/apache/perf/com/foo/MyEnum.cs rename to lang/csharp/src/apache/perf.dotnetcore/com/foo/MyEnum.cs diff --git a/lang/csharp/src/apache/perf/com/foo/MyFixed.cs b/lang/csharp/src/apache/perf.dotnetcore/com/foo/MyFixed.cs similarity index 100% rename from lang/csharp/src/apache/perf/com/foo/MyFixed.cs rename to lang/csharp/src/apache/perf.dotnetcore/com/foo/MyFixed.cs diff --git a/lang/csharp/src/apache/perf/com/foo/Narrow.cs b/lang/csharp/src/apache/perf.dotnetcore/com/foo/Narrow.cs similarity index 100% rename from lang/csharp/src/apache/perf/com/foo/Narrow.cs rename to lang/csharp/src/apache/perf.dotnetcore/com/foo/Narrow.cs diff --git a/lang/csharp/src/apache/perf/com/foo/Simple.cs b/lang/csharp/src/apache/perf.dotnetcore/com/foo/Simple.cs similarity index 100% rename from lang/csharp/src/apache/perf/com/foo/Simple.cs rename to lang/csharp/src/apache/perf.dotnetcore/com/foo/Simple.cs diff --git a/lang/csharp/src/apache/perf/com/foo/Wide.cs b/lang/csharp/src/apache/perf.dotnetcore/com/foo/Wide.cs similarity index 100% rename from lang/csharp/src/apache/perf/com/foo/Wide.cs rename to lang/csharp/src/apache/perf.dotnetcore/com/foo/Wide.cs diff --git a/lang/csharp/src/apache/perf/com/foo/newRec.cs b/lang/csharp/src/apache/perf.dotnetcore/com/foo/newRec.cs similarity index 100% rename from lang/csharp/src/apache/perf/com/foo/newRec.cs rename to lang/csharp/src/apache/perf.dotnetcore/com/foo/newRec.cs diff --git a/lang/csharp/src/apache/perf/schema.avsc b/lang/csharp/src/apache/perf.dotnetcore/schema.avsc similarity index 100% rename from lang/csharp/src/apache/perf/schema.avsc rename to lang/csharp/src/apache/perf.dotnetcore/schema.avsc diff --git a/lang/csharp/src/apache/perf.netfx/App.config b/lang/csharp/src/apache/perf.netfx/App.config new file mode 100644 index 00000000000..e8e81a28a39 --- /dev/null +++ b/lang/csharp/src/apache/perf.netfx/App.config @@ -0,0 +1,6 @@ + + + + + + diff --git a/lang/csharp/src/apache/perf.netfx/Avro.perf.netfx.csproj b/lang/csharp/src/apache/perf.netfx/Avro.perf.netfx.csproj new file mode 100644 index 00000000000..3f5491ac763 --- /dev/null +++ b/lang/csharp/src/apache/perf.netfx/Avro.perf.netfx.csproj @@ -0,0 +1,97 @@ + + + + + Debug + AnyCPU + {0D707008-7466-4407-8A80-C26DECAB18DB} + Exe + Avro.Perf.netfx + Avro.Perf.netfx + v4.6.1 + 512 + true + + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + false + + + + ..\..\..\packages\Newtonsoft.Json.10.0.3\lib\net45\Newtonsoft.Json.dll + + + + ..\..\..\packages\System.CodeDom.4.4.0\lib\net461\System.CodeDom.dll + + + + + + + + + + + + com\foo\A.cs + + + com\foo\Complex.cs + + + com\foo\MyEnum.cs + + + com\foo\MyFixed.cs + + + com\foo\Narrow.cs + + + com\foo\newRec.cs + + + com\foo\Simple.cs + + + com\foo\Wide.cs + + + PerfTest.cs + + + + + + schema.avsc + + + + + + + {c17f6af2-f200-4421-855b-13f4e97e9716} + Avro.Main + + + + \ No newline at end of file diff --git a/lang/csharp/src/apache/perf.netfx/Properties/AssemblyInfo.cs b/lang/csharp/src/apache/perf.netfx/Properties/AssemblyInfo.cs new file mode 100644 index 00000000000..7d1008e27b9 --- /dev/null +++ b/lang/csharp/src/apache/perf.netfx/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Avro.Perf.netfx")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Avro.Perf.netfx")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0d707008-7466-4407-8a80-c26decab18db")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/lang/csharp/src/apache/perf.netfx/packages.config b/lang/csharp/src/apache/perf.netfx/packages.config new file mode 100644 index 00000000000..2c331d71062 --- /dev/null +++ b/lang/csharp/src/apache/perf.netfx/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/lang/csharp/src/apache/perf/Avro.perf.csproj b/lang/csharp/src/apache/perf/Avro.perf.csproj deleted file mode 100644 index 7235c99bcbd..00000000000 --- a/lang/csharp/src/apache/perf/Avro.perf.csproj +++ /dev/null @@ -1,143 +0,0 @@ - - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {AC4E1909-2594-4D01-9B2B-B832C07BAFE5} - Exe - Properties - Avro.perf - Avro.perf - v3.5 - 512 - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - true - full - false - ..\..\..\build\perf\Debug\ - DEBUG;TRACE - prompt - 4 - Off - - - none - true - ..\..\..\build\perf\Release\ - - - prompt - 4 - Off - - - - - - - False - ..\..\..\..\..\lang\csharp\lib\main\Castle.Core.dll - - - False - ..\..\..\lib\test\nunit.framework.dll - - - - - - - - - - - {3b05043a-dc6c-49b6-85bf-9ab055d0b414} - Avro.ipc - - - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0} - Avro.main - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - - - - - - - - - Code - - - - - - - - - \ No newline at end of file diff --git a/lang/csharp/src/apache/perf/app.config b/lang/csharp/src/apache/perf/app.config deleted file mode 100755 index ae24790609c..00000000000 --- a/lang/csharp/src/apache/perf/app.config +++ /dev/null @@ -1,19 +0,0 @@ - - - - diff --git a/lang/csharp/src/apache/test.dotnetcore/Avro.test.dotnetcore.csproj b/lang/csharp/src/apache/test.dotnetcore/Avro.test.dotnetcore.csproj new file mode 100644 index 00000000000..b44c4350ece --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Avro.test.dotnetcore.csproj @@ -0,0 +1,26 @@ + + + + netcoreapp2.0 + + false + + Avro.Test + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lang/csharp/src/apache/test.dotnetcore/CodGen/CodeGenTest.cs b/lang/csharp/src/apache/test.dotnetcore/CodGen/CodeGenTest.cs new file mode 100644 index 00000000000..eaac4828e8f --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/CodGen/CodeGenTest.cs @@ -0,0 +1,129 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.CodeDom.Compiler; +using Microsoft.CSharp; +using NUnit.Framework; +using Avro.Specific; + +namespace Avro.Test +{ + [TestFixture] + + class CodeGenTest + { + [TestCase(@"{ +""type"" : ""record"", +""name"" : ""ClassKeywords"", +""namespace"" : ""com.base"", +""fields"" : + [ + { ""name"" : ""int"", ""type"" : ""int"" }, + { ""name"" : ""base"", ""type"" : ""long"" }, + { ""name"" : ""event"", ""type"" : ""boolean"" }, + { ""name"" : ""foreach"", ""type"" : ""double"" }, + { ""name"" : ""bool"", ""type"" : ""float"" }, + { ""name"" : ""internal"", ""type"" : ""bytes"" }, + { ""name"" : ""while"", ""type"" : ""string"" }, + { ""name"" : ""return"", ""type"" : ""null"" }, + { ""name"" : ""enum"", ""type"" : { ""type"" : ""enum"", ""name"" : ""class"", ""symbols"" : [ ""A"", ""B"" ] } }, + { ""name"" : ""string"", ""type"" : { ""type"": ""fixed"", ""size"": 16, ""name"": ""static"" } } + ] +} +", new object[] {"com.base.ClassKeywords", typeof(int), typeof(long), typeof(bool), typeof(double), typeof(float), typeof(byte[]), typeof(string),typeof(object),"com.base.class", "com.base.static"})] + [TestCase(@"{ +""type"" : ""record"", +""name"" : ""SchemaObject"", +""namespace"" : ""schematest"", +""fields"" : + [ + { ""name"" : ""myobject"", ""type"" : + [ + ""null"", + {""type"" : ""array"", ""items"" : [ ""null"", + { ""type"" : ""enum"", ""name"" : ""MyEnum"", ""symbols"" : [ ""A"", ""B"" ] }, + { ""type"": ""fixed"", ""size"": 16, ""name"": ""MyFixed"" } + ] + } + ] + } + ] +} +", new object[] { "schematest.SchemaObject", typeof(IList) })] + public static void TestCodeGen(string str, object[] result) + { + Schema schema = Schema.Parse(str); + + CompilerResults compres = GenerateSchema(schema); + + // instantiate object + ISpecificRecord rec = compres.CompiledAssembly.CreateInstance((string)result[0]) as ISpecificRecord; + Assert.IsNotNull(rec); + + // test type of each fields + for (int i = 1; i < result.Length; ++i) + { + object field = rec.Get(i - 1); + Type stype; + if (result[i].GetType() == typeof(string)) + { + object obj = compres.CompiledAssembly.CreateInstance((string)result[i]); + Assert.IsNotNull(obj); + stype = obj.GetType(); + } + else + stype = (Type)result[i]; + if (!stype.IsValueType) + Assert.IsNull(field); // can't test reference type, it will be null + else + Assert.AreEqual(stype, field.GetType()); + } + } + + + private static CompilerResults GenerateSchema(Schema schema) + { + var codegen = new CodeGen(); + codegen.AddSchema(schema); + return GenerateAssembly(codegen); + } + + private static CompilerResults GenerateAssembly(CodeGen schema) + { + var compileUnit = schema.GenerateCode(); + + var comparam = new CompilerParameters(new string[] { "mscorlib.dll" }); + comparam.ReferencedAssemblies.Add("System.dll"); + comparam.ReferencedAssemblies.Add("Avro.dll"); + comparam.GenerateInMemory = true; + var ccp = new CSharpCodeProvider(); + var units = new[] { compileUnit }; + var compres = ccp.CompileAssemblyFromDom(comparam, units); + if (compres.Errors.Count > 0) + { + for (int i = 0; i < compres.Errors.Count; i++) + Console.WriteLine(compres.Errors[i]); + } + Assert.AreEqual(0, compres.Errors.Count); + return compres; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/File/FileTests.cs b/lang/csharp/src/apache/test.dotnetcore/File/FileTests.cs new file mode 100644 index 00000000000..c565c5663c7 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/File/FileTests.cs @@ -0,0 +1,781 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections; +using System.IO; +using System.Collections.Generic; +using Avro.Generic; +using NUnit.Framework; +using Avro.Specific; +using System.Reflection; +using Avro.File; +using System.Linq; + +namespace Avro.Test.File +{ + [TestFixture] + public class FileTests + { + const string specificSchema = "{\"type\":\"record\",\"name\":\"Foo\",\"namespace\":\"Avro.Test.File\",\"fields\":" + + "[{\"name\":\"name\",\"type\":[\"null\",\"string\"]},{\"name\":\"age\",\"type\":\"int\"}]}"; + + /// + /// Reading & writing of specific (custom) record objects + /// + /// + /// + /// + [TestCase(specificSchema, new object[] { new object[] { "John", 23 } }, Codec.Type.Deflate)] + [TestCase(specificSchema, new object[] { new object[] { "Jane", 23 } }, Codec.Type.Deflate)] + [TestCase(specificSchema, new object[] { new object[] { "John", 23 }, new object[] { "Jane", 99 }, new object[] { "Jeff", 88 } }, Codec.Type.Deflate)] + [TestCase(specificSchema, new object[] { new object[] {"John", 23}, new object[] { "Jane", 99 }, new object[] { "Jeff", 88 }, + new object[] {"James", 13}, new object[] { "June", 109 }, new object[] { "Lloyd", 18 }, + new object[] {"Jenny", 3}, new object[] { "Bob", 9 }, new object[] { null, 48 }}, Codec.Type.Deflate)] + [TestCase(specificSchema, new object[] { new object[] { "John", 23 } }, Codec.Type.Null)] + [TestCase(specificSchema, new object[] { new object[] { "Jane", 23 } }, Codec.Type.Null)] + [TestCase(specificSchema, new object[] { new object[] { "John", 23 }, new object[] { "Jane", 99 }, new object[] { "Jeff", 88 } }, Codec.Type.Null)] + [TestCase(specificSchema, new object[] { new object[] {"John", 23}, new object[] { "Jane", 99 }, new object[] { "Jeff", 88 }, + new object[] {"James", 13}, new object[] { "June", 109 }, new object[] { "Lloyd", 18 }, + new object[] {"Jamie", 53}, new object[] { "Fanessa", 101 }, new object[] { "Kan", 18 }, + new object[] {"Janey", 33}, new object[] { "Deva", 102 }, new object[] { "Gavin", 28 }, + new object[] {"Lochy", 113}, new object[] { "Nickie", 10 }, new object[] { "Liddia", 38 }, + new object[] {"Fred", 3}, new object[] { "April", 17 }, new object[] { "Novac", 48 }, + new object[] {"Idan", 33}, new object[] { "Jolyon", 76 }, new object[] { "Ant", 68 }, + new object[] {"Ernie", 43}, new object[] { "Joel", 99 }, new object[] { "Dan", 78 }, + new object[] {"Dave", 103}, new object[] { "Hillary", 79 }, new object[] { "Grant", 88 }, + new object[] {"JJ", 14}, new object[] { "Bill", 90 }, new object[] { "Larry", 4 }, + new object[] {"Jenny", 3}, new object[] { "Bob", 9 }, new object[] { null, 48 }}, Codec.Type.Null)] + public void TestSpecificData(string schemaStr, object[] recs, Codec.Type codecType) + { + // create and write out + IList records = MakeRecords(recs); + + foreach(var rwFactory in SpecificOptions()) + { + MemoryStream dataFileOutputStream = new MemoryStream(); + Schema schema = Schema.Parse(schemaStr); + using (IFileWriter dataFileWriter = rwFactory.CreateWriter(dataFileOutputStream, schema, Codec.CreateCodec(codecType))) + { + foreach (Foo rec in records) + dataFileWriter.Append(rec); + } + + MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray()); + + // read back + IList readRecords = new List(); + + using (IFileReader reader = rwFactory.CreateReader(dataFileInputStream, null)) + { + foreach (Foo rec in reader.NextEntries) + readRecords.Add(rec); + } + + // compare objects via Json + Assert.AreEqual(records.Count, readRecords.Count); + for (int i = 0; i < records.Count; i++) + { + Assert.AreEqual(records[i].ToString(), readRecords[i].ToString()); + } + } + } + + /// + /// Reading & writing of generic record objects + /// + /// + /// + /// + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"null\"}]}", + new object[] { "f1", null }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"boolean\"}]}", + new object[] { "f1", true }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"boolean\"}]}", + new object[] { "f1", false }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"int\"}]}", + new object[] { "f1", 101 }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"long\"}]}", + new object[] { "f1", 101L }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"float\"}]}", + new object[] { "f1", 101.78f }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"double\"}]}", + new object[] { "f1", 101.78 }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"string\"}]}", + new object[] { "f1", "A" }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"bytes\"}]}", + new object[] { "f1", new byte[] { 0, 1 } }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"enum\", \"name\": \"e\", \"symbols\":[\"s1\", \"s2\"]}}]}", + new object[] { "f1", "s2" }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"array\", \"items\": \"int\"}}]}", + new object[] { "f1", new object[] { 0, 1, 101 } }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"array\", \"items\": \"int\"}}]}", + new object[] { "f1", new int[] { 0, 1, 101 } }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":[\"int\", \"long\"]}]}", + new object[] { "f1", 100 }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":[\"int\", \"long\"]}]}", + new object[] { "f1", 100L }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"fixed\", \"name\": \"f\", \"size\": 2}}]}", + new object[] { "f1", new byte[] { 1, 2 } }, Codec.Type.Deflate)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"null\"}]}", + new object[] { "f1", null }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"boolean\"}]}", + new object[] { "f1", true }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"boolean\"}]}", + new object[] { "f1", false }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"int\"}]}", + new object[] { "f1", 101 }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"long\"}]}", + new object[] { "f1", 101L }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"float\"}]}", + new object[] { "f1", 101.78f }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"double\"}]}", + new object[] { "f1", 101.78 }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"string\"}]}", + new object[] { "f1", "A" }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"bytes\"}]}", + new object[] { "f1", new byte[] { 0, 1 } }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"enum\", \"name\": \"e\", \"symbols\":[\"s1\", \"s2\"]}}]}", + new object[] { "f1", "s2" }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"array\", \"items\": \"int\"}}]}", + new object[] { "f1", new object[] { 0, 1, 101 } }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"array\", \"items\": \"int\"}}]}", + new object[] { "f1", new int[] { 0, 1, 101 } }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":[\"int\", \"long\"]}]}", + new object[] { "f1", 100 }, Codec.Type.Null)] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":[\"int\", \"long\"]}]}", + new object[] { "f1", 100L }, Codec.Type.Null)] + public void TestGenericData(string schemaStr, object[] value, Codec.Type codecType) + { + foreach(var rwFactory in GenericOptions()) + { + // Create and write out + MemoryStream dataFileOutputStream = new MemoryStream(); + using (var writer = rwFactory.CreateWriter(dataFileOutputStream, Schema.Parse(schemaStr), Codec.CreateCodec(codecType))) + { + writer.Append(mkRecord(value, Schema.Parse(schemaStr) as RecordSchema)); + } + + MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray()); + + // Read back + IList readFoos = new List(); + using (IFileReader reader = rwFactory.CreateReader(dataFileInputStream,null)) + { + foreach (GenericRecord foo in reader.NextEntries) + { + readFoos.Add(foo); + } + } + + Assert.IsTrue((readFoos != null && readFoos.Count > 0), + string.Format(@"Generic object: {0} did not serialise/deserialise correctly", readFoos)); + } + } + + /// + /// Reading & writing of primitive objects + /// + /// + /// + /// + [TestCase("{\"type\": \"boolean\"}", true, Codec.Type.Deflate)] + [TestCase("{\"type\": \"boolean\"}", false, Codec.Type.Deflate)] + [TestCase("{\"type\": \"boolean\"}", true, Codec.Type.Null)] + [TestCase("{\"type\": \"boolean\"}", false, Codec.Type.Null)] + [TestCase("[\"boolean\", \"null\"]", null, Codec.Type.Deflate)] + [TestCase("[\"boolean\", \"null\"]", true, Codec.Type.Deflate)] + [TestCase("[\"int\", \"long\"]", 100, Codec.Type.Deflate)] + [TestCase("[\"int\", \"long\"]", 100L, Codec.Type.Deflate)] + [TestCase("[\"float\", \"double\"]", 100.75, Codec.Type.Deflate)] + [TestCase("[\"float\", \"double\"]", 23.67f, Codec.Type.Deflate)] + [TestCase("[{\"type\": \"array\", \"items\": \"float\"}, \"double\"]", new float[] { 23.67f, 22.78f }, Codec.Type.Deflate)] + [TestCase("[{\"type\": \"array\", \"items\": \"float\"}, \"double\"]", 100.89, Codec.Type.Deflate)] + [TestCase("[{\"type\": \"array\", \"items\": \"string\"}, \"string\"]", "a", Codec.Type.Deflate)] + [TestCase("[{\"type\": \"array\", \"items\": \"string\"}, \"string\"]", new string[] { "a", "b" }, Codec.Type.Deflate)] + [TestCase("[{\"type\": \"array\", \"items\": \"bytes\"}, \"bytes\"]", new byte[] { 1, 2, 3 }, Codec.Type.Deflate)] + [TestCase("[{\"type\": \"array\", \"items\": \"bytes\"}, \"bytes\"]", new object[] { new byte[] { 1, 2 }, new byte[] { 3, 4 } }, Codec.Type.Deflate)] + [TestCase("[{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}, \"string\"]", "h1", Codec.Type.Deflate)] + [TestCase("{\"type\":\"string\"}", "John", Codec.Type.Deflate)] + [TestCase("{\"type\":[\"null\",\"string\"]}", null, Codec.Type.Deflate)] + [TestCase("{\"type\":\"int\"}", 1, Codec.Type.Deflate)] + [TestCase("{\"type\":\"boolean\"}", false, Codec.Type.Deflate)] + [TestCase("{\"type\":\"long\"}", 12312313123L, Codec.Type.Deflate)] + [TestCase("{\"type\":\"float\"}", 0.0f, Codec.Type.Deflate)] + [TestCase("{\"type\":\"double\"}", 0.0, Codec.Type.Deflate)] + [TestCase("[\"boolean\", \"null\"]", null, Codec.Type.Null)] + [TestCase("[\"boolean\", \"null\"]", true, Codec.Type.Null)] + [TestCase("[\"int\", \"long\"]", 100, Codec.Type.Null)] + [TestCase("[\"int\", \"long\"]", 100L, Codec.Type.Null)] + [TestCase("[\"float\", \"double\"]", 100.75, Codec.Type.Null)] + [TestCase("[\"float\", \"double\"]", 23.67f, Codec.Type.Null)] + [TestCase("[{\"type\": \"array\", \"items\": \"float\"}, \"double\"]", new float[] { 23.67f, 22.78f }, Codec.Type.Null)] + [TestCase("[{\"type\": \"array\", \"items\": \"float\"}, \"double\"]", 100.89, Codec.Type.Null)] + [TestCase("[{\"type\": \"array\", \"items\": \"string\"}, \"string\"]", "a", Codec.Type.Null)] + [TestCase("[{\"type\": \"array\", \"items\": \"string\"}, \"string\"]", new string[] { "a", "b" }, Codec.Type.Null)] + [TestCase("[{\"type\": \"array\", \"items\": \"bytes\"}, \"bytes\"]", new byte[] { 1, 2, 3 }, Codec.Type.Null)] + [TestCase("[{\"type\": \"array\", \"items\": \"bytes\"}, \"bytes\"]", new object[] { new byte[] { 1, 2 }, new byte[] { 3, 4 } }, Codec.Type.Null)] + [TestCase("[{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}, \"string\"]", "h1", Codec.Type.Null)] + [TestCase("{\"type\":\"string\"}", "John", Codec.Type.Null)] + [TestCase("{\"type\":[\"null\",\"string\"]}", null, Codec.Type.Null)] + [TestCase("{\"type\":\"int\"}", 1, Codec.Type.Null)] + [TestCase("{\"type\":\"boolean\"}", false, Codec.Type.Null)] + [TestCase("{\"type\":\"long\"}", 12312313123L, Codec.Type.Null)] + [TestCase("{\"type\":\"float\"}", 0.0f, Codec.Type.Null)] + [TestCase("{\"type\":\"double\"}", 0.0, Codec.Type.Null)] + [TestCase("{\"type\":\"string\"}", "test", Codec.Type.Null)] + public void TestPrimitiveData(string schemaStr, object value, Codec.Type codecType) + { + foreach(var rwFactory in GenericOptions()) + { + MemoryStream dataFileOutputStream = new MemoryStream(); + using (var writer = rwFactory.CreateWriter(dataFileOutputStream, Schema.Parse(schemaStr), Codec.CreateCodec(codecType))) + { + writer.Append(value); + } + + MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray()); + + Assert.IsTrue(CheckPrimitive(dataFileInputStream, value, rwFactory.CreateReader), + string.Format("Error reading generic data for object: {0}", value)); + } + } + + /// + /// Reading & writing of header meta data + /// + /// + /// + /// + [TestCase("bytesTest", new byte[] { 1, 2, 3 }, Codec.Type.Null, true)] + [TestCase("stringTest", "testVal", Codec.Type.Null, true)] + [TestCase("longTest", 12312313123L, Codec.Type.Null, true)] + [TestCase("bytesTest", new byte[] { 1 }, Codec.Type.Null, true)] + [TestCase("longTest", -1211212L, Codec.Type.Null, true)] + [TestCase("bytesTest", new byte[] { 1, 2, 3 }, Codec.Type.Deflate, true)] + [TestCase("stringTest", "testVal", Codec.Type.Deflate, true)] + [TestCase("longTest", 12312313123L, Codec.Type.Deflate, true)] + [TestCase("bytesTest", new byte[] { 1 }, Codec.Type.Deflate, true)] + [TestCase("longTest", -21211212L, Codec.Type.Deflate, true)] + [TestCase("bytesTest", new byte[] { 1, 2, 3 }, Codec.Type.Null, false)] + [TestCase("stringTest", "testVal", Codec.Type.Null, false)] + [TestCase("longTest", 12312313123L, Codec.Type.Null, false)] + [TestCase("bytesTest", new byte[] { 1 }, Codec.Type.Null, false)] + [TestCase("longTest", -1211212L, Codec.Type.Null, false)] + [TestCase("bytesTest", new byte[] { 1, 2, 3 }, Codec.Type.Deflate, false)] + [TestCase("stringTest", "testVal", Codec.Type.Deflate, false)] + [TestCase("longTest", 12312313123L, Codec.Type.Deflate, false)] + [TestCase("bytesTest", new byte[] { 1 }, Codec.Type.Deflate, false)] + [TestCase("longTest", -21211212L, Codec.Type.Deflate, false)] + public void TestMetaData(string key, object value, Codec.Type codecType, bool useTypeGetter) + { + // create and write out + object[] obj = new object[] { new object[] { "John", 23 } }; + IList records = MakeRecords(obj); + MemoryStream dataFileOutputStream = new MemoryStream(); + + Schema schema = Schema.Parse(specificSchema); + DatumWriter writer = new SpecificWriter(schema); + using (IFileWriter dataFileWriter = DataFileWriter.OpenWriter(writer, dataFileOutputStream, Codec.CreateCodec(codecType))) + { + SetMetaData(dataFileWriter, key, value); + foreach (Foo rec in records) + dataFileWriter.Append(rec); + } + + MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray()); + + // read back + using (IFileReader reader = DataFileReader.OpenReader(dataFileInputStream)) + { + Assert.IsTrue(ValidateMetaData(reader, key, value, useTypeGetter), + string.Format("Error validating header meta data for key: {0}, expected value: {1}", key, value)); + } + } + + /// + /// Partial reading of file / stream from + /// position in stream + /// + /// + /// + /// + [TestCase(specificSchema, Codec.Type.Null, 1, 330)] // 330 + [TestCase(specificSchema, Codec.Type.Null, 135, 330)] // 330 + [TestCase(specificSchema, Codec.Type.Null, 194, 264)] // 264 + [TestCase(specificSchema, Codec.Type.Null, 235, 264)] // 264 + [TestCase(specificSchema, Codec.Type.Null, 888, 165)] // 165 + [TestCase(specificSchema, Codec.Type.Null, 0, 330)] // 330 + public void TestPartialRead(string schemaStr, Codec.Type codecType, int position, int expectedRecords) + { + // create and write out + IList records = MakeRecords(GetTestFooObject()); + + MemoryStream dataFileOutputStream = new MemoryStream(); + + Schema schema = Schema.Parse(schemaStr); + DatumWriter writer = new SpecificWriter(schema); + using (IFileWriter dataFileWriter = DataFileWriter.OpenWriter(writer, dataFileOutputStream, Codec.CreateCodec(codecType))) + { + for (int i = 0; i < 10; ++i) + { + foreach (Foo foo in records) + { + dataFileWriter.Append(foo); + } + + // write out block + if (i == 1 || i == 4) + { + dataFileWriter.Sync(); + } + } + } + + MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray()); + + // read back + IList readRecords = new List(); + using (IFileReader reader = DataFileReader.OpenReader(dataFileInputStream)) + { + // move to next block from position + reader.Sync(position); + + // read records from synced position + foreach (Foo rec in reader.NextEntries) + readRecords.Add(rec); + } + + Assert.IsTrue((readRecords != null && readRecords.Count == expectedRecords), + string.Format("Error performing partial read after position: {0}", position)); + } + + /// + /// Partial reading of file / stream from position in stream + /// Tests reading from sync boundaries. + /// + /// + /// + /// + [TestCase(specificSchema, Codec.Type.Null)] + [TestCase(specificSchema, Codec.Type.Deflate)] + public void TestPartialReadAll(string schemaStr, Codec.Type codecType) + { + // create and write out + IList records = MakeRecords(GetTestFooObject()); + + MemoryStream dataFileOutputStream = new MemoryStream(); + + Schema schema = Schema.Parse(schemaStr); + DatumWriter writer = new SpecificWriter(schema); + int numRecords = 0; + List syncLogs = new List(); + using (IFileWriter dataFileWriter = DataFileWriter.OpenWriter(writer, dataFileOutputStream, Codec.CreateCodec(codecType))) + { + dataFileWriter.Flush(); + syncLogs.Add(new SyncLog { Position = dataFileOutputStream.Position - DataFileConstants.SyncSize + 1, RemainingRecords = numRecords }); + long lastPosition = dataFileOutputStream.Position; + for (int i = 0; i < 10; ++i) + { + foreach (Foo foo in records) + { + dataFileWriter.Append(foo); + if (dataFileOutputStream.Position != lastPosition) + { + syncLogs.Add(new SyncLog { Position = dataFileOutputStream.Position - DataFileConstants.SyncSize + 1, RemainingRecords = numRecords }); + lastPosition = dataFileOutputStream.Position; + } + numRecords++; + } + + // write out block + if (i == 1 || i == 4) + { + dataFileWriter.Sync(); + syncLogs.Add(new SyncLog { Position = dataFileOutputStream.Position - DataFileConstants.SyncSize + 1, RemainingRecords = numRecords }); + lastPosition = dataFileOutputStream.Position; + } + } + dataFileWriter.Flush(); + syncLogs.Add(new SyncLog { Position = dataFileOutputStream.Position, RemainingRecords = numRecords }); + } + + MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray()); + + // read back + using (IFileReader reader = DataFileReader.OpenReader(dataFileInputStream)) + { + long curPosition = 0; + + foreach (SyncLog syncLog in syncLogs) + { + int expectedRecords = numRecords - syncLog.RemainingRecords; + long nextSyncPoint = syncLog.Position; + AssertNumRecordsFromPosition( reader, curPosition, expectedRecords ); + AssertNumRecordsFromPosition( reader, nextSyncPoint - 1, expectedRecords ); + curPosition = nextSyncPoint; + } + } + } + + class SyncLog + { + public long Position { get; set; } + public int RemainingRecords { get; set; } + } + + private static void AssertNumRecordsFromPosition( IFileReader reader, long position, int expectedRecords ) + { + // move to next block from position + reader.Sync( position ); + + int readRecords = 0; + // read records from synced position + foreach( Foo rec in reader.NextEntries ) + { + readRecords++; + } + Assert.AreEqual( expectedRecords, readRecords, "didn't read expected records from position " + position ); + } + + /// + /// Reading all sync positions and + /// verifying them with subsequent seek + /// positions + /// + [TestCase(specificSchema, Codec.Type.Null, 2, 0, 1)] + [TestCase(specificSchema, Codec.Type.Null, 10, 1, 4)] + [TestCase(specificSchema, Codec.Type.Null, 200, 111, 15)] + [TestCase(specificSchema, Codec.Type.Null, 1000, 588, 998)] + [TestCase(specificSchema, Codec.Type.Deflate, 2, 0, 1)] + [TestCase(specificSchema, Codec.Type.Deflate, 10, 1, 4)] + [TestCase(specificSchema, Codec.Type.Deflate, 200, 111, 15)] + [TestCase(specificSchema, Codec.Type.Deflate, 1000, 588, 998)] + public void TestSyncAndSeekPositions(string schemaStr, Codec.Type codecType, int iterations, int firstSyncPosition, int secondSyncPosition) + { + // create and write out + IList records = MakeRecords(GetTestFooObject()); + MemoryStream dataFileOutputStream = new MemoryStream(); + + Schema schema = Schema.Parse(schemaStr); + DatumWriter writer = new SpecificWriter(schema); + using (IFileWriter dataFileWriter = DataFileWriter.OpenWriter(writer, dataFileOutputStream, Codec.CreateCodec(codecType))) + { + for (int i = 0; i < iterations; ++i) + { + foreach (Foo foo in records) + dataFileWriter.Append(foo); + + // write out block + if (i == firstSyncPosition || i == secondSyncPosition) + dataFileWriter.Sync(); + } + } + + MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray()); + + // read syncs + IList syncs = new List(); + using (IFileReader reader = DataFileReader.OpenReader(dataFileInputStream)) + { + long previousSync = -1; + + foreach (Foo foo in reader.NextEntries) + { + if (reader.PreviousSync() != previousSync + && reader.Tell() != reader.PreviousSync()) // EOF + { + previousSync = reader.PreviousSync(); + syncs.Add(previousSync); + } + } + + // verify syncs wth seeks + reader.Sync(0); // first sync + Assert.AreEqual(reader.PreviousSync(), syncs[0], + string.Format("Error syncing reader to position: {0}", syncs[0])); + + foreach (long sync in syncs) // the rest + { + reader.Seek(sync); + Foo foo = reader.Next(); + Assert.IsNotNull(foo, string.Format("Error seeking to sync position: {0}", sync)); + } + } + } + + [TestCase] + public void TestDifferentReaderSchema() + { + RecordSchema writerSchema = Schema.Parse( "{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"string\"}," + + "{\"name\":\"f2\", \"type\":\"string\"}]}" ) as RecordSchema; + Schema readerSchema = Schema.Parse( "{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"string\"}," + +"{\"name\":\"f3\", \"type\":\"string\", \"default\":\"test\"}]}" ); + + foreach(var rwFactory in GenericOptions()) + { + MemoryStream dataFileOutputStream = new MemoryStream(); + + using (var writer = rwFactory.CreateWriter(dataFileOutputStream, writerSchema, Codec.CreateCodec(Codec.Type.Null))) + { + writer.Append(mkRecord(new [] { "f1", "f1val", "f2", "f2val" }, writerSchema)); + } + + MemoryStream dataFileInputStream = new MemoryStream(dataFileOutputStream.ToArray()); + + using (IFileReader reader = rwFactory.CreateReader(dataFileInputStream, readerSchema)) + { + GenericRecord result = reader.Next(); + object ignore; + Assert.IsFalse(result.TryGetValue("f2", out ignore)); + Assert.AreEqual("f1val", result["f1"]); + Assert.AreEqual("test", result["f3"]); + } + } + } + + private bool CheckPrimitive(Stream input, T value, ReaderWriterPair.ReaderFactory createReader) + { + IFileReader reader = createReader(input, null); + IList readFoos = new List(); + foreach (T foo in reader.NextEntries) + { + readFoos.Add(foo); + } + return (readFoos.Count > 0 && + CheckPrimitiveEquals(value, readFoos[0])); + } + + private bool CheckPrimitiveEquals(object first, object second) + { + if (first is IList) + { + var firstList = (IList) first; + var secondList = (IList) second; + if (firstList.Count != secondList.Count) + { + return false; + } + for (int i = 0; i < firstList.Count; i++) + { + if (!CheckPrimitiveEquals(firstList[i], secondList[i])) + { + return false; + } + } + return true; + } + return (first == null && second == null) || (first.Equals(second)); + } + + private static GenericRecord mkRecord(object[] kv, RecordSchema s) + { + GenericRecord input = new GenericRecord(s); + for (int i = 0; i < kv.Length; i += 2) + { + string fieldName = (string)kv[i]; + object fieldValue = kv[i + 1]; + Schema inner = s[fieldName].Schema; + if (inner is EnumSchema) + { + GenericEnum ge = new GenericEnum(inner as EnumSchema, (string)fieldValue); + fieldValue = ge; + } + else if (inner is FixedSchema) + { + GenericFixed gf = new GenericFixed(inner as FixedSchema); + gf.Value = (byte[])fieldValue; + fieldValue = gf; + } + input.Add(fieldName, fieldValue); + } + return input; + } + + private IList MakeRecords(object[] recs) + { + IList records = new List(); + + foreach (object obj in recs) + { + object[] inner = (object[])obj; + Foo newFoo = new Foo { name = (String)inner[0], age = (int)inner[1] }; + records.Add(newFoo); + } + return records; + } + + private bool ValidateMetaData(IFileReader reader, + string key, + object expected, + bool useTypeGetter) + { + byte[] valueBytes = reader.GetMeta(key); + + if (expected is byte[]) + { + Byte[] expectedBytes = new Byte[valueBytes.Length]; + expectedBytes = (byte[])expected; + return Enumerable.SequenceEqual(expectedBytes, valueBytes); + } + else if (expected is long) + { + if (useTypeGetter) + return ((long)expected == reader.GetMetaLong(key)); + else + return ((long)expected == long.Parse(System.Text.Encoding.UTF8.GetString(valueBytes))); + } + else + { + if (useTypeGetter) + return ((string)expected == reader.GetMetaString(key)); + else + return ((string)expected == System.Text.Encoding.UTF8.GetString(valueBytes)); + } + } + + private void SetMetaData(IFileWriter dataFileWriter, string key, object value) + { + if (value is byte[]) + dataFileWriter.SetMeta(key, (byte[])value); + else if (value is long) + dataFileWriter.SetMeta(key, (long)value); + else + dataFileWriter.SetMeta(key, (string)value); + } + + private object[] GetTestFooObject() + { + return new object[] { new object[] {"John", 23}, new object[] { "Jane", 99 }, new object[] { "Jeff", 88 }, + new object[] {"James", 13}, new object[] { "June", 109 }, new object[] { "Lloyd", 18 }, + new object[] {"Jamie", 53}, new object[] { "Fanessa", 101 }, new object[] { "Kan", 18 }, + new object[] {"Janey", 33}, new object[] { "Deva", 102 }, new object[] { "Gavin", 28 }, + new object[] {"Lochy", 113}, new object[] { "Nickie", 10 }, new object[] { "Liddia", 38 }, + new object[] {"Fred", 3}, new object[] { "April", 17 }, new object[] { "Novac", 48 }, + new object[] {"Idan", 33}, new object[] { "Jolyon", 76 }, new object[] { "Ant", 68 }, + new object[] {"Ernie", 43}, new object[] { "Joel", 99 }, new object[] { "Dan", 78 }, + new object[] {"Dave", 103}, new object[] { "Hillary", 79 }, new object[] { "Grant", 88 }, + new object[] {"JJ", 14}, new object[] { "Bill", 90 }, new object[] { "Larry", 4 }, + new object[] {"Jenny", 3}, new object[] { "Bob", 9 }, new object[] { null, 48 }}; + } + + private static IEnumerable> SpecificOptions() + { + yield return new ReaderWriterPair + { + CreateReader = (stream, schema) => DataFileReader.OpenReader(stream, schema), + CreateWriter = (stream, schema, codec) => + DataFileWriter.OpenWriter(new SpecificWriter(schema), stream, codec ) + }; + + yield return new ReaderWriterPair + { + CreateReader = (stream, schema) => DataFileReader.OpenReader(stream, schema, + (ws, rs) => new SpecificDatumReader(ws, rs)), + CreateWriter = (stream, schema, codec) => + DataFileWriter.OpenWriter(new SpecificDatumWriter(schema), stream, codec ) + }; + } + + private static IEnumerable> GenericOptions() + { + yield return new ReaderWriterPair + { + CreateReader = (stream, schema) => DataFileReader.OpenReader(stream, schema), + CreateWriter = (stream, schema, codec) => + DataFileWriter.OpenWriter(new GenericWriter(schema), stream, codec ) + }; + + yield return new ReaderWriterPair + { + CreateReader = (stream, schema) => DataFileReader.OpenReader(stream, schema, + (ws, rs) => new GenericDatumReader(ws, rs)), + CreateWriter = (stream, schema, codec) => + DataFileWriter.OpenWriter(new GenericDatumWriter(schema), stream, codec ) + }; + } + + class ReaderWriterPair + { + public delegate IFileWriter WriterFactory(Stream stream, Schema writerSchema, Codec codec); + public delegate IFileReader ReaderFactory(Stream stream, Schema readerSchema); + + public WriterFactory CreateWriter { get; set; } + public ReaderFactory CreateReader { get; set; } + } + } + + + // Foo (Specific) + public class Foo : ISpecificRecord + { + public string name { get; set; } + public int age { get; set; } + + public Schema Schema + { + get + { + return Schema.Parse("{\"type\":\"record\",\"name\":\"Foo\",\"namespace\":\"Avro.Test.File\"," + + "\"fields\":[{\"name\":\"name\",\"type\":\"string\"},{\"name\":\"age\",\"type\":\"int\"}]}"); + } + } + + public object Get(int fieldPos) + { + switch (fieldPos) + { + case 0: + return name; + case 1: + return age; + } + throw new Exception("Invalid index " + fieldPos); + } + + public void Put(int fieldPos, object fieldValue) + { + switch (fieldPos) + { + case 0: + name = (string)fieldValue; + break; + case 1: + age = (int) fieldValue; + break; + default: + throw new Exception("Invalid index " + fieldPos); + } + } + + public override string ToString() + { + return string.Format("Name: {0}, Age: {1}", name, age); + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/HeaderDTO.cs b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/HeaderDTO.cs new file mode 100644 index 00000000000..13fd97ff380 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/HeaderDTO.cs @@ -0,0 +1,57 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace Avro.Test.Generic.Autogen +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class HeaderDTO : ISpecificRecord + { + public static Schema _SCHEMA = Avro.Schema.Parse("{\"type\":\"record\",\"name\":\"HeaderDTO\",\"namespace\":\"Avro.Test.Generic.Autogen\",\"fiel" + + "ds\":[{\"name\":\"Info\",\"type\":[\"null\",{\"type\":\"record\",\"name\":\"InfoDto\",\"namespace\"" + + ":\"Avro.Test.Generic.Autogen\",\"fields\":[{\"name\":\"Count\",\"type\":\"int\"}]}]}]}"); + private Avro.Test.Generic.Autogen.InfoDto _Info; + public virtual Schema Schema + { + get + { + return HeaderDTO._SCHEMA; + } + } + public Avro.Test.Generic.Autogen.InfoDto Info + { + get + { + return this._Info; + } + set + { + this._Info = value; + } + } + public virtual object Get(int fieldPos) + { + switch (fieldPos) + { + case 0: return this.Info; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Get()"); + }; + } + public virtual void Put(int fieldPos, object fieldValue) + { + switch (fieldPos) + { + case 0: this.Info = (Avro.Test.Generic.Autogen.InfoDto)fieldValue; break; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Put()"); + }; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/InfoDto.cs b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/InfoDto.cs new file mode 100644 index 00000000000..dc5dc7092e4 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/InfoDto.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace Avro.Test.Generic.Autogen +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class InfoDto : ISpecificRecord + { + public static Schema _SCHEMA = Avro.Schema.Parse("{\"type\":\"record\",\"name\":\"InfoDto\",\"namespace\":\"Avro.Test.Generic.Autogen\",\"fields" + + "\":[{\"name\":\"Count\",\"type\":\"int\"}]}"); + private int _Count; + public virtual Schema Schema + { + get + { + return InfoDto._SCHEMA; + } + } + public int Count + { + get + { + return this._Count; + } + set + { + this._Count = value; + } + } + public virtual object Get(int fieldPos) + { + switch (fieldPos) + { + case 0: return this.Count; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Get()"); + }; + } + public virtual void Put(int fieldPos, object fieldValue) + { + switch (fieldPos) + { + case 0: this.Count = (System.Int32)fieldValue; break; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Put()"); + }; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocol.avdl b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocol.avdl new file mode 100644 index 00000000000..10493a8e6d3 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocol.avdl @@ -0,0 +1,16 @@ +/** +* Test Protocol +*/ + +@namespace("Avro.Test.Generic.Autogen") + +protocol TestProtocol { + + record InfoDto { + int Count; + } + + record HeaderDTO { + union {null, InfoDto} Info; + } +} \ No newline at end of file diff --git a/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocol.cs b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocol.cs new file mode 100644 index 00000000000..c5fabd2bcce --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocol.cs @@ -0,0 +1,34 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace Avro.Test.Generic.Autogen +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + /// + /// * Headers + /// + public abstract class TestProtocol : Avro.Specific.ISpecificProtocol + { + private static readonly Avro.Protocol protocol = Avro.Protocol.Parse(@"{""protocol"":""TestProtocol"",""namespace"":""Avro.Test.Generic.Autogen"",""doc"":""* Headers"",""types"":[{""type"":""record"",""name"":""InfoDto"",""namespace"":""Avro.Test.Generic.Autogen"",""fields"":[{""name"":""Count"",""type"":""int""}]},{""type"":""record"",""name"":""HeaderDTO"",""namespace"":""Avro.Test.Generic.Autogen"",""fields"":[{""name"":""Info"",""type"":[""null"",""InfoDto""]}]}],""messages"":{}}"); + public Avro.Protocol Protocol + { + get + { + return protocol; + } + } + public void Request(Avro.Specific.ICallbackRequestor requestor, string messageName, object[] args, object callback) + { + ; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocolCallback.cs b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocolCallback.cs new file mode 100644 index 00000000000..b9b20b46ad2 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/TestProtocolCallback.cs @@ -0,0 +1,22 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace Avro.Test.Generic.Autogen +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + /// + /// * Headers + /// + public abstract class TestProtocolCallback : TestProtocol + { + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/readme.md b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/readme.md new file mode 100644 index 00000000000..da8dabf91cf --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Generic/Autogen/readme.md @@ -0,0 +1,13 @@ +# Avro test data + +This folder contains the Avro IDL file for reference as well as the actual auto-generated .cs files. If you want to regenerate these, you'll need to get the tools yourself and create the .cs files as follows (adjust paths as needed) + +## Create the intermediate avpr from the avdl + +`java.exe -jar avro-tools-1.8.1.jar idl TestProtocol.avdl > TestProtocol.avpr` + +## Create the .cs files from the intermediate avpr + +`avrogen.exe -p TestProtocol.avpr .` + +Now move the autogenerate .cs files to replace the existing ones diff --git a/lang/csharp/src/apache/test.dotnetcore/Generic/GenericSerializationTests.cs b/lang/csharp/src/apache/test.dotnetcore/Generic/GenericSerializationTests.cs new file mode 100644 index 00000000000..6b9b5c2e82b --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Generic/GenericSerializationTests.cs @@ -0,0 +1,59 @@ +using System.IO; +using Avro.IO; +using Avro.Specific; +using Avro.Test.Generic.Autogen; +using Newtonsoft.Json; +using NUnit.Framework; + +namespace Avro.Test.Generic +{ + [TestFixture] + public class GenericSerializationTests + { + [Test] + public void RoundTripObject() + { + // original object + var origObj = new HeaderDTO() + { + Info = new InfoDto() + { + Count = 1, + } + }; + + // Serialize + var origObjBytes = Serialize(origObj); + + // Deserialize + var regenObj = Deserialize(origObjBytes); + + // Verify everything survived the roundtrip, simplest to compare their JSON + Assert.IsTrue(string.Equals(JsonConvert.SerializeObject(origObj), JsonConvert.SerializeObject(regenObj))); + } + + public static byte[] Serialize(T thisObj) where T : ISpecificRecord + { + using (var ms = new MemoryStream()) + { + var enc = new BinaryEncoder(ms); + var writer = new SpecificDefaultWriter(thisObj.Schema); // Schema comes from pre-compiled, code-gen phase + writer.Write(thisObj, enc); + return ms.ToArray(); + } + } + + public static T Deserialize(byte[] bytes) where T : ISpecificRecord, new() + { + using (var ms = new MemoryStream(bytes)) + { + var dec = new BinaryDecoder(ms); + var regenObj = new T(); + + var reader = new SpecificDefaultReader(regenObj.Schema, regenObj.Schema); + reader.Read(regenObj, dec); + return regenObj; + } + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Generic/GenericTests.cs b/lang/csharp/src/apache/test.dotnetcore/Generic/GenericTests.cs new file mode 100644 index 00000000000..af9805c3334 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Generic/GenericTests.cs @@ -0,0 +1,496 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.IO; +using System.Linq; +using Avro.IO; +using System.Collections.Generic; +using Avro.Generic; +using NUnit.Framework; + +namespace Avro.Test.Generic +{ + class GenericTests + { + private static void test(string s, T value) + { + Stream ms; + Schema ws; + serialize(s, value, out ms, out ws); + Schema rs = Schema.Parse(s); + T output = deserialize(ms, ws, rs); + Assert.AreEqual(value, output); + } + + [TestCase("{\"type\": \"boolean\"}", true)] + [TestCase("{\"type\": \"boolean\"}", false)] + + // Union + [TestCase("[\"boolean\", \"null\"]", null)] + [TestCase("[\"boolean\", \"null\"]", true)] + [TestCase("[\"int\", \"long\"]", 100)] + [TestCase("[\"int\", \"long\"]", 100L)] + [TestCase("[\"float\", \"double\"]", 100.75)] + [TestCase("[\"float\", \"double\"]", 23.67f)] + [TestCase("[{\"type\": \"array\", \"items\": \"float\"}, \"double\"]", new float[] { 23.67f, 22.78f })] + [TestCase("[{\"type\": \"array\", \"items\": \"float\"}, \"double\"]", 100.89)] + [TestCase("[{\"type\": \"array\", \"items\": \"string\"}, \"string\"]", "a")] + [TestCase("[{\"type\": \"array\", \"items\": \"string\"}, \"string\"]", new string[] { "a", "b" })] + [TestCase("[{\"type\": \"array\", \"items\": \"bytes\"}, \"bytes\"]", new byte[] { 1, 2, 3 })] + [TestCase("[{\"type\": \"array\", \"items\": \"bytes\"}, \"bytes\"]", + new object[] { new byte[] { 1, 2 }, new byte[] { 3, 4 } })] + [TestCase("[{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}, \"string\"]", "h1")] + public void TestPrimitive(string schema, object value) + { + test(schema, value); + } + + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"null\"}]}", + new object[] { "f1", null })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"boolean\"}]}", + new object[] { "f1", true })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"boolean\"}]}", + new object[] { "f1", false })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"int\"}]}", + new object[] { "f1", 101 })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"long\"}]}", + new object[] { "f1", 101L })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"float\"}]}", + new object[] { "f1", 101.78f })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"double\"}]}", + new object[] { "f1", 101.78 })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"string\"}]}", + new object[] { "f1", "A" })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"bytes\"}]}", + new object[] { "f1", new byte[] { 0, 1 } })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"enum\", \"name\": \"e\", \"symbols\":[\"s1\", \"s2\"]}}]}", + new object[] { "f1", "s2" })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"array\", \"items\": \"int\"}}]}", + new object[] { "f1", new object[] { 0, 1, 101 } })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"array\", \"items\": \"int\"}}]}", + new object[] { "f1", new int[] { 0, 1, 101 } })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":[\"int\", \"long\"]}]}", + new object[] { "f1", 100 })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":[\"int\", \"long\"]}]}", + new object[] { "f1", 100L })] + [TestCase("{\"type\":\"record\", \"name\":\"n\", \"fields\":" + + "[{\"name\":\"f1\", \"type\":{\"type\": \"fixed\", \"name\": \"f\", \"size\": 2}}]}", + new object[] { "f1", new byte[] { 1, 2 } })] + public void TestRecord(string schema, object[] kv) + { + test(schema, mkRecord(kv, Schema.Parse(schema) as RecordSchema)); + } + + [TestCase("{\"type\": \"map\", \"values\": \"string\"}", + new object[] { "a", "0", "b", "1", "c", "101" })] + public void TestMap(string schema, object[] values) + { + test(schema, mkMap(values)); + } + + [TestCase("[{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"string\"}]}, \"string\"]", + "{\"type\":\"record\", \"name\":\"n\", \"fields\":[{\"name\":\"f1\", \"type\":\"string\"}]}", + new object[] { "f1", "v1" })] + public void TestUnion_record(string unionSchema, string recordSchema, object[] value) + { + test(unionSchema, mkRecord(value, Schema.Parse(recordSchema) as RecordSchema)); + } + + [TestCase("[{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}, \"string\"]", + "{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}", "s1")] + [TestCase("[{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}, \"string\"]", + "{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}", "s2")] + [TestCase("[{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}, \"string\"]", + "{\"type\": \"enum\", \"symbols\": [\"s1\", \"s2\"], \"name\": \"e\"}", "s3", + typeof(AvroException))] + public void TestUnion_enum(string unionSchema, string enumSchema, string value, Type exceptionType = null) + { + if (exceptionType == null) + test(unionSchema, mkEnum(enumSchema, value)); + else + Assert.Throws(exceptionType, () => test(unionSchema, mkEnum(enumSchema, value))); + } + + + [TestCase("[{\"type\": \"map\", \"values\": \"int\"}, \"string\"]", + "{\"type\": \"map\", \"values\": \"int\"}", new object[] { "a", 1, "b", 2 })] + public void TestUnion_map(string unionSchema, string mapSchema, object[] value) + { + test(unionSchema, mkMap(value)); + } + + [TestCase("[{\"type\": \"fixed\", \"size\": 2, \"name\": \"f\"}, \"string\"]", + "{\"type\": \"fixed\", \"size\": 2, \"name\": \"f\"}", new byte[] { 1, 2 })] + [TestCase("[{\"type\": \"fixed\", \"size\": 2, \"name\": \"f\"}, \"string\"]", + "{\"type\": \"fixed\", \"size\": 2, \"name\": \"f\"}", new byte[] { 1, 2, 3 }, + typeof(AvroException))] + [TestCase("[{\"type\": \"fixed\", \"size\": 2, \"name\": \"f\"}, \"string\"]", + "{\"type\": \"fixed\", \"size\": 3, \"name\": \"f\"}", new byte[] { 1, 2, 3 }, + typeof(AvroException))] + public void TestUnion_fixed(string unionSchema, string fixedSchema, byte[] value, Type exceptionType = null) + { + if (exceptionType == null) + test(unionSchema, mkFixed(fixedSchema, value)); + else + Assert.Throws(exceptionType, () => test(unionSchema, mkFixed(fixedSchema, value))); + } + + public void TestResolution(string writerSchema, T actual, string readerSchema, S expected) + { + Stream ms; + Schema ws; + serialize(writerSchema, actual, out ms, out ws); + Schema rs = Schema.Parse(readerSchema); + S output = deserialize(ms, ws, rs); + Assert.AreEqual(expected, output); + } + + [TestCase("int", 10, "long", 10L)] + [TestCase("int", 10, "float", 10.0f)] + [TestCase("int", 10, "double", 10.0)] + [TestCase("long", 10L, "float", 10.0f)] + [TestCase("long", 10L, "double", 10.0)] + [TestCase("float", 10.0f, "double", 10.0)] + [TestCase("{\"type\":\"array\", \"items\":\"int\"}", new int[] { 10, 20 }, + "{\"type\":\"array\", \"items\":\"long\"}", new object[] { 10L, 20L })] + [TestCase("[\"int\", \"boolean\"]", true, "[\"boolean\", \"double\"]", true)] + [TestCase("[\"int\", \"boolean\"]", 10, "[\"boolean\", \"double\"]", 10.0)] + [TestCase("[\"int\", \"boolean\"]", 10, "\"int\"", 10)] + [TestCase("[\"int\", \"boolean\"]", 10, "\"double\"", 10.0)] + [TestCase("\"int\"", 10, "[\"int\", \"boolean\"]", 10)] + [TestCase("\"int\"", 10, "[\"long\", \"boolean\"]", 10L)] + public void TestResolution_simple(string writerSchema, object actual, string readerSchema, object expected) + { + TestResolution(writerSchema, actual, readerSchema, expected); + } + + [Test] + public void TestResolution_intMapToLongMap() + { + TestResolution("{\"type\":\"map\", \"values\":\"int\"}", mkMap(new object[] { "a", 10, "b", 20 }), + "{\"type\":\"map\", \"values\":\"long\"}", mkMap(new object[] { "a", 10L, "b", 20L })); + } + + [Test] + public void TestResolution_enum() + { + string ws = "{\"type\":\"enum\", \"symbols\":[\"a\", \"b\"], \"name\":\"e\"}"; + string rs = "{\"type\":\"enum\", \"symbols\":[\"a\", \"b\"], \"name\":\"e\"}"; + TestResolution(ws, mkEnum(ws, "a"), rs, mkEnum(rs, "a")); + } + + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"boolean\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", true, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"},{\"name\":\"f1\",\"type\":\"boolean\"}]}", + new object[] { "f1", true, "f2", 100 }, Description = "Out of order fields")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"boolean\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", true, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"boolean\"},{\"name\":\"f2\",\"type\":\"long\"}]}", + new object[] { "f1", true, "f2", 100L }, Description = "Field promotion")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"boolean\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", true, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"boolean\"}]}", + new object[] { "f1", true }, Description = "Missing fields - 1")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"null\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", null, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - null")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"boolean\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", true, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - boolean")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"int\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 1, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - int")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"long\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 1L, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - long")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"float\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 1.0f, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - float")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"double\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 1.0, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - double")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"bytes\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", new byte[] { 1 , 0 }, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - bytes")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"string\"},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", "h", "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - string")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":{\"type\":\"array\",\"items\":\"int\"}},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", new int[] { 100, 101 }, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - array")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":[\"int\", \"null\"]},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 101, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f2", 100 }, Description = "Missing fields - union")] + // TODO: Missing fields - record, enum, map, fixed + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"boolean\"}]}", + new object[] { "f1", true }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":\"boolean\"},{\"name\":\"f2\",\"type\":\"string\",\"default\":\"d\"}]}", + new object[] { "f1", true, "f2", "d" }, Description = "Default field")] + public void TestResolution_record(string ws, object[] actual, string rs, object[] expected) + { + TestResolution(ws, mkRecord(actual, Schema.Parse(ws) as RecordSchema), rs, + mkRecord(expected, Schema.Parse(rs) as RecordSchema)); + } + + [TestCase("{\"type\":\"map\",\"values\":\"int\"}", new object[] { "a", 100, "b", -202 }, + "{\"type\":\"map\",\"values\":\"long\"}", new object[] { "a", 100L, "b", -202L })] + public void TestResolution_intMapToLongMap(string ws, object[] value, string rs, object[] expected) + { + TestResolution(ws, mkMap(value), rs, mkMap(expected)); + } + + + private static void testResolutionMismatch(string writerSchema, T value, string readerSchema) + { + Stream ms; + Schema ws; + serialize(writerSchema, value, out ms, out ws); + deserialize(ms, ws, Schema.Parse(readerSchema)); + } + + [TestCase("boolean", true, "null", typeof(AvroException))] + [TestCase("int", 10, "boolean", typeof(AvroException))] + [TestCase("int", 10, "string", typeof(AvroException))] + [TestCase("int", 10, "bytes", typeof(AvroException))] + [TestCase("int", 10, "{\"type\":\"record\",\"name\":\"r\",\"fields\":[{\"name\":\"f\", \"type\":\"int\"}]}", typeof(AvroException))] + [TestCase("int", 10, "{\"type\":\"enum\",\"name\":\"e\",\"symbols\":[\"s\", \"t\"]}", typeof(AvroException))] + [TestCase("int", 10, "{\"type\":\"array\",\"items\":\"int\"}", typeof(AvroException))] + [TestCase("int", 10, "{\"type\":\"map\",\"values\":\"int\"}", typeof(AvroException))] + [TestCase("int", 10, "[\"string\", \"bytes\"]", typeof(AvroException))] + [TestCase("int", 10, "{\"type\":\"fixed\",\"name\":\"f\",\"size\":2}", typeof(AvroException))] + [TestCase("{\"type\":\"array\",\"items\":\"int\"}", new int[] { 10 }, "\"boolean\"", typeof(AvroException))] + [TestCase("{\"type\":\"array\",\"items\":\"int\"}", new int[] { 10 }, "{\"type\":\"array\",\"items\":\"string\"}", typeof(AvroException))] + [TestCase("[\"int\", \"boolean\"]", 10, "[\"string\", \"bytes\"]", typeof(AvroException))] + [TestCase("[\"int\", \"boolean\"]", 10, "\"string\"", typeof(AvroException))] + public void TestResolutionMismatch_simple(string writerSchema, object value, string readerSchema, Type exceptionType) + { + Assert.Throws(exceptionType, () => testResolutionMismatch(writerSchema, value, readerSchema)); + } + + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":[\"int\", \"null\"]},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 101, "f2", 100 }, "int", + typeof(AvroException), Description = "Non-record schema")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":[\"int\", \"null\"]},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 101, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"s\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"int\"}]}", + typeof(AvroException), Description = "Name mismatch")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":[\"int\", \"null\"]},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 101, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f2\",\"type\":\"string\"}]}", + typeof(AvroException), Description = "incompatible field")] + [TestCase("{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f1\",\"type\":[\"int\", \"null\"]},{\"name\":\"f2\",\"type\":\"int\"}]}", + new object[] { "f1", 101, "f2", 100 }, + "{\"type\":\"record\",\"name\":\"r\",\"fields\":" + + "[{\"name\":\"f3\",\"type\":\"string\"}]}", + typeof(AvroException), Description = "new field without default")] + public void TestResolutionMismatch_record(string ws, object[] actual, string rs, Type exceptionType) + { + Assert.Throws(exceptionType, () => testResolutionMismatch(ws, mkRecord(actual, Schema.Parse(ws) as RecordSchema), rs)); + } + + [TestCase("{\"type\":\"enum\",\"name\":\"e\",\"symbols\":[\"s\", \"t\"]}", "s", "int", + typeof(AvroException), Description = "Non-enum schema")] + [TestCase("{\"type\":\"enum\",\"name\":\"e\",\"symbols\":[\"s\", \"t\"]}", + "s", "{\"type\":\"enum\",\"name\":\"f\",\"symbols\":[\"s\", \"t\"]}", + typeof(AvroException), Description = "Name mismatch")] + [TestCase("{\"type\":\"enum\",\"name\":\"e\",\"symbols\":[\"s\", \"t\"]}", + "s", "{\"type\":\"enum\",\"name\":\"f\",\"symbols\":[\"t\", \"u\"]}", + typeof(AvroException), Description = "Incompatible symbols")] + public void TestResolutionMismatch_enum(string ws, string value, string rs, Type exceptionType) + { + Assert.Throws(exceptionType, () => testResolutionMismatch(ws, mkEnum(ws, value), rs)); + } + + [TestCase("{\"type\":\"map\",\"values\":\"int\"}", new object[] { "a", 0 }, "int", + typeof(AvroException), Description = "Non-map schema")] + [TestCase("{\"type\":\"map\",\"values\":\"int\"}", + new object[] { "a", 0 }, "{\"type\":\"map\",\"values\":\"string\"}", + typeof(AvroException), Description = "Name mismatch")] + public void TestResolutionMismatch_map(string ws, object[] value, string rs, Type exceptionType) + { + Assert.Throws(exceptionType, () => testResolutionMismatch(ws, mkMap(value), rs)); + } + + [TestCase("{\"type\":\"fixed\",\"name\":\"f\",\"size\":2}", new byte[] { 1, 1 }, "int", + typeof(AvroException), Description = "Non-fixed schema")] + [TestCase("{\"type\":\"fixed\",\"name\":\"f\",\"size\":2}", + new byte[] { 1, 1 }, "{\"type\":\"fixed\",\"name\":\"g\",\"size\":2}", + typeof(AvroException), Description = "Name mismatch")] + [TestCase("{\"type\":\"fixed\",\"name\":\"f\",\"size\":2}", + new byte[] { 1, 1 }, "{\"type\":\"fixed\",\"name\":\"f\",\"size\":1}", + typeof(AvroException), Description = "Size mismatch")] + public void TestResolutionMismatch_fixed(string ws, byte[] value, string rs, Type exceptionType) + { + Assert.Throws(exceptionType, () => testResolutionMismatch(ws, mkFixed(ws, value), rs)); + } + + private static GenericRecord mkRecord(object[] kv, RecordSchema s) + { + GenericRecord input = new GenericRecord(s); + for (int i = 0; i < kv.Length; i += 2) + { + string fieldName = (string)kv[i]; + object fieldValue = kv[i + 1]; + Schema inner = s[fieldName].Schema; + if (inner is EnumSchema) + { + GenericEnum ge = new GenericEnum(inner as EnumSchema, (string)fieldValue); + fieldValue = ge; + } + else if (inner is FixedSchema) + { + GenericFixed gf = new GenericFixed(inner as FixedSchema); + gf.Value = (byte[])fieldValue; + fieldValue = gf; + } + input.Add(fieldName, fieldValue); + } + return input; + } + + private static IDictionary mkMap(object[] vv) + { + IDictionary d = new Dictionary(); + for (int j = 0; j < vv.Length; j += 2) + { + d[(string)vv[j]] = vv[j + 1]; + } + return d; + } + + private static object mkEnum(string enumSchema, string value) + { + return new GenericEnum(Schema.Parse(enumSchema) as EnumSchema, value); + } + + private static object mkFixed(string fixedSchema, byte[] value) + { + return new GenericFixed(Schema.Parse(fixedSchema) as FixedSchema, value); + } + + private static S deserialize(Stream ms, Schema ws, Schema rs) + { + long initialPos = ms.Position; + GenericReader r = new GenericReader(ws, rs); + Decoder d = new BinaryDecoder(ms); + var items = new List(); + // validate reading twice to make sure there isn't some state that isn't reset between reads. + items.Add( Read( r, d ) ); + items.Add( Read( r, d ) ); + Assert.AreEqual(ms.Length, ms.Position); // Ensure we have read everything. + checkAlternateDeserializers(items, ms, initialPos, ws, rs); + return items[0]; + } + + private static S Read( DatumReader reader, Decoder d ) + { + S reuse = default( S ); + return reader.Read( reuse, d ); + } + + private static void checkAlternateDeserializers(IEnumerable expectations, Stream input, long startPos, Schema ws, Schema rs) + { + input.Position = startPos; + var reader = new GenericDatumReader(ws, rs); + Decoder d = new BinaryDecoder(input); + foreach( var expected in expectations ) + { + var read = Read( reader, d ); + Assert.AreEqual(expected, read); + } + Assert.AreEqual(input.Length, input.Position); // Ensure we have read everything. + } + + private static void serialize(string writerSchema, T actual, out Stream stream, out Schema ws) + { + var ms = new MemoryStream(); + Encoder e = new BinaryEncoder(ms); + ws = Schema.Parse(writerSchema); + GenericWriter w = new GenericWriter(ws); + // write twice so we can validate reading twice + w.Write(actual, e); + w.Write(actual, e); + ms.Flush(); + ms.Position = 0; + checkAlternateSerializers(ms.ToArray(), actual, ws); + stream = ms; + } + + private static void checkAlternateSerializers(byte[] expected, T value, Schema ws) + { + var ms = new MemoryStream(); + var writer = new GenericDatumWriter(ws); + var e = new BinaryEncoder(ms); + writer.Write(value, e); + writer.Write(value, e); + var output = ms.ToArray(); + + Assert.AreEqual(expected.Length, output.Length); + Assert.True(expected.SequenceEqual(output)); + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/IO/BinaryCodecTests.cs b/lang/csharp/src/apache/test.dotnetcore/IO/BinaryCodecTests.cs new file mode 100644 index 00000000000..b6d2e89258d --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/IO/BinaryCodecTests.cs @@ -0,0 +1,334 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using System.IO; + +using Avro.IO; + +namespace Avro.Test +{ + using Decoder = Avro.IO.Decoder; + using Encoder = Avro.IO.Encoder; + delegate T Decode(Decoder d); + delegate void Skip(Decoder d); + delegate void Encode(Encoder e, T t); + + /// + /// Tests the BinaryEncoder and BinaryDecoder. This is pertty general set of test cases and hence + /// can be used for any encoder and its corresponding decoder. + /// + [TestFixture] + public class BinaryCodecTests + { + + /// + /// Writes an avro type T with value t into a stream using the encode method e + /// and reads it back using the decode method d and verifies that + /// the value read back is the same as the one written in. + /// + /// Avro type to test + /// Value for the Avro type to test. + /// The decode method + /// The encode method + private void TestRead(T t, Decode r, Encode w, int size) + { + MemoryStream iostr = new MemoryStream(); + Encoder e = new BinaryEncoder(iostr); + w(e, t); + iostr.Flush(); + Assert.AreEqual(size, iostr.Length); + iostr.Position = 0; + Decoder d = new BinaryDecoder(iostr); + T actual = r(d); + Assert.AreEqual(t, actual); + Assert.AreEqual(-1, iostr.ReadByte()); + iostr.Close(); + } + + /// + /// Writes an avro type T with value t into a stream using the encode method e + /// and reads it back using the decode method d and verifies that + /// the value read back is the same as the one written in. + /// + /// Avro type to test + /// Value for the Avro type to test. + /// The skip method + /// The encode method + private void TestSkip(T t, Skip s, Encode w, int size) + { + MemoryStream iostr = new MemoryStream(); + Encoder e = new BinaryEncoder(iostr); + w(e, t); + iostr.Flush(); + Assert.AreEqual(size, iostr.Length); + iostr.Position = 0; + Decoder d = new BinaryDecoder(iostr); + s(d); + Assert.AreEqual(-1, iostr.ReadByte()); + iostr.Close(); + } + + + [TestCase(true)] + [TestCase(false)] + public void TestBoolean(bool b) + { + TestRead(b, (Decoder d) => d.ReadBoolean(), (Encoder e, bool t) => e.WriteBoolean(t), 1); + TestSkip(b, (Decoder d) => d.SkipBoolean(), (Encoder e, bool t) => e.WriteBoolean(t), 1); + } + + [TestCase(0, 1)] + [TestCase(1, 1)] + [TestCase(63, 1)] + [TestCase(64, 2)] + [TestCase(8191, 2)] + [TestCase(8192, 3)] + [TestCase(1048575, 3)] + [TestCase(1048576, 4)] + [TestCase(134217727, 4)] + [TestCase(134217728, 5)] + [TestCase(2147483647, 5)] + [TestCase(-1, 1)] + [TestCase(-64, 1)] + [TestCase(-65, 2)] + [TestCase(-8192, 2)] + [TestCase(-8193, 3)] + [TestCase(-1048576, 3)] + [TestCase(-1048577, 4)] + [TestCase(-134217728, 4)] + [TestCase(-134217729, 5)] + [TestCase(-2147483648, 5)] + public void TestInt(int n, int size) + { + TestRead(n, (Decoder d) => d.ReadInt(), (Encoder e, int t) => e.WriteInt(t), size); + TestSkip(n, (Decoder d) => d.SkipInt(), (Encoder e, int t) => e.WriteInt(t), size); + } + + [TestCase(0, 1)] + [TestCase(1, 1)] + [TestCase(63, 1)] + [TestCase(64, 2)] + [TestCase(8191, 2)] + [TestCase(8192, 3)] + [TestCase(1048575, 3)] + [TestCase(1048576, 4)] + [TestCase(134217727, 4)] + [TestCase(134217728, 5)] + [TestCase(17179869183L, 5)] + [TestCase(17179869184L, 6)] + [TestCase(2199023255551L, 6)] + [TestCase(2199023255552L, 7)] + [TestCase(281474976710655L, 7)] + [TestCase(281474976710656L, 8)] + [TestCase(36028797018963967L, 8)] + [TestCase(36028797018963968L, 9)] + [TestCase(4611686018427387903L, 9)] + [TestCase(4611686018427387904L, 10)] + [TestCase(9223372036854775807L, 10)] + [TestCase(-1, 1)] + [TestCase(-64, 1)] + [TestCase(-65, 2)] + [TestCase(-8192, 2)] + [TestCase(-8193, 3)] + [TestCase(-1048576, 3)] + [TestCase(-1048577, 4)] + [TestCase(-134217728, 4)] + [TestCase(-134217729, 5)] + [TestCase(-17179869184L, 5)] + [TestCase(-17179869185L, 6)] + [TestCase(-2199023255552L, 6)] + [TestCase(-2199023255553L, 7)] + [TestCase(-281474976710656L, 7)] + [TestCase(-281474976710657L, 8)] + [TestCase(-36028797018963968L, 8)] + [TestCase(-36028797018963969L, 9)] + [TestCase(-4611686018427387904L, 9)] + [TestCase(-4611686018427387905L, 10)] + [TestCase(-9223372036854775808L, 10)] + public void TestLong(long n, int size) + { + TestRead(n, (Decoder d) => d.ReadLong(), (Encoder e, long t) => e.WriteLong(t), size); + TestSkip(n, (Decoder d) => d.SkipLong(), (Encoder e, long t) => e.WriteLong(t), size); + } + + [TestCase(0.0f)] + [TestCase(Single.MaxValue, Description = "Max value")] + [TestCase(1.17549435E-38f, Description = "Min 'normal' value")] + [TestCase(1.4e-45f, Description = "Min value")] + public void TestFloat(float n) + { + TestRead(n, (Decoder d) => d.ReadFloat(), (Encoder e, float t) => e.WriteFloat(t), 4); + TestSkip(n, (Decoder d) => d.SkipFloat(), (Encoder e, float t) => e.WriteFloat(t), 4); + } + + [TestCase(0.0)] + [TestCase(1.7976931348623157e+308, Description = "Max value")] + [TestCase(2.2250738585072014E-308, Description = "Min 'normal' value")] + [TestCase(4.9e-324, Description = "Min value")] + public void TestDouble(double n) + { + TestRead(n, (Decoder d) => d.ReadDouble(), (Encoder e, double t) => e.WriteDouble(t), 8); + TestSkip(n, (Decoder d) => d.SkipDouble(), (Encoder e, double t) => e.WriteDouble(t), 8); + } + + + [TestCase(0, 1)] + [TestCase(5, 1)] + [TestCase(63, 1)] + [TestCase(64, 2)] + [TestCase(8191, 2)] + [TestCase(8192, 3)] + public void TestBytes(int length, int overhead) + { + Random r = new Random(); + byte[] b = new byte[length]; + r.NextBytes(b); + TestRead(b, (Decoder d) => d.ReadBytes(), (Encoder e, byte[] t) => e.WriteBytes(t), overhead + b.Length); + TestSkip(b, (Decoder d) => d.SkipBytes(), (Encoder e, byte[] t) => e.WriteBytes(t), overhead + b.Length); + } + + [TestCase("", 1)] + [TestCase("hello", 1)] + [TestCase("1234567890123456789012345678901234567890123456789012345678901234", 2)] + public void TestString(string n, int overhead) + { + TestRead(n, (Decoder d) => d.ReadString(), (Encoder e, string t) => e.WriteString(t), overhead + n.Length); + TestSkip(n, (Decoder d) => d.SkipString(), (Encoder e, string t) => e.WriteString(t), overhead + n.Length); + } + + [TestCase(0, 1)] + [TestCase(1, 1)] + [TestCase(64, 2)] + public void TestEnum(int n, int size) + { + TestRead(n, (Decoder d) => d.ReadEnum(), (Encoder e, int t) => e.WriteEnum(t), size); + TestSkip(n, (Decoder d) => d.SkipEnum(), (Encoder e, int t) => e.WriteEnum(t), size); + } + + [TestCase(1, new int[] { })] + [TestCase(3, new int[] { 0 })] + [TestCase(4, new int[] { 64 })] + public void TestArray(int size, int[] entries) + { + TestRead(entries, (Decoder d) => + { + int[] t = new int[entries.Length]; + int j = 0; + for (long n = d.ReadArrayStart(); n != 0; n = d.ReadArrayNext()) + { + for (int i = 0; i < n; i++) { t[j++] = d.ReadInt(); } + + } + return t; + }, + (Encoder e, int[] t) => + { + e.WriteArrayStart(); + e.SetItemCount(t.Length); + foreach (int i in t) { e.StartItem(); e.WriteInt(i); } e.WriteArrayEnd(); + }, size); + + TestSkip(entries, (Decoder d) => + { + for (long n = d.ReadArrayStart(); n != 0; n = d.ReadArrayNext()) + { + for (int i = 0; i < n; i++) { d.SkipInt(); } + + } + }, + (Encoder e, int[] t) => + { + e.WriteArrayStart(); + e.SetItemCount(t.Length); + foreach (int i in t) { e.StartItem(); e.WriteInt(i); } e.WriteArrayEnd(); + }, size); + } + + [TestCase(1, new string[] { })] + [TestCase(6, new string[] { "a", "b" })] + [TestCase(9, new string[] { "a", "b", "c", "" })] + public void TestMap(int size, string[] entries) + { + TestRead(entries, (Decoder d) => + { + string[] t = new string[entries.Length]; + int j = 0; + for (long n = d.ReadArrayStart(); n != 0; n = d.ReadArrayNext()) + { + for (int i = 0; i < n; i++) { t[j++] = d.ReadString(); t[j++] = d.ReadString(); } + + } + return t; + }, + (Encoder e, string[] t) => + { + e.WriteArrayStart(); + e.SetItemCount(t.Length / 2); + for (int i = 0; i < t.Length; i += 2) + { + e.StartItem(); e.WriteString(t[i]); e.WriteString(t[i + 1]); + } + e.WriteArrayEnd(); + }, size); + + TestSkip(entries, (Decoder d) => + { + for (long n = d.ReadArrayStart(); n != 0; n = d.ReadArrayNext()) + { + for (int i = 0; i < n; i++) { d.SkipString(); d.SkipString(); } + + } + }, + (Encoder e, string[] t) => + { + e.WriteArrayStart(); + e.SetItemCount(t.Length / 2); + for (int i = 0; i < t.Length; i += 2) + { + e.StartItem(); e.WriteString(t[i]); e.WriteString(t[i + 1]); + } + e.WriteArrayEnd(); + }, size); + } + + [TestCase(0, 1)] + [TestCase(1, 1)] + [TestCase(64, 2)] + public void TestUnionIndex(int n, int size) + { + TestRead(n, (Decoder d) => d.ReadUnionIndex(), (Encoder e, int t) => e.WriteUnionIndex(t), size); + TestSkip(n, (Decoder d) => d.SkipUnionIndex(), (Encoder e, int t) => e.WriteUnionIndex(t), size); + } + + [TestCase(0)] + [TestCase(1)] + [TestCase(64)] + public void TestFixed(int size) + { + byte[] b = new byte[size]; + new Random().NextBytes(b); + TestRead(b, (Decoder d) => { byte[] t = new byte[size]; d.ReadFixed(t); return t; }, + (Encoder e, byte[] t) => e.WriteFixed(t), size); + TestSkip(b, (Decoder d) => d.SkipFixed(size), + (Encoder e, byte[] t) => e.WriteFixed(t), size); + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/All.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/All.cs new file mode 100644 index 00000000000..f1d364882d4 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/All.cs @@ -0,0 +1,95 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + /// + /// * Licensed to the Apache Software Foundation (ASF) under one\r\n * or more contributor license agreements. See the NOTICE file\r\n * distributed with this work for additional information\r\n * regarding copyright ownership. The ASF licenses this file\r\n * to you under the Apache License, Version 2.0 (the\r\n * \"License\"); you may not use this file except in compliance\r\n * with the License. You may obtain a copy of the License at\r\n *\r\n * http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License. + /// + public abstract class All : Avro.Specific.ISpecificProtocol + { + private static readonly Avro.Protocol protocol = Avro.Protocol.Parse("{\r\n \"protocol\": \"All\",\r\n \"namespace\": \"org.apache.avro.test\",\r\n \"doc\": \"* Lice" + + "nsed to the Apache Software Foundation (ASF) under one\\\\r\\\\n * or more contribut" + + "or license agreements. See the NOTICE file\\\\r\\\\n * distributed with this work f" + + "or additional information\\\\r\\\\n * regarding copyright ownership. The ASF licens" + + "es this file\\\\r\\\\n * to you under the Apache License, Version 2.0 (the\\\\r\\\\n * \\" + + "\\\\\"License\\\\\\\"); you may not use this file except in compliance\\\\r\\\\n * with the" + + " License. You may obtain a copy of the License at\\\\r\\\\n *\\\\r\\\\n * http://ww" + + "w.apache.org/licenses/LICENSE-2.0\\\\r\\\\n *\\\\r\\\\n * Unless required by applicable " + + "law or agreed to in writing, software\\\\r\\\\n * distributed under the License is d" + + "istributed on an \\\\\\\"AS IS\\\\\\\" BASIS,\\\\r\\\\n * WITHOUT WARRANTIES OR CONDITIONS O" + + "F ANY KIND, either express or implied.\\\\r\\\\n * See the License for the specific " + + "language governing permissions and\\\\r\\\\n * limitations under the License.\",\r\n \"" + + "types\": [\r\n {\r\n \"type\": \"enum\",\r\n \"name\": \"AllEnum\",\r\n \"namesp" + + "ace\": \"org.apache.avro.test\",\r\n \"symbols\": [\r\n \"FOO\",\r\n \"BAR\"" + + "\r\n ]\r\n },\r\n {\r\n \"type\": \"fixed\",\r\n \"name\": \"FixedTest\",\r\n " + + " \"namespace\": \"org.apache.avro.test\",\r\n \"size\": 10\r\n },\r\n {\r\n " + + " \"type\": \"record\",\r\n \"name\": \"AllTestRecord\",\r\n \"namespace\": \"org.apac" + + "he.avro.test\",\r\n \"fields\": [\r\n {\r\n \"name\": \"booleanTest\",\r\n" + + " \"type\": \"boolean\"\r\n },\r\n {\r\n \"name\": \"intTest\"," + + "\r\n \"type\": \"int\"\r\n },\r\n {\r\n \"name\": \"longTest\",\r" + + "\n \"type\": \"long\"\r\n },\r\n {\r\n \"name\": \"floatTest\"," + + "\r\n \"type\": \"float\"\r\n },\r\n {\r\n \"name\": \"doubleTes" + + "t\",\r\n \"type\": \"double\"\r\n },\r\n {\r\n \"name\": \"bytes" + + "Test\",\r\n \"type\": \"bytes\"\r\n },\r\n {\r\n \"name\": \"str" + + "ingTest\",\r\n \"type\": \"string\"\r\n },\r\n {\r\n \"name\": " + + "\"enumTest\",\r\n \"type\": \"AllEnum\"\r\n },\r\n {\r\n \"name" + + "\": \"fixedTest\",\r\n \"type\": \"FixedTest\"\r\n },\r\n {\r\n " + + " \"name\": \"arrayTest\",\r\n \"type\": {\r\n \"type\": \"array\",\r\n " + + " \"items\": \"long\"\r\n }\r\n },\r\n {\r\n \"name\": \"ma" + + "pTest\",\r\n \"type\": {\r\n \"type\": \"map\",\r\n \"values\": " + + "\"long\"\r\n }\r\n },\r\n {\r\n \"name\": \"nestedTest\",\r\n " + + " \"type\": [\r\n \"AllTestRecord\",\r\n \"null\"\r\n ]\r" + + "\n }\r\n ]\r\n }\r\n ],\r\n \"messages\": {\r\n \"echo\": {\r\n \"request" + + "\": [\r\n {\r\n \"name\": \"allTest\",\r\n \"type\": \"AllTestRecord\"" + + "\r\n }\r\n ],\r\n \"response\": \"AllTestRecord\"\r\n },\r\n \"echoParam" + + "eters\": {\r\n \"request\": [\r\n {\r\n \"name\": \"booleanTest\",\r\n " + + " \"type\": \"boolean\"\r\n },\r\n {\r\n \"name\": \"intTest\",\r\n " + + " \"type\": \"int\"\r\n },\r\n {\r\n \"name\": \"longTest\",\r\n " + + " \"type\": \"long\"\r\n },\r\n {\r\n \"name\": \"floatTest\",\r\n " + + " \"type\": \"float\"\r\n },\r\n {\r\n \"name\": \"doubleTest\",\r" + + "\n \"type\": \"double\"\r\n },\r\n {\r\n \"name\": \"bytesTest" + + "\",\r\n \"type\": \"bytes\"\r\n },\r\n {\r\n \"name\": \"stringT" + + "est\",\r\n \"type\": \"string\"\r\n },\r\n {\r\n \"name\": \"enu" + + "mTest\",\r\n \"type\": \"AllEnum\"\r\n },\r\n {\r\n \"name\": \"" + + "fixedTest\",\r\n \"type\": \"FixedTest\"\r\n },\r\n {\r\n \"na" + + "me\": \"arrayTest\",\r\n \"type\": {\r\n \"type\": \"array\",\r\n " + + " \"items\": \"long\"\r\n }\r\n },\r\n {\r\n \"name\": \"mapTes" + + "t\",\r\n \"type\": {\r\n \"type\": \"map\",\r\n \"values\": \"lon" + + "g\"\r\n }\r\n },\r\n {\r\n \"name\": \"nestedTest\",\r\n " + + " \"type\": \"AllTestRecord\"\r\n }\r\n ],\r\n \"response\": \"AllTestRecor" + + "d\"\r\n }\r\n }\r\n}"); + public Avro.Protocol Protocol + { + get + { + return protocol; + } + } + public void Request(Avro.Specific.ICallbackRequestor requestor, string messageName, object[] args, object callback) + { + switch(messageName) + { + case "echo": + requestor.Request(messageName, args, callback); + break; + + case "echoParameters": + requestor.Request(messageName, args, callback); + break; + }; + } + public abstract org.apache.avro.test.AllTestRecord echo(org.apache.avro.test.AllTestRecord allTest); + public abstract org.apache.avro.test.AllTestRecord echoParameters(bool booleanTest, int intTest, long longTest, float floatTest, double doubleTest, byte[] bytesTest, string stringTest, org.apache.avro.test.AllEnum enumTest, org.apache.avro.test.FixedTest fixedTest, IList arrayTest, IDictionary mapTest, org.apache.avro.test.AllTestRecord nestedTest); + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllCallback.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllCallback.cs new file mode 100644 index 00000000000..cd9c688f039 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllCallback.cs @@ -0,0 +1,24 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + /// + /// * Licensed to the Apache Software Foundation (ASF) under one\r\n * or more contributor license agreements. See the NOTICE file\r\n * distributed with this work for additional information\r\n * regarding copyright ownership. The ASF licenses this file\r\n * to you under the Apache License, Version 2.0 (the\r\n * \"License\"); you may not use this file except in compliance\r\n * with the License. You may obtain a copy of the License at\r\n *\r\n * http://www.apache.org/licenses/LICENSE-2.0\r\n *\r\n * Unless required by applicable law or agreed to in writing, software\r\n * distributed under the License is distributed on an \"AS IS\" BASIS,\r\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n * See the License for the specific language governing permissions and\r\n * limitations under the License. + /// + public abstract class AllCallback : All + { + public abstract void echo(org.apache.avro.test.AllTestRecord allTest, Avro.IO.ICallback callback); + public abstract void echoParameters(bool booleanTest, int intTest, long longTest, float floatTest, double doubleTest, byte[] bytesTest, string stringTest, org.apache.avro.test.AllEnum enumTest, org.apache.avro.test.FixedTest fixedTest, IList arrayTest, IDictionary mapTest, org.apache.avro.test.AllTestRecord nestedTest, Avro.IO.ICallback callback); + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllEnum.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllEnum.cs new file mode 100644 index 00000000000..3a4ae29b6ff --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllEnum.cs @@ -0,0 +1,21 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public enum AllEnum + { + FOO, + BAR, + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllTestRecord.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllTestRecord.cs new file mode 100644 index 00000000000..1b881b3a646 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllTestRecord.cs @@ -0,0 +1,209 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class AllTestRecord : ISpecificRecord + { + private static Schema _SCHEMA = Avro.Schema.Parse(@"{""type"":""record"",""name"":""AllTestRecord"",""namespace"":""org.apache.avro.test"",""fields"":[{""name"":""booleanTest"",""type"":""boolean""},{""name"":""intTest"",""type"":""int""},{""name"":""longTest"",""type"":""long""},{""name"":""floatTest"",""type"":""float""},{""name"":""doubleTest"",""type"":""double""},{""name"":""bytesTest"",""type"":""bytes""},{""name"":""stringTest"",""type"":""string""},{""name"":""enumTest"",""type"":{""type"":""enum"",""name"":""AllEnum"",""namespace"":""org.apache.avro.test"",""symbols"":[""FOO"",""BAR""]}},{""name"":""fixedTest"",""type"":{""type"":""fixed"",""name"":""FixedTest"",""namespace"":""org.apache.avro.test"",""size"":10}},{""name"":""arrayTest"",""type"":{""type"":""array"",""items"":""long""}},{""name"":""mapTest"",""type"":{""type"":""map"",""values"":""long""}},{""name"":""nestedTest"",""type"":[""AllTestRecord"",""null""]}]}"); + private bool _booleanTest; + private int _intTest; + private long _longTest; + private float _floatTest; + private double _doubleTest; + private byte[] _bytesTest; + private string _stringTest; + private org.apache.avro.test.AllEnum _enumTest; + private org.apache.avro.test.FixedTest _fixedTest; + private IList _arrayTest; + private IDictionary _mapTest; + private org.apache.avro.test.AllTestRecord _nestedTest; + public virtual Schema Schema + { + get + { + return AllTestRecord._SCHEMA; + } + } + public bool booleanTest + { + get + { + return this._booleanTest; + } + set + { + this._booleanTest = value; + } + } + public int intTest + { + get + { + return this._intTest; + } + set + { + this._intTest = value; + } + } + public long longTest + { + get + { + return this._longTest; + } + set + { + this._longTest = value; + } + } + public float floatTest + { + get + { + return this._floatTest; + } + set + { + this._floatTest = value; + } + } + public double doubleTest + { + get + { + return this._doubleTest; + } + set + { + this._doubleTest = value; + } + } + public byte[] bytesTest + { + get + { + return this._bytesTest; + } + set + { + this._bytesTest = value; + } + } + public string stringTest + { + get + { + return this._stringTest; + } + set + { + this._stringTest = value; + } + } + public org.apache.avro.test.AllEnum enumTest + { + get + { + return this._enumTest; + } + set + { + this._enumTest = value; + } + } + public org.apache.avro.test.FixedTest fixedTest + { + get + { + return this._fixedTest; + } + set + { + this._fixedTest = value; + } + } + public IList arrayTest + { + get + { + return this._arrayTest; + } + set + { + this._arrayTest = value; + } + } + public IDictionary mapTest + { + get + { + return this._mapTest; + } + set + { + this._mapTest = value; + } + } + public org.apache.avro.test.AllTestRecord nestedTest + { + get + { + return this._nestedTest; + } + set + { + this._nestedTest = value; + } + } + public virtual object Get(int fieldPos) + { + switch (fieldPos) + { + case 0: return this.booleanTest; + case 1: return this.intTest; + case 2: return this.longTest; + case 3: return this.floatTest; + case 4: return this.doubleTest; + case 5: return this.bytesTest; + case 6: return this.stringTest; + case 7: return this.enumTest; + case 8: return this.fixedTest; + case 9: return this.arrayTest; + case 10: return this.mapTest; + case 11: return this.nestedTest; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Get()"); + }; + } + public virtual void Put(int fieldPos, object fieldValue) + { + switch (fieldPos) + { + case 0: this.booleanTest = (System.Boolean)fieldValue; break; + case 1: this.intTest = (System.Int32)fieldValue; break; + case 2: this.longTest = (System.Int64)fieldValue; break; + case 3: this.floatTest = (System.Single)fieldValue; break; + case 4: this.doubleTest = (System.Double)fieldValue; break; + case 5: this.bytesTest = (System.Byte[])fieldValue; break; + case 6: this.stringTest = (System.String)fieldValue; break; + case 7: this.enumTest = (org.apache.avro.test.AllEnum)fieldValue; break; + case 8: this.fixedTest = (org.apache.avro.test.FixedTest)fieldValue; break; + case 9: this.arrayTest = (IList)fieldValue; break; + case 10: this.mapTest = (IDictionary)fieldValue; break; + case 11: this.nestedTest = (org.apache.avro.test.AllTestRecord)fieldValue; break; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Put()"); + }; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllTestRecordPartial.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllTestRecordPartial.cs new file mode 100644 index 00000000000..de387d8d977 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/AllTestRecordPartial.cs @@ -0,0 +1,50 @@ +using System.Linq; + +namespace org.apache.avro.test +{ + public partial class AllTestRecord + { + protected bool Equals(AllTestRecord other) + { + bool arrayEqual = _arrayTest.SequenceEqual(other._arrayTest); + bool mapEqual = _mapTest.SequenceEqual(other._mapTest); + bool bytesEqual = _bytesTest.SequenceEqual(other._bytesTest); + + return Equals(_nestedTest, other._nestedTest) && mapEqual && + arrayEqual + && Equals(_fixedTest, other._fixedTest) && + _enumTest == other._enumTest && string.Equals(_stringTest, other._stringTest) && + bytesEqual && _doubleTest.Equals(other._doubleTest) && + _floatTest.Equals(other._floatTest) && _longTest == other._longTest && _intTest == other._intTest && + _booleanTest.Equals(other._booleanTest); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((AllTestRecord) obj); + } + + public override int GetHashCode() + { + unchecked + { + var hashCode = (_nestedTest != null ? _nestedTest.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (_mapTest != null ? _mapTest.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (_arrayTest != null ? _arrayTest.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (_fixedTest != null ? _fixedTest.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (int) _enumTest; + hashCode = (hashCode*397) ^ (_stringTest != null ? _stringTest.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (_bytesTest != null ? _bytesTest.GetHashCode() : 0); + hashCode = (hashCode*397) ^ _doubleTest.GetHashCode(); + hashCode = (hashCode*397) ^ _floatTest.GetHashCode(); + hashCode = (hashCode*397) ^ _longTest.GetHashCode(); + hashCode = (hashCode*397) ^ _intTest; + hashCode = (hashCode*397) ^ _booleanTest.GetHashCode(); + return hashCode; + } + } + } +} \ No newline at end of file diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/FixedTest.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/FixedTest.cs new file mode 100644 index 00000000000..edcc444b407 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/FixedTest.cs @@ -0,0 +1,39 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class FixedTest : SpecificFixed + { + private static Schema _SCHEMA = Avro.Schema.Parse("{\"type\":\"fixed\",\"name\":\"FixedTest\",\"namespace\":\"org.apache.avro.test\",\"size\":10}"); + private static uint fixedSize = 10; + public FixedTest() : + base(fixedSize) + { + } + public override Schema Schema + { + get + { + return FixedTest._SCHEMA; + } + } + public static uint FixedSize + { + get + { + return FixedTest.fixedSize; + } + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Kind.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Kind.cs new file mode 100644 index 00000000000..9f73ad97101 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Kind.cs @@ -0,0 +1,22 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.vshost.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public enum Kind + { + FOO, + BAR, + BAZ, + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/MD5.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/MD5.cs new file mode 100644 index 00000000000..bc80a1b748d --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/MD5.cs @@ -0,0 +1,40 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.vshost.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class MD5 : SpecificFixed + { + private static Schema _SCHEMA = Avro.Schema.Parse("{\"type\":\"fixed\",\"name\":\"MD5\",\"namespace\":\"org.apache.avro.test\",\"size\":16,\"javaAn" + + "notation\":\"org.apache.avro.TestAnnotation\"}"); + private static uint fixedSize = 16; + public MD5() : + base(fixedSize) + { + } + public override Schema Schema + { + get + { + return MD5._SCHEMA; + } + } + public static uint FixedSize + { + get + { + return MD5.fixedSize; + } + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Mail.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Mail.cs new file mode 100644 index 00000000000..9a6fdfcfdb0 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Mail.cs @@ -0,0 +1,87 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public abstract class Mail : Avro.Specific.ISpecificProtocol + { + private static readonly Avro.Protocol protocol = Avro.Protocol.Parse(@"{ + ""protocol"": ""Mail"", + ""namespace"": ""org.apache.avro.test"", + ""types"": [ + { + ""type"": ""record"", + ""name"": ""Message"", + ""namespace"": ""org.apache.avro.test"", + ""fields"": [ + { + ""name"": ""to"", + ""type"": ""string"" + }, + { + ""name"": ""from"", + ""type"": ""string"" + }, + { + ""name"": ""body"", + ""type"": ""string"" + } + ] + } + ], + ""messages"": { + ""send"": { + ""request"": [ + { + ""name"": ""message"", + ""type"": ""Message"" + } + ], + ""response"": ""string"" + }, + ""fireandforget"": { + ""request"": [ + { + ""name"": ""message"", + ""type"": ""Message"" + } + ], + ""response"": ""null"", + ""one-way"": true + } + } +}"); + public Avro.Protocol Protocol + { + get + { + return protocol; + } + } + public void Request(Avro.Specific.ICallbackRequestor requestor, string messageName, object[] args, object callback) + { + switch(messageName) + { + case "send": + requestor.Request(messageName, args, callback); + break; + + case "fireandforget": + requestor.Request(messageName, args, callback); + break; + }; + } + public abstract string send(org.apache.avro.test.Message message); + public abstract void fireandforget(org.apache.avro.test.Message message); + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/MailCallback.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/MailCallback.cs new file mode 100644 index 00000000000..eb25503d94d --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/MailCallback.cs @@ -0,0 +1,20 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public abstract class MailCallback : Mail + { + public abstract void send(org.apache.avro.test.Message message, Avro.IO.ICallback callback); + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Message.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Message.cs new file mode 100644 index 00000000000..ed6c74d1c68 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Message.cs @@ -0,0 +1,85 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class Message : ISpecificRecord + { + private static Schema _SCHEMA = Avro.Schema.Parse("{\"type\":\"record\",\"name\":\"Message\",\"namespace\":\"org.apache.avro.test\",\"fields\":[{\"" + + "name\":\"to\",\"type\":\"string\"},{\"name\":\"from\",\"type\":\"string\"},{\"name\":\"body\",\"type" + + "\":\"string\"}]}"); + private string _to; + private string _from; + private string _body; + public virtual Schema Schema + { + get + { + return Message._SCHEMA; + } + } + public string to + { + get + { + return this._to; + } + set + { + this._to = value; + } + } + public string from + { + get + { + return this._from; + } + set + { + this._from = value; + } + } + public string body + { + get + { + return this._body; + } + set + { + this._body = value; + } + } + public virtual object Get(int fieldPos) + { + switch (fieldPos) + { + case 0: return this.to; + case 1: return this.from; + case 2: return this.body; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Get()"); + }; + } + public virtual void Put(int fieldPos, object fieldValue) + { + switch (fieldPos) + { + case 0: this.to = (System.String)fieldValue; break; + case 1: this.from = (System.String)fieldValue; break; + case 2: this.body = (System.String)fieldValue; break; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Put()"); + }; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Simple.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Simple.cs new file mode 100644 index 00000000000..1902130be2e --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/Simple.cs @@ -0,0 +1,103 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.vshost.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + /// + /// Protocol used for testing. + /// + public abstract class Simple : Avro.Specific.ISpecificProtocol + { + private static readonly Avro.Protocol protocol = Avro.Protocol.Parse("{\r\n \"protocol\": \"Simple\",\r\n \"namespace\": \"org.apache.avro.test\",\r\n \"doc\": \"Pro" + + "tocol used for testing.\",\r\n \"types\": [\r\n {\r\n \"type\": \"enum\",\r\n \"na" + + "me\": \"Kind\",\r\n \"namespace\": \"org.apache.avro.test\",\r\n \"symbols\": [\r\n " + + " \"FOO\",\r\n \"BAR\",\r\n \"BAZ\"\r\n ],\r\n \"javaAnnotation\": \"" + + "org.apache.avro.TestAnnotation\"\r\n },\r\n {\r\n \"type\": \"fixed\",\r\n \"n" + + "ame\": \"MD5\",\r\n \"namespace\": \"org.apache.avro.test\",\r\n \"size\": 16,\r\n " + + " \"javaAnnotation\": \"org.apache.avro.TestAnnotation\"\r\n },\r\n {\r\n \"typ" + + "e\": \"record\",\r\n \"name\": \"TestRecord\",\r\n \"namespace\": \"org.apache.avro." + + "test\",\r\n \"fields\": [\r\n {\r\n \"name\": \"name\",\r\n \"type" + + "\": \"string\",\r\n \"javaAnnotation\": \"org.apache.avro.TestAnnotation\"\r\n " + + " },\r\n {\r\n \"name\": \"kind\",\r\n \"type\": \"Kind\"\r\n " + + "},\r\n {\r\n \"name\": \"hash\",\r\n \"type\": \"MD5\"\r\n }\r\n " + + " ],\r\n \"javaAnnotation\": \"org.apache.avro.TestAnnotation\"\r\n },\r\n {\r" + + "\n \"type\": \"error\",\r\n \"name\": \"TestError\",\r\n \"namespace\": \"org.apa" + + "che.avro.test\",\r\n \"fields\": [\r\n {\r\n \"name\": \"message\",\r\n " + + " \"type\": \"string\"\r\n }\r\n ]\r\n },\r\n {\r\n \"type\": \"recor" + + "d\",\r\n \"name\": \"TestRecordWithUnion\",\r\n \"namespace\": \"org.apache.avro.t" + + "est\",\r\n \"fields\": [\r\n {\r\n \"name\": \"kind\",\r\n \"type\"" + + ": [\r\n \"null\",\r\n \"Kind\"\r\n ]\r\n },\r\n {" + + "\r\n \"name\": \"value\",\r\n \"type\": [\r\n \"null\",\r\n " + + " \"string\"\r\n ]\r\n }\r\n ]\r\n }\r\n ],\r\n \"messages\": {\r\n " + + " \"hello\": {\r\n \"doc\": \"Send a greeting\",\r\n \"request\": [\r\n {\r\n " + + " \"name\": \"greeting\",\r\n \"type\": \"string\"\r\n }\r\n ],\r\n " + + " \"response\": \"string\"\r\n },\r\n \"echo\": {\r\n \"doc\": \"Pretend you\'re in " + + "a cave!\",\r\n \"request\": [\r\n {\r\n \"name\": \"record\",\r\n " + + " \"type\": \"TestRecord\"\r\n }\r\n ],\r\n \"response\": \"TestRecord\"\r\n " + + "},\r\n \"add\": {\r\n \"request\": [\r\n {\r\n \"name\": \"arg1\",\r\n " + + " \"type\": \"int\"\r\n },\r\n {\r\n \"name\": \"arg2\",\r\n " + + " \"type\": \"int\"\r\n }\r\n ],\r\n \"response\": \"int\"\r\n },\r\n \"echoB" + + "ytes\": {\r\n \"request\": [\r\n {\r\n \"name\": \"data\",\r\n \"t" + + "ype\": \"bytes\"\r\n }\r\n ],\r\n \"response\": \"bytes\"\r\n },\r\n \"erro" + + "r\": {\r\n \"doc\": \"Always throws an error.\",\r\n \"request\": [],\r\n \"res" + + "ponse\": \"null\",\r\n \"errors\": [\r\n \"TestError\"\r\n ]\r\n },\r\n \"a" + + "ck\": {\r\n \"doc\": \"Send a one way message\",\r\n \"request\": [],\r\n \"res" + + "ponse\": \"null\",\r\n \"one-way\": true\r\n }\r\n }\r\n}"); + public Avro.Protocol Protocol + { + get + { + return protocol; + } + } + public void Request(Avro.Specific.ICallbackRequestor requestor, string messageName, object[] args, object callback) + { + switch(messageName) + { + case "hello": + requestor.Request(messageName, args, callback); + break; + + case "echo": + requestor.Request(messageName, args, callback); + break; + + case "add": + requestor.Request(messageName, args, callback); + break; + + case "echoBytes": + requestor.Request(messageName, args, callback); + break; + + case "error": + requestor.Request(messageName, args, callback); + break; + + case "ack": + requestor.Request(messageName, args, callback); + break; + }; + } + // Send a greeting + public abstract string hello(string greeting); + // Pretend you're in a cave! + public abstract org.apache.avro.test.TestRecord echo(org.apache.avro.test.TestRecord record); + public abstract int add(int arg1, int arg2); + public abstract byte[] echoBytes(byte[] data); + // Always throws an error. + public abstract object error(); + // Send a one way message + public abstract void ack(); + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/SimpleCallback.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/SimpleCallback.cs new file mode 100644 index 00000000000..4e5054dd317 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/SimpleCallback.cs @@ -0,0 +1,30 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.vshost.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + /// + /// Protocol used for testing. + /// + public abstract class SimpleCallback : Simple + { + // Send a greeting + public abstract void hello(string greeting, Avro.IO.ICallback callback); + // Pretend you're in a cave! + public abstract void echo(org.apache.avro.test.TestRecord record, Avro.IO.ICallback callback); + public abstract void add(int arg1, int arg2, Avro.IO.ICallback callback); + public abstract void echoBytes(byte[] data, Avro.IO.ICallback callback); + // Always throws an error. + public abstract void error(Avro.IO.ICallback callback); + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestError.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestError.cs new file mode 100644 index 00000000000..1ea2e688fbf --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestError.cs @@ -0,0 +1,56 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.vshost.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class TestError : SpecificException + { + private static Schema _SCHEMA = Avro.Schema.Parse("{\"type\":\"error\",\"name\":\"TestError\",\"namespace\":\"org.apache.avro.test\",\"fields\":[{" + + "\"name\":\"message\",\"type\":\"string\"}]}"); + private string _message; + public override Schema Schema + { + get + { + return TestError._SCHEMA; + } + } + public string message + { + get + { + return this._message; + } + set + { + this._message = value; + } + } + public override object Get(int fieldPos) + { + switch (fieldPos) + { + case 0: return this.message; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Get()"); + }; + } + public override void Put(int fieldPos, object fieldValue) + { + switch (fieldPos) + { + case 0: this.message = (System.String)fieldValue; break; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Put()"); + }; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecord.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecord.cs new file mode 100644 index 00000000000..899b4522572 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecord.cs @@ -0,0 +1,83 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.vshost.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class TestRecord : ISpecificRecord + { + private static Schema _SCHEMA = Avro.Schema.Parse(@"{""type"":""record"",""name"":""TestRecord"",""namespace"":""org.apache.avro.test"",""fields"":[{""name"":""name"",""type"":""string"",""javaAnnotation"":""org.apache.avro.TestAnnotation""},{""name"":""kind"",""type"":{""type"":""enum"",""name"":""Kind"",""namespace"":""org.apache.avro.test"",""symbols"":[""FOO"",""BAR"",""BAZ""],""javaAnnotation"":""org.apache.avro.TestAnnotation""}},{""name"":""hash"",""type"":{""type"":""fixed"",""name"":""MD5"",""namespace"":""org.apache.avro.test"",""size"":16,""javaAnnotation"":""org.apache.avro.TestAnnotation""}}],""javaAnnotation"":""org.apache.avro.TestAnnotation""}"); + private string _name; + private org.apache.avro.test.Kind _kind; + private org.apache.avro.test.MD5 _hash; + public virtual Schema Schema + { + get + { + return TestRecord._SCHEMA; + } + } + public string name + { + get + { + return this._name; + } + set + { + this._name = value; + } + } + public org.apache.avro.test.Kind kind + { + get + { + return this._kind; + } + set + { + this._kind = value; + } + } + public org.apache.avro.test.MD5 hash + { + get + { + return this._hash; + } + set + { + this._hash = value; + } + } + public virtual object Get(int fieldPos) + { + switch (fieldPos) + { + case 0: return this.name; + case 1: return this.kind; + case 2: return this.hash; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Get()"); + }; + } + public virtual void Put(int fieldPos, object fieldValue) + { + switch (fieldPos) + { + case 0: this.name = (System.String)fieldValue; break; + case 1: this.kind = (org.apache.avro.test.Kind)fieldValue; break; + case 2: this.hash = (org.apache.avro.test.MD5)fieldValue; break; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Put()"); + }; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecordExtensions.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecordExtensions.cs new file mode 100644 index 00000000000..83346231b52 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecordExtensions.cs @@ -0,0 +1,29 @@ +namespace org.apache.avro.test +{ + public partial class TestRecord + { + protected bool Equals(TestRecord other) + { + return string.Equals(_name, other._name) && _kind == other._kind && Equals(_hash, other._hash); + } + + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != this.GetType()) return false; + return Equals((TestRecord) obj); + } + + public override int GetHashCode() + { + unchecked + { + int hashCode = (_name != null ? _name.GetHashCode() : 0); + hashCode = (hashCode*397) ^ (int) _kind; + hashCode = (hashCode*397) ^ (_hash != null ? _hash.GetHashCode() : 0); + return hashCode; + } + } + } +} \ No newline at end of file diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecordWithUnion.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecordWithUnion.cs new file mode 100644 index 00000000000..f2b4251964c --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/GeneratedFiles/org/apache/avro/test/TestRecordWithUnion.cs @@ -0,0 +1,69 @@ +// ------------------------------------------------------------------------------ +// +// Generated by avrogen.vshost.exe, version 0.9.0.0 +// Changes to this file may cause incorrect behavior and will be lost if code +// is regenerated +// +// ------------------------------------------------------------------------------ +namespace org.apache.avro.test +{ + using System; + using System.Collections.Generic; + using System.Text; + using Avro; + using Avro.Specific; + + public partial class TestRecordWithUnion : ISpecificRecord + { + private static Schema _SCHEMA = Avro.Schema.Parse(@"{""type"":""record"",""name"":""TestRecordWithUnion"",""namespace"":""org.apache.avro.test"",""fields"":[{""name"":""kind"",""type"":[""null"",{""type"":""enum"",""name"":""Kind"",""namespace"":""org.apache.avro.test"",""symbols"":[""FOO"",""BAR"",""BAZ""],""javaAnnotation"":""org.apache.avro.TestAnnotation""}]},{""name"":""value"",""type"":[""null"",""string""]}]}"); + private System.Nullable _kind; + private string _value; + public virtual Schema Schema + { + get + { + return TestRecordWithUnion._SCHEMA; + } + } + public System.Nullable kind + { + get + { + return this._kind; + } + set + { + this._kind = value; + } + } + public string @value + { + get + { + return this._value; + } + set + { + this._value = value; + } + } + public virtual object Get(int fieldPos) + { + switch (fieldPos) + { + case 0: return this.kind; + case 1: return this.@value; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Get()"); + }; + } + public virtual void Put(int fieldPos, object fieldValue) + { + switch (fieldPos) + { + case 0: this.kind = fieldValue == null ? (System.Nullable)null : (org.apache.avro.test.Kind)fieldValue; break; + case 1: this.@value = (System.String)fieldValue; break; + default: throw new AvroRuntimeException("Bad index " + fieldPos + " in Put()"); + }; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/HttpClientServerTest.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/HttpClientServerTest.cs new file mode 100644 index 00000000000..36979006e0c --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/HttpClientServerTest.cs @@ -0,0 +1,90 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Net; + +using NUnit.Framework; +//using Microsoft.VisualStudio.TestTools.UnitTesting; + +using Avro.ipc; +using Avro.ipc.Generic; +using Avro.Generic; + +namespace Avro.Test.Ipc +{ + [TestFixture] + //[TestClass] + public class HttpClientServerTest + { + private HttpListenerServer server; + private MailResponder mailResponder; + private HttpTransceiver transceiver; + private GenericRequestor proxy; + + const string URL = @"http://localhost:18080/avro/test/ipc/mailResponder/"; + + [OneTimeSetUp] + //[TestInitialize] + public void Init() + { + mailResponder = new MailResponder(); + + server = new HttpListenerServer(new string[] { URL }, mailResponder); + server.Start(); + + HttpWebRequest requestTemplate = (HttpWebRequest)HttpWebRequest.Create(URL); + requestTemplate.Timeout = 6000; + requestTemplate.Proxy = null; + transceiver = new HttpTransceiver(requestTemplate); + proxy = new GenericRequestor(transceiver, MailResponder.Protocol); + } + + [OneTimeTearDown] + //[TestCleanup] + public void Cleanup() + { + server.Stop(); + } + + private string Send(GenericRecord message) + { + var request = new GenericRecord(MailResponder.Protocol.Messages["send"].Request); + request.Add("message", message); + + var result = (string)proxy.Request("send", request); + return result; + } + + [Test] + //[TestMethod] + public void TestRequestResponse() + { + for (int x = 0; x < 5; x++) + { + var message = SocketServerTest.CreateMessage(); + + var result = Send(message); + SocketServerTest.VerifyResponse(result); + } + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/LocalTransceiverTest.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/LocalTransceiverTest.cs new file mode 100644 index 00000000000..fc6a7fc6f22 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/LocalTransceiverTest.cs @@ -0,0 +1,72 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using Avro.Generic; +using Avro.IO; +using Avro.ipc; +using Avro.ipc.Generic; +using NUnit.Framework; + +namespace Avro.Test.Ipc +{ + [TestFixture] + public class LocalTransceiverTest + { + [TestCase] + public void TestSingleRpc() + { + Transceiver t = new LocalTransceiver(new TestResponder(protocol)); + var p = new GenericRecord(protocol.Messages["m"].Request); + p.Add("x", "hello"); + var r = new GenericRequestor(t, protocol); + + for (int x = 0; x < 5; x++) + { + object request = r.Request("m", p); + Assert.AreEqual("there", request); + } + } + + + private readonly Protocol protocol = Protocol.Parse("" + "{\"protocol\": \"Minimal\", " + + "\"messages\": { \"m\": {" + + + " \"request\": [{\"name\": \"x\", \"type\": \"string\"}], " + + " \"response\": \"string\"} } }"); + + public class TestResponder : GenericResponder + { + public TestResponder(Protocol local) + : base(local) + { + } + + public override object Respond(Message message, object request) + { + Assert.AreEqual("hello", ((GenericRecord) request)["x"]); + return "there"; + } + + public override void WriteError(Schema schema, object error, Encoder output) + { + throw new NotSupportedException(); + } + } + } +} \ No newline at end of file diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/MailResponder.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/MailResponder.cs new file mode 100644 index 00000000000..04ef0e92ba2 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/MailResponder.cs @@ -0,0 +1,102 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.IO; +using System.Reflection; +using Avro.Generic; +using Avro.IO; +using Avro.ipc; +using Avro.ipc.Generic; +using NUnit.Framework; + +namespace Avro.Test.Ipc +{ + public class MailResponder : GenericResponder + { + private static Protocol protocol; + private CountdownLatch allMessages = new CountdownLatch(5); + + public MailResponder() + : base(Protocol) + { + } + + public static Protocol Protocol + { + get + { + if (protocol == null) + { + string readAllLines; + using ( + Stream stream = + Assembly.GetExecutingAssembly().GetManifestResourceStream("Avro.Test.Ipc.mail.avpr")) + using (var reader = new StreamReader(stream)) + { + readAllLines = reader.ReadToEnd(); + } + + protocol = Protocol.Parse(readAllLines); + } + + return protocol; + } + } + + public override object Respond(Message message, object request) + { + if (message.Name == "send") + { + var genericRecord = (GenericRecord) ((GenericRecord) request)["message"]; + + return "Sent message to [" + genericRecord["to"] + + "] from [" + genericRecord["from"] + "] with body [" + + genericRecord["body"] + "]"; + } + if (message.Name == "fireandforget") + { + allMessages.Signal(); + return null; + } + + throw new NotSupportedException(); + } + + public void Reset() + { + allMessages = new CountdownLatch(5); + } + + public void AwaitMessages() + { + allMessages.Wait(2000); + } + + public void AssertAllMessagesReceived() + { + Assert.AreEqual(0, allMessages.CurrentCount); + } + + + public override void WriteError(Schema schema, object error, Encoder output) + { + Assert.Fail(error.ToString()); + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/SerializationTest.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/SerializationTest.cs new file mode 100644 index 00000000000..58198023cb6 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/SerializationTest.cs @@ -0,0 +1,153 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System.Collections.Generic; +using Avro.ipc; +using Avro.ipc.Generic; +using Avro.ipc.Specific; +using NUnit.Framework; +using org.apache.avro.test; + +namespace Avro.Test.Ipc +{ + [TestFixture] + public class SerializationTest + { + class AllImpl :All + { + public override AllTestRecord echo(AllTestRecord allTest) + { + return allTest; + } + + public override AllTestRecord echoParameters(bool booleanTest, int intTest, long longTest, float floatTest, double doubleTest, + byte[] bytesTest, string stringTest, AllEnum enumTest, FixedTest fixedTest, IList arrayTest, + IDictionary mapTest, AllTestRecord nestedTest) + { + return new AllTestRecord + { + stringTest = stringTest, + booleanTest = booleanTest, + intTest = intTest, + arrayTest = arrayTest, + bytesTest = bytesTest, + doubleTest = doubleTest, + enumTest = enumTest, + fixedTest = fixedTest, + floatTest = floatTest, + longTest = longTest, + mapTest = mapTest, + nestedTest = nestedTest + }; + } + } + private SocketServer server; + private SocketTransceiver transceiver; + private All simpleClient; + + [OneTimeSetUp] + public void Init() + { + var mailResponder = new SpecificResponder(new AllImpl()); + + server = new SocketServer("localhost", 0, mailResponder); + server.Start(); + + transceiver = new SocketTransceiver("localhost", server.Port); + + simpleClient = SpecificRequestor.CreateClient(transceiver); + } + + [OneTimeTearDown] + public void Cleanup() + { + server.Stop(); + + transceiver.Disconnect(); + } + + [Test] + public void EchoClass() + { + AllTestRecord expected = CreateExpectedTestData(); + AllTestRecord actual = simpleClient.echo(expected); + + Assert.AreEqual(expected, actual); + } + + [Test] + public void EchoParameters() + { + AllTestRecord expected = CreateExpectedTestData(); + + AllTestRecord actual = simpleClient.echoParameters( + expected.booleanTest, + expected.intTest, + expected.longTest, + expected.floatTest, + expected.doubleTest, + expected.bytesTest, + expected.stringTest, + expected.enumTest, + expected.fixedTest, + expected.arrayTest, + expected.mapTest, + expected.nestedTest); + + Assert.AreEqual(expected, actual); + } + + private static AllTestRecord CreateExpectedTestData() + { + var fixedTestData = new FixedTest(); + fixedTestData.Value[0] = 5; + + return new AllTestRecord + { + arrayTest = new List { 1, 2, 3, 4 }, + booleanTest = true, + bytesTest = new byte[] { 1, 2, 3, 4 }, + doubleTest = 5.0, + enumTest = AllEnum.BAR, + fixedTest = fixedTestData, + floatTest = 99.0f, + intTest = 3, + longTest = 4, + stringTest = "required", + mapTest = new Dictionary + { + { "foo", 1}, + { "bar", 2} + }, + nestedTest = new AllTestRecord + { + booleanTest = true, + bytesTest = new byte[] { 1 }, + stringTest = "required", + fixedTest = fixedTestData, + arrayTest = new List { 1, 2, 3, 4 }, + mapTest = new Dictionary + { + { "foo", 1}, + { "bar", 2} + }, + } + }; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerConcurrentExecutionTest.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerConcurrentExecutionTest.cs new file mode 100644 index 00000000000..b0847ca73b0 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerConcurrentExecutionTest.cs @@ -0,0 +1,146 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Threading; +using Avro.Generic; +using Avro.IO; +using Avro.ipc; +using Avro.ipc.Generic; +using NUnit.Framework; + +namespace Avro.Test.Ipc +{ + [TestFixture] + public class SocketServerConcurrentExecutionTest + { + private SocketServer server; + + private SocketTransceiver transceiver; + private GenericRequestor proxy; + + //[TearDown] + public void Cleanup() + { + try + { + if (transceiver != null) + { + transceiver.Disconnect(); + } + } + catch + { + } + + try + { + server.Stop(); + } + catch + { + } + } + + // AVRO-625 [Test] + // Currently, SocketTransceiver does not permit out-of-order requests on a stateful connection. + public void Test() + { + var waitLatch = new CountdownLatch(1); + var simpleResponder = new SimpleResponder(waitLatch); + server = new SocketServer("localhost", 0, simpleResponder); + + server.Start(); + + int port = server.Port; + + transceiver = new SocketTransceiver("localhost", port); + proxy = new GenericRequestor(transceiver, SimpleResponder.Protocol); + + // Step 1: + proxy.GetRemote(); // force handshake + + new Thread(x => + { + // Step 2a: + waitLatch.Wait(); + + var ack = new GenericRecord(SimpleResponder.Protocol.Messages["ack"].Request); + // Step 2b: + proxy.Request("ack", ack); + + }).Start(); + + + /* + * 3. Execute the Client.hello("wait") RPC, which will block until the + * Client.ack() call has completed in the background thread. + */ + + var request = new GenericRecord(SimpleResponder.Protocol.Messages["hello"].Request); + request.Add("greeting", "wait"); + + var response = (string)proxy.Request("hello", request); + + // 4. If control reaches here, both RPCs have executed concurrently + Assert.AreEqual("wait", response); + } + + private class SimpleResponder : GenericResponder + { + private readonly CountdownLatch waitLatch; + private readonly CountdownLatch ackLatch = new CountdownLatch(1); + + static readonly public Protocol Protocol = Protocol.Parse("{\"protocol\":\"Simple\",\"namespace\":\"org.apache.avro.test\",\"doc\":\"Protocol used for testing.\",\"version\":\"1.6.2\",\"javaAnnotation\":[\"javax.annotation.Generated(\\\"avro\\\")\",\"org.apache.avro.TestAnnotation\"],\"types\":[{\"type\":\"enum\",\"name\":\"Kind\",\"symbols\":[\"FOO\",\"BAR\",\"BAZ\"],\"javaAnnotation\":\"org.apache.avro.TestAnnotation\"},{\"type\":\"fixed\",\"name\":\"MD5\",\"size\":16,\"javaAnnotation\":\"org.apache.avro.TestAnnotation\"},{\"type\":\"record\",\"name\":\"TestRecord\",\"fields\":[{\"name\":\"name\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"},\"order\":\"ignore\",\"javaAnnotation\":\"org.apache.avro.TestAnnotation\"},{\"name\":\"kind\",\"type\":\"Kind\",\"order\":\"descending\"},{\"name\":\"hash\",\"type\":\"MD5\"}],\"javaAnnotation\":\"org.apache.avro.TestAnnotation\"},{\"type\":\"error\",\"name\":\"TestError\",\"fields\":[{\"name\":\"message\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}]},{\"type\":\"record\",\"name\":\"TestRecordWithUnion\",\"fields\":[{\"name\":\"kind\",\"type\":[\"null\",\"Kind\"]},{\"name\":\"value\",\"type\":[\"null\",{\"type\":\"string\",\"avro.java.string\":\"String\"}]}]}],\"messages\":{\"hello\":{\"doc\":\"Send a greeting\",\"request\":[{\"name\":\"greeting\",\"type\":{\"type\":\"string\",\"avro.java.string\":\"String\"}}],\"response\":{\"type\":\"string\",\"avro.java.string\":\"String\"}},\"echo\":{\"doc\":\"Pretend you're in a cave!\",\"request\":[{\"name\":\"record\",\"type\":\"TestRecord\"}],\"response\":\"TestRecord\"},\"add\":{\"specialProp\":\"test\",\"request\":[{\"name\":\"arg1\",\"type\":\"int\"},{\"name\":\"arg2\",\"type\":\"int\"}],\"response\":\"int\"},\"echoBytes\":{\"request\":[{\"name\":\"data\",\"type\":\"bytes\"}],\"response\":\"bytes\"},\"error\":{\"doc\":\"Always throws an error.\",\"request\":[],\"response\":\"null\",\"errors\":[\"TestError\"]},\"ack\":{\"doc\":\"Send a one way message\",\"javaAnnotation\":\"org.apache.avro.TestAnnotation\",\"request\":[],\"response\":\"null\",\"one-way\":true}}}"); + + public SimpleResponder(CountdownLatch waitLatch) + : base(Protocol) + { + this.waitLatch = waitLatch; + } + + public override object Respond(Message message, object request) + { + if (message.Name == "hello") + { + string greeting = ((GenericRecord)request)["greeting"].ToString(); + if (greeting == "wait") + { + // Step 3a: + waitLatch.Signal(); + + // Step 3b: + ackLatch.Wait(); + } + return greeting; + } + if (message.Name == "ack") + { + ackLatch.Signal(); + } + + throw new NotSupportedException(); + } + + public override void WriteError(Schema schema, object error, Encoder output) + { + throw new System.NotImplementedException(); + } + } + } +} \ No newline at end of file diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerTest.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerTest.cs new file mode 100644 index 00000000000..9d091ae3dc7 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerTest.cs @@ -0,0 +1,187 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Net.Sockets; +using Avro.Generic; +using Avro.ipc; +using Avro.ipc.Generic; +using NUnit.Framework; + +namespace Avro.Test.Ipc +{ + [TestFixture] + public class SocketServerTest + { + private SocketServer server; + private MailResponder mailResponder; + private SocketTransceiver transceiver; + private GenericRequestor proxy; + + [OneTimeSetUp] + public void Init() + { + mailResponder = new MailResponder(); + + server = new SocketServer("localhost", 0, mailResponder); + server.Start(); + + transceiver = new SocketTransceiver("localhost", server.Port); + proxy = new GenericRequestor(transceiver, MailResponder.Protocol); + } + + [OneTimeTearDown] + public void Cleanup() + { + server.Stop(); + + transceiver.Disconnect(); + } + + public void Reset() + { + Cleanup(); + Init(); + } + + private string Send(GenericRecord message) + { + var request = new GenericRecord(MailResponder.Protocol.Messages["send"].Request); + request.Add("message", message); + + var result = (string) proxy.Request("send", request); + return result; + } + + private static void FireAndForget(GenericRequestor proxy, GenericRecord genericRecord) + { + var request = new GenericRecord(MailResponder.Protocol.Messages["fireandforget"].Request); + request.Add("message", genericRecord); + + proxy.Request("fireandforget", request); + } + + private void FireAndForget(GenericRecord genericRecord) + { + FireAndForget(proxy, genericRecord); + } + + private static byte[] GetBytes(string str) + { + var bytes = new byte[str.Length*sizeof (char)]; + Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length); + return bytes; + } + + public static GenericRecord CreateMessage() + { + // The first and only type in the list is the Message type. + var recordSchema = (RecordSchema) MailResponder.Protocol.Types[0]; + var record = new GenericRecord(recordSchema); + + record.Add("to", "wife"); + record.Add("from", "husband"); + record.Add("body", "I love you!"); + + return record; + } + + public static void VerifyResponse(string result) + { + Assert.AreEqual( + "Sent message to [wife] from [husband] with body [I love you!]", + result); + } + + [Test] + public void TestBadRequest() + { + int port = server.Port; + const string msg = "GET /status HTTP/1.1\n\n"; + var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + clientSocket.Connect("localhost", port); + + clientSocket.Send(GetBytes(msg)); + var buf = new byte[2048]; + + try + { + clientSocket.Receive(buf); + } + catch (SocketException ex) + { + Assert.AreEqual(ex.ErrorCode, (int)SocketError.ConnectionReset); + } + } + + [Test] + public void TestMixtureOfRequests() + { + mailResponder.Reset(); + for (int x = 0; x < 5; x++) + { + var createMessage = CreateMessage(); + FireAndForget(createMessage); + + var result = Send(createMessage); + VerifyResponse(result); + } + mailResponder.AwaitMessages(); + mailResponder.AssertAllMessagesReceived(); + } + + [Test] + public void TestMultipleConnectionsCount() + { + Reset(); + + var transceiver2 = new SocketTransceiver("localhost", server.Port); + + var proxy2 = new GenericRequestor(transceiver2, MailResponder.Protocol); + + FireAndForget(proxy, CreateMessage()); + FireAndForget(proxy2, CreateMessage()); + transceiver2.Disconnect(); + } + + [Test] + public void TestOneway() + { + Reset(); + for (int x = 0; x < 5; x++) + { + GenericRecord genericRecord = CreateMessage(); + FireAndForget(genericRecord); + } + mailResponder.AwaitMessages(); + mailResponder.AssertAllMessagesReceived(); + } + + [Test] + public void TestRequestResponse() + { + for (int x = 0; x < 5; x++) + { + var message = CreateMessage(); + + var result = Send(message); + VerifyResponse(result); + } + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerWithCallbacksTest.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerWithCallbacksTest.cs new file mode 100644 index 00000000000..e24b255eeb8 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketServerWithCallbacksTest.cs @@ -0,0 +1,806 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Diagnostics; +using System.Net.Sockets; +using System.Threading; +using Avro.ipc; +using Avro.ipc.Specific; +using NUnit.Framework; +using org.apache.avro.test; + +namespace Avro.Test.Ipc +{ + [TestFixture] + public class SocketServerWithCallbacksTest + { + private static volatile bool ackFlag; + private static volatile CountdownLatch ackLatch = new CountdownLatch(1); + + private SocketServer server; + private SocketTransceiver transceiver; + private SimpleCallback simpleClient; + + [OneTimeSetUp] + public void Init() + { + var responder = new SpecificResponder(new SimpleImpl()); + server = new SocketServer("localhost", 0, responder); + server.Start(); + + transceiver = new SocketTransceiver("localhost", server.Port); + simpleClient = SpecificRequestor.CreateClient(transceiver); + } + + [OneTimeTearDown] + public void TearDown() + { + try + { + if (transceiver != null) + { + transceiver.Disconnect(); + } + } + catch + { + } + + try + { + server.Stop(); + } + catch + { + } + } + + + // AVRO-625 [Test] + public void CancelPendingRequestsOnTransceiverClose() + { + // Start up a second server so that closing the server doesn't + // interfere with the other unit tests: + var blockingSimpleImpl = new BlockingSimpleImpl(); + + var responder = new SpecificResponder(blockingSimpleImpl); + var server2 = new SocketServer("localhost", 0, responder); + + server2.Start(); + + try + { + int serverPort = server2.Port; + + var transceiver2 = new SocketTransceiver("localhost", serverPort); + + var addFuture = new CallFuture(); + try + { + var simpleClient2 = SpecificRequestor.CreateClient(transceiver2); + + // The first call has to block for the handshake: + Assert.AreEqual(3, simpleClient2.add(1, 2)); + + // Now acquire the semaphore so that the server will block: + blockingSimpleImpl.acquireRunPermit(); + simpleClient2.add(1, 2, addFuture); + } + finally + { + // When the transceiver is closed, the CallFuture should get + // an IOException + transceiver2.Close(); + } + bool ioeThrown = false; + try + { + addFuture.WaitForResult(2000); + } + catch (Exception) + { + } + //catch (ExecutionException e) { + // ioeThrown = e.getCause() instanceof IOException; + // Assert.assertTrue(e.getCause() instanceof IOException); + //} catch (Exception e) { + // e.printStackTrace(); + // Assert.fail("Unexpected Exception: " + e.toString()); + //} + Assert.IsTrue(ioeThrown, "Expected IOException to be thrown"); + } + finally + { + blockingSimpleImpl.releaseRunPermit(); + server2.Stop(); + } + } + + // AVRO-625 [Test] + public void CancelPendingRequestsAfterChannelCloseByServerShutdown() + { + // The purpose of this test is to verify that a client doesn't stay + // blocked when a server is unexpectedly killed (or when for some + // other reason the channel is suddenly closed) while the server + // was in the process of handling a request (thus after it received + // the request, and before it returned the response). + + // Start up a second server so that closing the server doesn't + // interfere with the other unit tests: + var blockingSimpleImpl = new BlockingSimpleImpl(); + + var responder = new SpecificResponder(blockingSimpleImpl); + var server2 = new SocketServer("localhost", 0, responder); + + server2.Start(); + SocketTransceiver transceiver2 = null; + + try + { + transceiver2 = new SocketTransceiver("localhost", server2.Port); + + var simpleClient2 = SpecificRequestor.CreateClient(transceiver2); + + // Acquire the method-enter permit, which will be released by the + // server method once we call it + blockingSimpleImpl.acquireEnterPermit(); + + // Acquire the run permit, to avoid that the server method returns immediately + blockingSimpleImpl.acquireRunPermit(); + + var t = new Thread(() => + { + try + { + simpleClient2.add(3, 4); + Assert.Fail("Expected an exception"); + } + catch (Exception) + { + // expected + } + }); + // Start client call + t.Start(); + + // Wait until method is entered on the server side + blockingSimpleImpl.acquireEnterPermit(); + + // The server side method is now blocked waiting on the run permit + // (= is busy handling the request) + + // Stop the server + server2.Stop(); + + // With the server gone, we expect the client to get some exception and exit + // Wait for client thread to exit + t.Join(10000); + + Assert.IsFalse(t.IsAlive, "Client request should not be blocked on server shutdown"); + } + finally + { + blockingSimpleImpl.releaseRunPermit(); + server2.Stop(); + if (transceiver2 != null) + transceiver2.Close(); + } + } + + + private class CallbackCallFuture : CallFuture + { + private readonly Action _handleException; + private readonly Action _handleResult; + + public CallbackCallFuture(Action handleResult = null, Action handleException = null) + { + _handleResult = handleResult; + _handleException = handleException; + } + + public override void HandleResult(T result) + { + _handleResult(result); + } + + public override void HandleException(Exception exception) + { + _handleException(exception); + } + } + + private class NestedCallFuture : CallFuture + { + private readonly CallFuture cf; + + public NestedCallFuture(CallFuture cf) + { + this.cf = cf; + } + + public override void HandleResult(T result) + { + cf.HandleResult(result); + } + + public override void HandleException(Exception exception) + { + cf.HandleException(exception); + } + } + + + private string Hello(string howAreYou) + { + var response = new CallFuture(); + + simpleClient.hello(howAreYou, response); + + return response.WaitForResult(2000); + } + + private void Hello(string howAreYou, CallFuture future1) + { + simpleClient.hello(howAreYou, future1); + } + + private class BlockingSimpleImpl : SimpleImpl + { + /** Semaphore that is released when the method is entered. */ + private readonly Semaphore enterSemaphore = new Semaphore(1, 1); + /** Semaphore that must be acquired for the method to run and exit. */ + private readonly Semaphore runSemaphore = new Semaphore(1, 1); + + + public override string hello(string greeting) + { + releaseEnterPermit(); + acquireRunPermit(); + try + { + return base.hello(greeting); + } + finally + { + releaseRunPermit(); + } + } + + public override TestRecord echo(TestRecord record) + { + releaseEnterPermit(); + acquireRunPermit(); + try + { + return base.echo(record); + } + finally + { + releaseRunPermit(); + } + } + + public override int add(int arg1, int arg2) + { + releaseEnterPermit(); + acquireRunPermit(); + try + { + return base.add(arg1, arg2); + } + finally + { + releaseRunPermit(); + } + } + + public override byte[] echoBytes(byte[] data) + { + releaseEnterPermit(); + acquireRunPermit(); + try + { + return base.echoBytes(data); + } + finally + { + releaseRunPermit(); + } + } + + public override object error() + { + releaseEnterPermit(); + acquireRunPermit(); + try + { + return base.error(); + } + finally + { + releaseRunPermit(); + } + } + + public override void ack() + { + releaseEnterPermit(); + acquireRunPermit(); + try + { + base.ack(); + } + finally + { + releaseRunPermit(); + } + } + + + /** + * Acquires a single permit from the semaphore. + */ + + public void acquireRunPermit() + { + try + { + runSemaphore.WaitOne(); + // } catch (InterruptedException e) { + // Thread.currentThread().interrupt(); + // throw new RuntimeException(e); + //} + } + finally + { + } + } + + /** + * Releases a single permit to the semaphore. + */ + + public void releaseRunPermit() + { + try + { + runSemaphore.Release(); + } + catch //(SemaphoreFullException) + { + } + } + + private void releaseEnterPermit() + { + try + { + enterSemaphore.Release(); + } + catch //(SemaphoreFullException) + { + } + } + + /** + * Acquires a single permit from the semaphore. + */ + + public void acquireEnterPermit() + { + try + { + enterSemaphore.WaitOne(); + // } catch (InterruptedException e) { + // Thread.currentThread().interrupt(); + // throw new RuntimeException(e); + //} + } + finally + { + } + } + } + + [Test] + public void Ack() + { + simpleClient.ack(); + + ackLatch.Wait(2000); + Assert.IsTrue(ackFlag, "Expected ack flag to be set"); + + ackLatch = new CountdownLatch(1); + simpleClient.ack(); + ackLatch.Wait(2000); + Assert.IsFalse(ackFlag, "Expected ack flag to be cleared"); + } + + [Test] + public void Add() + { + // Test synchronous RPC: + Assert.AreEqual(8, simpleClient.add(2, 6)); + + // Test asynchronous RPC (future): + var future1 = new CallFuture(); + simpleClient.add(8, 8, future1); + Assert.AreEqual(16, future1.WaitForResult(2000)); + Assert.IsNull(future1.Error); + + // Test asynchronous RPC (callback): + var future2 = new CallFuture(); + simpleClient.add(512, 256, new NestedCallFuture(future2)); + + Assert.AreEqual(768, future2.WaitForResult(2000)); + Assert.IsNull(future2.Error); + } + + [Test] + public void ClientReconnectAfterServerRestart() + { + // Start up a second server so that closing the server doesn't + // interfere with the other unit tests: + SimpleImpl simpleImpl = new BlockingSimpleImpl(); + + var responder = new SpecificResponder(simpleImpl); + var server2 = new SocketServer("localhost", 0, responder); + + server2.Start(); + + try + { + int serverPort = server2.Port; + + // Initialize a client, and establish a connection to the server: + Transceiver transceiver2 = new SocketTransceiver("localhost", serverPort); + + var simpleClient2 = + SpecificRequestor.CreateClient(transceiver2); + + Assert.AreEqual(3, simpleClient2.add(1, 2)); + + // Restart the server: + server2.Stop(); + try + { + simpleClient2.add(2, -1); + Assert.Fail("Client should not be able to invoke RPCs because server is no longer running"); + } + catch (Exception) + { + // Expected since server is no longer running + } + + Thread.Sleep(2000); + server2 = new SocketServer("localhost", serverPort, new SpecificResponder(new SimpleImpl())); + + server2.Start(); + + // Invoke an RPC using the same client, which should reestablish the + // connection to the server: + Assert.AreEqual(3, simpleClient2.add(1, 2)); + } + finally + { + server2.Stop(); + } + } + + [Test] + public void Echo() + { + var record = new TestRecord + { + hash = + new MD5 + { + Value = + new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 1, 2, 3, 4, 5, 6, 7, 8} + }, + kind = Kind.FOO, + name = "My Record" + }; + + // Test synchronous RPC: + TestRecord testRecord = simpleClient.echo(record); + Assert.AreEqual(record, testRecord); + + // Test asynchronous RPC (future): + var future1 = new CallFuture(); + simpleClient.echo(record, future1); + Assert.AreEqual(record, future1.WaitForResult(2000)); + Assert.IsNull(future1.Error); + + // Test asynchronous RPC (callback): + var future2 = new CallFuture(); + simpleClient.echo(record, new NestedCallFuture(future2)); + + Assert.AreEqual(record, future2.WaitForResult(2000)); + Assert.IsNull(future2.Error); + } + + [Test] + public void EchoBytes() + { + var byteBuffer = new byte[] {1, 2, 3, 4, 5, 6, 7, 8}; + + // Test synchronous RPC: + Assert.AreEqual(byteBuffer, simpleClient.echoBytes(byteBuffer)); + + // Test asynchronous RPC (future): + var future1 = new CallFuture(); + simpleClient.echoBytes(byteBuffer, future1); + Assert.AreEqual(byteBuffer, future1.WaitForResult(2000)); + Assert.IsNull(future1.Error); + + // Test asynchronous RPC (callback): + var future2 = new CallFuture(); + simpleClient.echoBytes(byteBuffer, new NestedCallFuture(future2)); + + Assert.AreEqual(byteBuffer, future2.WaitForResult(2000)); + Assert.IsNull(future2.Error); + } + + [Test, TestCase(false, TestName = "Specific error"), TestCase(true, TestName = "System error")] + public void Error(bool systemError) + { + Type expected; + + if(systemError) + { + expected = typeof(Exception); + SimpleImpl.throwSystemError = true; + } + else + { + expected = typeof(TestError); + SimpleImpl.throwSystemError = false; + } + + // Test synchronous RPC: + try + { + simpleClient.error(); + Assert.Fail("Expected " + expected.Name + " to be thrown"); + } + catch (Exception e) + { + Assert.AreEqual(expected, e.GetType()); + } + + // Test asynchronous RPC (future): + var future = new CallFuture(); + simpleClient.error(future); + try + { + future.WaitForResult(2000); + Assert.Fail("Expected " + expected.Name + " to be thrown"); + } + catch (Exception e) + { + Assert.AreEqual(expected, e.GetType()); + } + + Assert.IsNotNull(future.Error); + Assert.AreEqual(expected, future.Error.GetType()); + Assert.IsNull(future.Result); + + // Test asynchronous RPC (callback): + Exception errorRef = null; + var latch = new CountdownLatch(1); + simpleClient.error(new CallbackCallFuture( + result => Assert.Fail("Expected " + expected.Name), + exception => + { + errorRef = exception; + latch.Signal(); + })); + + Assert.IsTrue(latch.Wait(2000), "Timed out waiting for error"); + Assert.IsNotNull(errorRef); + Assert.AreEqual(expected, errorRef.GetType()); + } + + [Test] + public void Greeting() + { + // Test synchronous RPC: + string response = Hello("how are you?"); + Assert.AreEqual("Hello, how are you?", response); + + // Test asynchronous RPC (future): + var future1 = new CallFuture(); + Hello("World!", future1); + + string result = future1.WaitForResult(); + Assert.AreEqual("Hello, World!", result); + Assert.IsNull(future1.Error); + + // Test asynchronous RPC (callback): + var future2 = new CallFuture(); + + Hello("what's up?", new NestedCallFuture(future2)); + Assert.AreEqual("Hello, what's up?", future2.WaitForResult()); + Assert.IsNull(future2.Error); + } + + //[Test] + public void PerformanceTest() + { + const int threadCount = 8; + const long runTimeMillis = 10*1000L; + + + long rpcCount = 0; + int[] runFlag = {1}; + + var startLatch = new CountdownLatch(threadCount); + for (int ii = 0; ii < threadCount; ii++) + { + new Thread(() => + { + { + try + { + startLatch.Signal(); + startLatch.Wait(2000); + + while (Interlocked.Add(ref runFlag[0], 0) == 1) + { + Interlocked.Increment(ref rpcCount); + Assert.AreEqual("Hello, World!", simpleClient.hello("World!")); + } + } + catch (Exception e) + { + Console.WriteLine(e); + } + } + }).Start(); + } + + startLatch.Wait(2000); + Thread.Sleep(2000); + Interlocked.Exchange(ref runFlag[0], 1); + + string results = "Completed " + rpcCount + " RPCs in " + runTimeMillis + + "ms => " + ((rpcCount/(double) runTimeMillis)*1000) + " RPCs/sec, " + + (runTimeMillis/(double) rpcCount) + " ms/RPC."; + + Debug.WriteLine(results); + } + + [Test] + public void TestSendAfterChannelClose() + { + // Start up a second server so that closing the server doesn't + // interfere with the other unit tests: + + var responder = new SpecificResponder(new SimpleImpl()); + var server2 = new SocketServer("localhost", 0, responder); + + server2.Start(); + + try + { + var transceiver2 = new SocketTransceiver("localhost", server2.Port); + + try + { + var simpleClient2 = SpecificRequestor.CreateClient(transceiver2); + + // Verify that connection works: + Assert.AreEqual(3, simpleClient2.add(1, 2)); + + // Try again with callbacks: + var addFuture = new CallFuture(); + simpleClient2.add(1, 2, addFuture); + Assert.AreEqual(3, addFuture.WaitForResult(2000)); + + // Shut down server: + server2.Stop(); + + // Send a new RPC, and verify that it throws an Exception that + // can be detected by the client: + bool ioeCaught = false; + try + { + simpleClient2.add(1, 2); + Assert.Fail("Send after server close should have thrown Exception"); + } + catch (SocketException) + { + ioeCaught = true; + } + + Assert.IsTrue(ioeCaught, "Expected IOException"); + + // Send a new RPC with callback, and verify that the correct Exception + // is thrown: + ioeCaught = false; + try + { + addFuture = new CallFuture(); + simpleClient2.add(1, 2, addFuture); + addFuture.WaitForResult(2000); + + Assert.Fail("Send after server close should have thrown Exception"); + } + catch (SocketException) + { + ioeCaught = true; + } + + Assert.IsTrue(ioeCaught, "Expected IOException"); + } + finally + { + transceiver2.Disconnect(); + } + } + finally + { + server2.Stop(); + Thread.Sleep(1000); + } + } + + private class SimpleImpl : Simple + { + public static bool throwSystemError = false; + + public override string hello(string greeting) + { + return "Hello, " + greeting; + } + + public override TestRecord echo(TestRecord record) + { + return record; + } + + public override int add(int arg1, int arg2) + { + return arg1 + arg2; + } + + public override byte[] echoBytes(byte[] data) + { + return data; + } + + public override object error() + { + if(throwSystemError) + throw new SystemException("System error"); + else + throw new TestError { message = "Test Message" }; + } + + public override void ack() + { + ackFlag = !ackFlag; + ackLatch.Signal(); + } + } + + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketTransceiverWhenServerStopsTest.cs b/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketTransceiverWhenServerStopsTest.cs new file mode 100644 index 00000000000..ee1d1e55687 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Ipc/SocketTransceiverWhenServerStopsTest.cs @@ -0,0 +1,188 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Threading; +using Avro.ipc; +using Avro.ipc.Specific; +using NUnit.Framework; +using org.apache.avro.test; + +namespace Avro.Test.Ipc +{ + [TestFixture] + public class SocketTransceiverWhenServerStopsTest + { + private static org.apache.avro.test.Message CreateMessage() + { + var msg = new org.apache.avro.test.Message + { + to = "wife", + from = "husband", + body = "I love you!" + }; + return msg; + } + + private static readonly DateTime Jan1st1970 = new DateTime + (1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + public static long CurrentTimeMillis() + { + return (long) (DateTime.UtcNow - Jan1st1970).TotalMilliseconds; + } + + public class MailImpl : Mail + { + private CountdownLatch allMessages = new CountdownLatch(5); + + // in this simple example just return details of the message + public override String send(org.apache.avro.test.Message message) + { + return "Sent message to [" + message.to + + "] from [" + message.from + "] with body [" + + message.body + "]"; + } + + public override void fireandforget(org.apache.avro.test.Message message) + { + allMessages.Signal(); + } + + public void reset() + { + allMessages = new CountdownLatch(5); + } + } + + [Test] + public void TestSocketTransceiverWhenServerStops() + { + Responder responder = new SpecificResponder(new MailImpl()); + var server = new SocketServer("localhost", 0, responder); + + server.Start(); + + var transceiver = new SocketTransceiver("localhost", server.Port); + var mail = SpecificRequestor.CreateClient(transceiver); + + int[] successes = {0}; + int failures = 0; + int[] quitOnFailure = {0}; + var threads = new List(); + + // Start a bunch of client threads that use the transceiver to send messages + for (int i = 0; i < 100; i++) + { + var thread = new Thread( + () => + { + while (true) + { + try + { + mail.send(CreateMessage()); + Interlocked.Increment(ref successes[0]); + } + catch (Exception) + { + Interlocked.Increment(ref failures); + + if (Interlocked.Add(ref quitOnFailure[0], 0) == 1) + { + return; + } + } + } + }); + + thread.Name = "Thread" + i; + threads.Add(thread); + thread.Start(); + } + + // Be sure the threads are running: wait until we get a good deal of successes + while (Interlocked.Add(ref successes[0], 0) < 10000) + { + Thread.Sleep(50); + } + + // Now stop the server + server.Stop(); + + // Server is stopped: successes should not increase anymore: wait until we're in that situation + while (true) + { + int previousSuccesses = Interlocked.Add(ref successes[0], 0); + Thread.Sleep(500); + if (previousSuccesses == Interlocked.Add(ref successes[0], 0)) + { + break; + } + } + + server.Start(); + + long now = CurrentTimeMillis(); + + int previousSuccesses2 = successes[0]; + while (true) + { + Thread.Sleep(500); + if (successes[0] > previousSuccesses2) + { + break; + } + if (CurrentTimeMillis() - now > 5000) + { + Console.WriteLine("FYI: requests don't continue immediately..."); + break; + } + } + + // Stop our client, we would expect this to go on immediately + Console.WriteLine("Stopping transceiver"); + + Interlocked.Add(ref quitOnFailure[0], 1); + now = CurrentTimeMillis(); + transceiver.Close(); + + // Wait for all threads to quit + while (true) + { + threads.RemoveAll(x => !x.IsAlive); + + if (threads.Count > 0) + Thread.Sleep(1000); + else + break; + } + + if (CurrentTimeMillis() - now > 10000) + { + Assert.Fail("Stopping NettyTransceiver and waiting for client threads to quit took too long."); + } + else + { + Console.WriteLine("Stopping NettyTransceiver and waiting for client threads to quit took " + + (CurrentTimeMillis() - now) + " ms"); + } + } + } +} \ No newline at end of file diff --git a/lang/csharp/src/apache/codegen/Properties/AssemblyInfo.cs b/lang/csharp/src/apache/test.dotnetcore/Properties/AssemblyInfo.cs similarity index 77% rename from lang/csharp/src/apache/codegen/Properties/AssemblyInfo.cs rename to lang/csharp/src/apache/test.dotnetcore/Properties/AssemblyInfo.cs index 0eeb236618a..9d6bc9834c7 100644 --- a/lang/csharp/src/apache/codegen/Properties/AssemblyInfo.cs +++ b/lang/csharp/src/apache/test.dotnetcore/Properties/AssemblyInfo.cs @@ -1,4 +1,4 @@ -/** +/** * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information @@ -19,15 +19,9 @@ using System.Reflection; using System.Runtime.InteropServices; -[assembly: AssemblyTitle("Avro.codegen")] [assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Apache")] -[assembly: AssemblyProduct("Avro.codegen")] [assembly: AssemblyCopyright("Copyright © Apache 2013")] [assembly: AssemblyTrademark("")] [assembly: AssemblyCulture("")] [assembly: ComVisible(false)] -[assembly: Guid("3C23DD33-DD4F-42B1-B71F-8F9C86929E58")] -[assembly: AssemblyVersion("0.9.0.0")] -[assembly: AssemblyFileVersion("0.9.0.0")] \ No newline at end of file +[assembly: Guid("442785CE-3633-4A04-A103-434104F63D55")] diff --git a/lang/csharp/src/apache/test.dotnetcore/Protocol/ProtocolTest.cs b/lang/csharp/src/apache/test.dotnetcore/Protocol/ProtocolTest.cs new file mode 100644 index 00000000000..3c6c00b8935 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Protocol/ProtocolTest.cs @@ -0,0 +1,445 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.IO; +using NUnit.Framework; +using Avro; + +namespace Avro.Test +{ + [TestFixture] + public class ProtocolTest + { + [TestCase(@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + ""doc"": ""HelloWorld"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""CurseMore"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse"", ""CurseMore""] + } + } +}", true)] + [TestCase(@"{ + ""protocol"" : ""MyProtocol"", + ""namespace"" : ""com.foo"", + ""types"" : [ + { + ""type"" : ""record"", + ""name"" : ""A"", + ""fields"" : [ { ""name"" : ""f1"", ""type"" : ""long"" } ] + }, + { + ""type"" : ""enum"", + ""name"" : ""MyEnum"", + ""symbols"" : [ ""A"", ""B"", ""C"" ] + }, + { + ""type"": ""fixed"", + ""size"": 16, + ""name"": ""MyFixed"" + }, + { + ""type"" : ""record"", + ""name"" : ""Z"", + ""fields"" : + [ + { ""name"" : ""myUInt"", ""type"" : [ ""int"", ""null"" ] }, + { ""name"" : ""myULong"", ""type"" : [ ""long"", ""null"" ] }, + { ""name"" : ""myUBool"", ""type"" : [ ""boolean"", ""null"" ] }, + { ""name"" : ""myUDouble"", ""type"" : [ ""double"", ""null"" ] }, + { ""name"" : ""myUFloat"", ""type"" : [ ""float"", ""null"" ] }, + { ""name"" : ""myUBytes"", ""type"" : [ ""bytes"", ""null"" ] }, + { ""name"" : ""myUString"", ""type"" : [ ""string"", ""null"" ] }, + + { ""name"" : ""myInt"", ""type"" : ""int"" }, + { ""name"" : ""myLong"", ""type"" : ""long"" }, + { ""name"" : ""myBool"", ""type"" : ""boolean"" }, + { ""name"" : ""myDouble"", ""type"" : ""double"" }, + { ""name"" : ""myFloat"", ""type"" : ""float"" }, + { ""name"" : ""myBytes"", ""type"" : ""bytes"" }, + { ""name"" : ""myString"", ""type"" : ""string"" }, + { ""name"" : ""myNull"", ""type"" : ""null"" }, + + { ""name"" : ""myFixed"", ""type"" : ""MyFixed"" }, + { ""name"" : ""myFixed2"", ""type"" : ""MyFixed"" }, + { ""name"" : ""myA"", ""type"" : ""A"" }, + { ""name"" : ""myE"", ""type"" : ""MyEnum"" }, + { ""name"" : ""myArray"", ""type"" : { ""type"" : ""array"", ""items"" : ""bytes"" } }, + { ""name"" : ""myArray2"", ""type"" : { ""type"" : ""array"", ""items"" : { ""type"" : ""record"", ""name"" : ""newRec"", ""fields"" : [ { ""name"" : ""f1"", ""type"" : ""long""} ] } } }, + { ""name"" : ""myMap"", ""type"" : { ""type"" : ""map"", ""values"" : ""string"" } }, + { ""name"" : ""myMap2"", ""type"" : { ""type"" : ""map"", ""values"" : ""newRec"" } }, + { ""name"" : ""myObject"", ""type"" : [ ""MyEnum"", ""A"", ""null"" ] }, + { ""name"" : ""next"", ""type"" : [ ""A"", ""null"" ] } + ] + } , + { + ""type"" : ""int"" + } + ] +}", true)] + [TestCase(@"{ + ""protocol"" : ""MyProtocol"", + ""namespace"" : ""com.bar"", + ""types"" : [ + { + ""type"" : ""record"", + ""name"" : ""A"", + ""fields"" : + [ + { ""name"" : ""f1"", ""type"" : ""long"" } + ] + }, + { + ""type"" : ""enum"", + ""name"" : ""MyEnum"", + ""symbols"" : [ ""A"", ""B"", ""C"" ] + }, + { + ""type"": ""fixed"", + ""size"": 16, + ""name"": ""MyFixed"" + }, + { + ""type"" : ""record"", + ""name"" : ""Z"", + ""fields"" : + [ + { ""name"" : ""myUInt"", ""type"" : [ ""int"", ""null"" ], ""default"" : 1 }, + { ""name"" : ""myULong"", ""type"" : [ ""long"", ""null"" ], ""default"" : 2 }, + { ""name"" : ""myUBool"", ""type"" : [ ""boolean"", ""null"" ], ""default"" : true }, + { ""name"" : ""myUDouble"", ""type"" : [ ""double"", ""null"" ], ""default"" : 3 }, + { ""name"" : ""myUFloat"", ""type"" : [ ""float"", ""null"" ], ""default"" : 4.5 }, + { ""name"" : ""myUBytes"", ""type"" : [ ""bytes"", ""null"" ], ""default"" : ""\u00ff"" }, + { ""name"" : ""myUString"", ""type"" : [ ""string"", ""null"" ], ""default"" : ""foo"" }, + + { ""name"" : ""myInt"", ""type"" : ""int"", ""default"" : 10 }, + { ""name"" : ""myLong"", ""type"" : ""long"", ""default"" : 11 }, + { ""name"" : ""myBool"", ""type"" : ""boolean"", ""default"" : false }, + { ""name"" : ""myDouble"", ""type"" : ""double"", ""default"" : 12 }, + { ""name"" : ""myFloat"", ""type"" : ""float"", ""default"" : 13.14 }, + { ""name"" : ""myBytes"", ""type"" : ""bytes"", ""default"" : ""\u00ff"" }, + { ""name"" : ""myString"", ""type"" : ""string"", ""default"" : ""bar"" }, + { ""name"" : ""myNull"", ""type"" : ""null"", ""default"" : null }, + + { ""name"" : ""myFixed"", ""type"" : ""MyFixed"", ""default"" : ""\u00FFFFFFFFFFFFFFFFA"" }, + { ""name"" : ""myFixed2"", ""type"" : ""MyFixed"", ""default"" : ""\u00FFFFFFFFFFFFFFFFA"" }, + { ""name"" : ""myA"", ""type"" : ""A"", ""default"" : {""f1"":5} }, + { ""name"" : ""myE"", ""type"" : ""MyEnum"", ""default"" : ""C"" }, + { ""name"" : ""myArray"", ""type"" : { ""type"" : ""array"", ""items"" : ""bytes"" }, ""default"" : [ ""a12b"", ""cc50"" ] }, + { ""name"" : ""myArray2"", ""type"" : { ""type"" : ""array"", ""items"" : { ""type"" : ""record"", ""name"" : ""newRec"", ""fields"" : [ { ""name"" : ""f2"", ""type"" : ""long""} ], ""default"" : {""f2"":5} } }, ""default"" : [ {""f2"":6}, {""f2"":7} ] }, + { ""name"" : ""myMap"", ""type"" : { ""type"" : ""map"", ""values"" : ""string"" }, ""default"" : {""a"":""A"", ""b"":""B""} }, + { ""name"" : ""myMap2"", ""type"" : { ""type"" : ""map"", ""values"" : ""newRec"" }, ""default"" : { ""key1"":{""f2"":6}, ""key2"":{""f2"":7} } }, + { ""name"" : ""myObject"", ""type"" : [ ""MyEnum"", ""A"", ""null"" ], ""default"" : ""A"" }, + { ""name"" : ""next"", ""type"" : [ ""null"" , ""A"" ], ""default"" : null } + ] + } , + { + ""type"" : ""int"" + } + ] +}", true)] + public static void TestProtocol(string str, bool valid) + { + Protocol protocol = Protocol.Parse(str); + Assert.IsTrue(valid); + string json = protocol.ToString(); + + Protocol protocol2 = Protocol.Parse(json); + string json2 = protocol2.ToString(); + + Assert.AreEqual(json,json2); + } + + // Protocols match + [TestCase( +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", + true,true)] + // Protocols match, order of schemas in 'types' are different + [TestCase( +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", + false,true)] + // Name of protocol is different + [TestCase( +@"{ + ""protocol"": ""TestProtocol1"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", + false,false)] + // Name of a message request is different: 'hi' + [TestCase( +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hi"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", + false,false)] + // Name of a type is different : Curse1 + [TestCase( +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse1"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse1""] + } + } +}", +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hi"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", + false,false)] + // Name of a record field is different: 'mymessage' + [TestCase( +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hello"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", +@"{ + ""protocol"": ""TestProtocol"", + ""namespace"": ""com.acme"", + + ""types"": [ + {""name"": ""Greeting"", ""type"": ""record"", ""fields"": [ + {""name"": ""message"", ""type"": ""string""}]}, + {""name"": ""Curse"", ""type"": ""error"", ""fields"": [ + {""name"": ""mymessage"", ""type"": ""string""}]} + ], + + ""messages"": { + ""hi"": { + ""request"": [{""name"": ""greeting"", ""type"": ""Greeting"" }], + ""response"": ""Greeting"", + ""errors"": [""Curse""] + } + } +}", + false,false)] + public static void TestProtocolHash(string str1, string str2, bool md5_equal, bool hash_equal) + { + Protocol protocol1 = Protocol.Parse(str1); + Protocol protocol2 = Protocol.Parse(str2); + + byte[] md51 = protocol1.MD5; + byte[] md52 = protocol2.MD5; + + int hash1 = protocol1.GetHashCode(); + int hash2 = protocol2.GetHashCode(); + + Assert.AreEqual(md5_equal, md51.SequenceEqual(md52)); + Assert.AreEqual(hash_equal, hash1 == hash2); + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Schema/AliasTest.cs b/lang/csharp/src/apache/test.dotnetcore/Schema/AliasTest.cs new file mode 100644 index 00000000000..2ef954ce7e1 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Schema/AliasTest.cs @@ -0,0 +1,239 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using Avro; + +namespace Avro.Test +{ + [TestFixture] + public class AliasTest + { + [TestCase(@"{""type"":""record"",""name"":""LongList"", ""namespace"":""com"", ""aliases"":[""c"",""foo.y""], + ""fields"": + [{""name"":""f1"",""type"":""long"", ""extraprop"":""important"", ""id"":""1029"", ""aliases"":[""a"",""b"",""c""] }, + {""name"":""f2"",""type"": ""int""}]}", + true)] + [TestCase(@"{""type"":""record"",""name"":""LongList"", ""aliases"":[""Alias1""], + ""fields"":[{""name"":""f1"",""type"":""long"", ""order"":""junk"" }, + {""name"":""f2"",""type"": ""int""}]}", + false)] + [TestCase(@"{""type"":""record"",""name"":""LongList"", ""aliases"":[""Alias1""], ""customprop"":""123456"", + ""fields"":[{""name"":""f1"",""type"":""long"", ""order"":""ascending"", ""fprop"":""faaa"" }, + {""name"":""f2"",""type"": ""int""}]}", + true)] + [TestCase(@"{""type"":""record"",""name"":""LongList"", ""aliases"":[""Alias1""], + ""fields"":[{""name"":""f1"",""type"":""long""}, + {""name"":""f2"",""type"": ""int""}]}", + true)] + [TestCase(@"{""type"":""record"",""name"":""LongList"", ""aliases"":[""Alias1"",""Alias2""], + ""fields"":[{""name"":""f1"",""type"":""long""}, + {""name"":""f2"",""type"": ""int""}]}", + true)] + [TestCase(@"{""type"":""record"",""name"":""LongList"", ""aliases"":[""Alias1"",9], + ""fields"":[{""name"":""f1"",""type"":""long""}, + {""name"":""f2"",""type"": ""int""}]}", + false)] + [TestCase(@"{""type"":""record"",""name"":""LongList"", ""aliases"":[1, 2], + ""fields"":[{""name"":""f1"",""type"":""long"", ""default"": ""100""}, + {""name"":""f2"",""type"": ""int""}]}", + false)] + [TestCase(@"{""type"":""record"",""name"":""LongList"", ""aliases"": ""wrong alias format"", + ""fields"":[{""name"":""value"",""type"":""long"", ""default"": ""100""}, + {""name"":""next"",""type"":[""LongList"",""null""]}]}", + false)] + public void TestAliases(string s, bool valid) // also tests properties, default, order + { + try + { + Schema sc = Schema.Parse(s); + Assert.IsTrue(valid); + + string json = sc.ToString(); + Schema sc2 = Schema.Parse(json); + string json2 = sc2.ToString(); + + Assert.IsTrue(json == json2); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Assert.IsFalse(valid); + } + } + + // Enum + [TestCase(@"{""type"":""enum"",""name"":""Symbols"", ""symbols"" : [ ""A"", ""B"", ""C"" ] }", + @"{""type"":""enum"",""name"":""Symbols"", ""symbols"" : [ ""A"", ""B"", ""C"" ] }", + true)] + [TestCase(@"{""type"":""enum"",""name"":""Symbols"", ""symbols"" : [ ""A"", ""B"", ""C"" ] }", + @"{""type"":""enum"",""name"":""NewSymbols"", ""symbols"" : [ ""A"", ""B"", ""C"" ] }", + false)] + [TestCase(@"{""type"":""enum"",""name"":""Symbols"", ""aliases"" : [""NewSymbols""], ""symbols"" : [ ""A"", ""B"", ""C"" ] }", + @"{""type"":""enum"",""name"":""NewSymbols"", ""symbols"" : [ ""A"", ""B"", ""C"" ] }", + true)] + [TestCase(@"{""type"":""enum"",""name"":""Symbols"", ""aliases"" : [""DiffSymbols"", ""OtherSymbols""], ""symbols"" : [ ""A"", ""B"", ""C"" ] }", + @"{""type"":""enum"",""name"":""NewSymbols"", ""symbols"" : [ ""A"", ""B"", ""C"" ] }", + false)] + public void TestEnumAliasesResolution(string reader, string writer, bool canread) + { + try + { + Schema rs = Schema.Parse(reader); + Schema ws = Schema.Parse(writer); + Assert.IsTrue(rs.CanRead(ws) == canread); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Assert.IsTrue(false); + } + } + + // Fixed + [TestCase(@"{""type"": ""fixed"", ""name"": ""Fixed"", ""size"": 1}", + @"{""type"": ""fixed"", ""name"": ""Fixed"", ""size"": 1}", + true)] + [TestCase(@"{""type"": ""fixed"", ""name"": ""Fixed"", ""size"": 1}", + @"{""type"": ""fixed"", ""name"": ""NewFixed"", ""size"": 1}", + false)] + [TestCase(@"{""type"": ""fixed"", ""name"": ""Fixed"", ""aliases"" : [""NewFixed""], ""size"": 1}", + @"{""type"": ""fixed"", ""name"": ""NewFixed"", ""size"": 1}", + true)] + [TestCase(@"{""type"": ""fixed"", ""name"": ""Fixed"", ""aliases"" : [""DiffFixed"", ""OtherFixed""], ""size"": 1}", + @"{""type"": ""fixed"", ""name"": ""NewFixed"", ""size"": 1}", + false)] + public void TestFixedAliasesResolution(string reader, string writer, bool canread) + { + try + { + Schema rs = Schema.Parse(reader); + Schema ws = Schema.Parse(writer); + Assert.IsTrue(rs.CanRead(ws) == canread); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Assert.IsTrue(false); + } + } + + // Records + [TestCase(1,@"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + @"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + true)] + [TestCase(2,@"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + @"{""type"":""record"",""name"":""NewRec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + false)] + [TestCase(3,@"{""type"":""record"",""name"":""Rec"", ""aliases"":[""NewRec""], + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + @"{""type"":""record"",""name"":""NewRec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + true)] + [TestCase(4,@"{""type"":""record"",""name"":""Rec"", ""aliases"":[""OtherRec"",""DiffRec""], + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + @"{""type"":""record"",""name"":""NewRec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + false)] + [TestCase(5,@"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f3"",""type"": ""int""}]}", + @"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + false)] + [TestCase(6,@"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f3"",""type"": ""int"", ""aliases"":[""f2""]}]}", + @"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + true)] + [TestCase(7,@"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f3"",""type"": ""int"", ""aliases"":[""f4"",""f5""]}]}", + @"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"":""long"" }, + {""name"":""f2"",""type"": ""int""}]}", + false)] + [TestCase(8,@"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"": {""type"":""enum"", ""name"":""Symbol"", ""symbols"":[""A""] }}]}", + @"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"": {""type"":""enum"", ""name"":""NewSymbol"", ""symbols"":[""A""] }}]}", + false)] + [TestCase(9,@"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"": {""type"":""enum"", ""name"":""Symbol"", ""aliases"":[""NewSymbol""], ""symbols"":[""A""] }}]}", + @"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"": {""type"":""enum"", ""name"":""NewSymbol"", ""symbols"":[""A""] }}]}", + true)] + [TestCase(10,@"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"": {""type"":""enum"", ""name"":""Symbol"", ""aliases"":[""DiffSymbol""], ""symbols"":[""A""] }}]}", + @"{""type"":""record"",""name"":""Rec"", + ""fields"":[{""name"":""f1"",""type"": {""type"":""enum"", ""name"":""NewSymbol"", ""symbols"":[""A""] }}]}", + false)] + [TestCase(11,@"{""type"":""record"",""name"":""Rec"",""aliases"":[""NewRec""], + ""fields"":[{""name"":""f2"",""aliases"":[""f1""],""type"": {""type"":""enum"", ""name"":""Symbol"", ""aliases"":[""NewSymbol""], ""symbols"":[""A""] }}, + {""name"":""f3"",""aliases"":[""f4""],""type"": {""type"":""fixed"", ""name"":""Fixed"", ""aliases"":[""NewFixed""], ""size"": 1 }} + ]}", + @"{""type"":""record"",""name"":""NewRec"", + ""fields"":[{""name"":""f1"",""type"": {""type"":""enum"", ""name"":""NewSymbol"", ""symbols"":[""A""] }}, + {""name"":""f4"",""type"": {""type"":""fixed"", ""name"":""NewFixed"", ""size"": 1 }} + ]}", + true)] + [TestCase(12,@"{""type"":""record"",""name"":""Rec"",""aliases"":[""NewRec""], + ""fields"":[{""name"":""f2"",""aliases"":[""f1""],""type"": {""type"":""enum"", ""name"":""Symbol"", ""aliases"":[""NewSymbol""], ""symbols"":[""A""] }}, + {""name"":""f3"",""aliases"":[""f4""],""type"": {""type"":""fixed"", ""name"":""Fixed"", ""aliases"":[""NewFixed""], ""size"":1 }} + ]}", + @"{""type"":""record"",""name"":""NewRec"", + ""fields"":[{""name"":""f1"",""type"": {""type"":""enum"", ""name"":""NewSymbol"", ""symbols"":[""A"",""B""] }}, + {""name"":""f4"",""type"": {""type"":""fixed"", ""name"":""NewFixed"", ""size"":1 }} + ]}", + true)] + + public void TestRecordAliasesResolution(int testid, string reader, string writer, bool canread) + { + try + { + Schema rs = Schema.Parse(reader); + Schema ws = Schema.Parse(writer); + Assert.IsTrue(rs.CanRead(ws) == canread); + } + catch (Exception ex) + { + Console.WriteLine(ex.Message); + Assert.IsTrue(false); + } + } + + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Schema/SchemaNormalizationTests.cs b/lang/csharp/src/apache/test.dotnetcore/Schema/SchemaNormalizationTests.cs new file mode 100644 index 00000000000..18168384230 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Schema/SchemaNormalizationTests.cs @@ -0,0 +1,95 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using System.IO; +using Avro.Test.Utils; +using Avro; + +namespace Avro.Test +{ + [TestFixture] + public class SchemaNormalizationTests + { + private static readonly long One = -9223372036854775808; + private static readonly byte[] Postfix = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + [Test, TestCaseSource("ProvideCanonicalTestCases")] + public void CanonicalTest(string input, string expectedOutput) + { + Assert.AreEqual(expectedOutput, SchemaNormalization.ToParsingForm(Schema.Parse(input))); + } + + [Test, TestCaseSource("ProvideFingerprintTestCases")] + public void FingerprintTest(string input, string expectedOutput) + { + Schema s = Schema.Parse(input); + long carefulFP = AltFingerprint(SchemaNormalization.ToParsingForm(s)); + Assert.AreEqual(long.Parse(expectedOutput), carefulFP); + Assert.AreEqual(carefulFP, SchemaNormalization.ParsingFingerprint64(s)); + } + + private static List ProvideFingerprintTestCases() + { + using (StreamReader reader = new StreamReader("../../../../../../../../share/test/data/schema-tests.txt")) + { + return CaseFinder.Find(reader, "fingerprint", new List()); + } + } + + private static List ProvideCanonicalTestCases() + { + using (StreamReader reader = new StreamReader("../../../../../../../../share/test/data/schema-tests.txt")) + { + return CaseFinder.Find(reader, "canonical", new List()); + } + } + + private static long AltFingerprint(string s) + { + long tmp = AltExtended(SchemaNormalization.Empty64, 64, One, Encoding.UTF8.GetBytes(s)); + return AltExtended(SchemaNormalization.Empty64, 64, tmp, Postfix); + } + + private static long AltExtended(long poly, int degree, long fp, byte[] b) + { + long overflowBit = 1L << (64 - degree); + for (int i = 0; i < b.Length; i++) + { + for (int j = 1; j < 129; j = j << 1) + { + bool overflow = (0 != (fp & overflowBit)); + fp = (long) (((ulong) fp) >> 1); + if (0 != (j & b[i])) + { + fp |= One; + } + if (overflow) + { + fp ^= poly; + } + } + } + return fp; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Schema/SchemaTests.cs b/lang/csharp/src/apache/test.dotnetcore/Schema/SchemaTests.cs new file mode 100644 index 00000000000..265def28c55 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Schema/SchemaTests.cs @@ -0,0 +1,279 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections.Generic; +using System.Text; +using NUnit.Framework; +using Avro; + +namespace Avro.Test +{ + [TestFixture] + public class SchemaTests + { + // Primitive types - shorthand + [TestCase("null")] + [TestCase("boolean")] + [TestCase("int")] + [TestCase("long")] + [TestCase("float")] + [TestCase("double")] + [TestCase("bytes")] + [TestCase("string")] + + [TestCase("\"null\"")] + [TestCase("\"boolean\"")] + [TestCase("\"int\"")] + [TestCase("\"long\"")] + [TestCase("\"float\"")] + [TestCase("\"double\"")] + [TestCase("\"bytes\"")] + [TestCase("\"string\"")] + + // Primitive types - longer + [TestCase("{ \"type\": \"null\" }")] + [TestCase("{ \"type\": \"boolean\" }")] + [TestCase("{ \"type\": \"int\" }")] + [TestCase("{ \"type\": \"long\" }")] + [TestCase("{ \"type\": \"float\" }")] + [TestCase("{ \"type\": \"double\" }")] + [TestCase("{ \"type\": \"bytes\" }")] + [TestCase("{ \"type\": \"string\" }")] + // Record + [TestCase("{\"type\": \"record\",\"name\": \"Test\",\"fields\": [{\"name\": \"f\",\"type\": \"long\"}]}")] + [TestCase("{\"type\": \"record\",\"name\": \"Test\",\"fields\": " + + "[{\"name\": \"f1\",\"type\": \"long\"},{\"name\": \"f2\", \"type\": \"int\"}]}")] + [TestCase("{\"type\": \"error\",\"name\": \"Test\",\"fields\": " + + "[{\"name\": \"f1\",\"type\": \"long\"},{\"name\": \"f2\", \"type\": \"int\"}]}")] + [TestCase("{\"type\":\"record\",\"name\":\"LongList\"," + + "\"fields\":[{\"name\":\"value\",\"type\":\"long\"},{\"name\":\"next\",\"type\":[\"LongList\",\"null\"]}]}")] // Recursive. + [TestCase("{\"type\":\"record\",\"name\":\"LongList\"," + + "\"fields\":[{\"name\":\"value\",\"type\":\"long\"},{\"name\":\"next\",\"type\":[\"LongListA\",\"null\"]}]}", + typeof(SchemaParseException), Description = "Unknown name")] + [TestCase("{\"type\":\"record\",\"name\":\"LongList\"}", + typeof(SchemaParseException), Description = "No fields")] + [TestCase("{\"type\":\"record\",\"name\":\"LongList\", \"fields\": \"hi\"}", + typeof(SchemaParseException), Description = "Fields not an array")] + + // Enum + [TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"]}")] + [TestCase("{\"type\": \"enum\", \"name\": \"Status\", \"symbols\": \"Normal Caution Critical\"}", + typeof(SchemaParseException), Description = "Symbols not an array")] + [TestCase("{\"type\": \"enum\", \"name\": [ 0, 1, 1, 2, 3, 5, 8 ], \"symbols\": [\"Golden\", \"Mean\"]}", + typeof(SchemaParseException), Description = "Name not a string")] + [TestCase("{\"type\": \"enum\", \"symbols\" : [\"I\", \"will\", \"fail\", \"no\", \"name\"]}", + typeof(SchemaParseException), Description = "No name")] + [TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\" : [\"AA\", \"AA\"]}", + typeof(SchemaParseException), Description = "Duplicate symbol")] + + // Array + [TestCase("{\"type\": \"array\", \"items\": \"long\"}")] + [TestCase("{\"type\": \"array\",\"items\": {\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"]}}")] + + // Map + [TestCase("{\"type\": \"map\", \"values\": \"long\"}")] + [TestCase("{\"type\": \"map\",\"values\": {\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"]}}")] + + // Union + [TestCase("[\"string\", \"null\", \"long\"]")] + [TestCase("[\"string\", \"long\", \"long\"]", + typeof(SchemaParseException), Description = "Duplicate type")] + [TestCase("[{\"type\": \"array\", \"items\": \"long\"}, {\"type\": \"array\", \"items\": \"string\"}]", + typeof(SchemaParseException), Description = "Duplicate type")] + [TestCase("{\"type\":[\"string\", \"null\", \"long\"]}")] + + // Fixed + [TestCase("{ \"type\": \"fixed\", \"name\": \"Test\", \"size\": 1}")] + [TestCase("{\"type\": \"fixed\", \"name\": \"MyFixed\", \"namespace\": \"org.apache.hadoop.avro\", \"size\": 1}")] + [TestCase("{ \"type\": \"fixed\", \"name\": \"Test\", \"size\": 1}")] + [TestCase("{ \"type\": \"fixed\", \"name\": \"Test\", \"size\": 1}")] + [TestCase("{\"type\": \"fixed\", \"name\": \"Missing size\"}", typeof(SchemaParseException))] + [TestCase("{\"type\": \"fixed\", \"size\": 314}", typeof(SchemaParseException), + Description = "No name")] + public void TestBasic(string s, Type exceptionType=null) + { + if (exceptionType == null) + Schema.Parse(s); + else + Assert.Throws(exceptionType, () => Schema.Parse(s)); + } + + [TestCase("null", Schema.Type.Null)] + [TestCase("boolean", Schema.Type.Boolean)] + [TestCase("int", Schema.Type.Int)] + [TestCase("long", Schema.Type.Long)] + [TestCase("float", Schema.Type.Float)] + [TestCase("double", Schema.Type.Double)] + [TestCase("bytes", Schema.Type.Bytes)] + [TestCase("string", Schema.Type.String)] + + [TestCase("{ \"type\": \"null\" }", Schema.Type.Null)] + [TestCase("{ \"type\": \"boolean\" }", Schema.Type.Boolean)] + [TestCase("{ \"type\": \"int\" }", Schema.Type.Int)] + [TestCase("{ \"type\": \"long\" }", Schema.Type.Long)] + [TestCase("{ \"type\": \"float\" }", Schema.Type.Float)] + [TestCase("{ \"type\": \"double\" }", Schema.Type.Double)] + [TestCase("{ \"type\": \"bytes\" }", Schema.Type.Bytes)] + [TestCase("{ \"type\": \"string\" }", Schema.Type.String)] + public void TestPrimitive(string s, Schema.Type type) + { + Schema sc = Schema.Parse(s); + Assert.IsTrue(sc is PrimitiveSchema); + Assert.AreEqual(type, sc.Tag); + + testEquality(s, sc); + testToString(sc); + } + + private static void testEquality(string s, Schema sc) + { + Assert.IsTrue(sc.Equals(sc)); + Schema sc2 = Schema.Parse(s); + Assert.IsTrue(sc.Equals(sc2)); + Assert.AreEqual(sc.GetHashCode(), sc2.GetHashCode()); + } + + private static void testToString(Schema sc) + { + try + { + Assert.AreEqual(sc, Schema.Parse(sc.ToString())); + } + catch (Exception e) + { + throw new AvroException(e.ToString() + ": " + sc.ToString()); + } + } + + [TestCase("{\"type\":\"record\",\"name\":\"LongList\"," + + "\"fields\":[{\"name\":\"f1\",\"type\":\"long\"}," + + "{\"name\":\"f2\",\"type\": \"int\"}]}", + new string[] { "f1", "long", "100", "f2", "int", "10" })] + [TestCase("{\"type\":\"record\",\"name\":\"LongList\"," + + "\"fields\":[{\"name\":\"f1\",\"type\":\"long\", \"default\": \"100\"}," + + "{\"name\":\"f2\",\"type\": \"int\"}]}", + new string[] { "f1", "long", "100", "f2", "int", "10" })] + [TestCase("{\"type\":\"record\",\"name\":\"LongList\"," + + "\"fields\":[{\"name\":\"value\",\"type\":\"long\", \"default\": \"100\"}," + + "{\"name\":\"next\",\"type\":[\"LongList\",\"null\"]}]}", + new string[] { "value", "long", "100", "next", "union", null })] + public void TestRecord(string s, string[] kv) + { + Schema sc = Schema.Parse(s); + Assert.AreEqual(Schema.Type.Record, sc.Tag); + RecordSchema rs = sc as RecordSchema; + Assert.AreEqual(kv.Length / 3, rs.Count); + for (int i = 0; i < kv.Length; i += 3) + { + Field f = rs[kv[i]]; + Assert.AreEqual(kv[i + 1], f.Schema.Name); + /* + if (kv[i + 2] != null) + { + Assert.IsNotNull(f.DefaultValue); + Assert.AreEqual(kv[i + 2], f.DefaultValue); + } + else + { + Assert.IsNull(f.DefaultValue); + } + */ + } + testEquality(s, sc); + testToString(sc); + } + + [TestCase("{\"type\": \"enum\", \"name\": \"Test\", \"symbols\": [\"A\", \"B\"]}", + new string[] { "A", "B" })] + public void TestEnum(string s, string[] symbols) + { + Schema sc = Schema.Parse(s); + Assert.AreEqual(Schema.Type.Enumeration, sc.Tag); + EnumSchema es = sc as EnumSchema; + Assert.AreEqual(symbols.Length, es.Count); + + int i = 0; + foreach (String str in es) + { + Assert.AreEqual(symbols[i++], str); + } + + testEquality(s, sc); + testToString(sc); + } + + [TestCase("{\"type\": \"array\", \"items\": \"long\"}", "long")] + public void TestArray(string s, string item) + { + Schema sc = Schema.Parse(s); + Assert.AreEqual(Schema.Type.Array, sc.Tag); + ArraySchema ars = sc as ArraySchema; + Assert.AreEqual(item, ars.ItemSchema.Name); + + testEquality(s, sc); + testToString(sc); + } + + [TestCase("{\"type\": \"map\", \"values\": \"long\"}", "long")] + public void TestMap(string s, string value) + { + Schema sc = Schema.Parse(s); + Assert.AreEqual(Schema.Type.Map, sc.Tag); + MapSchema ms = sc as MapSchema; + Assert.AreEqual(value, ms.ValueSchema.Name); + + testEquality(s, sc); + testToString(sc); + } + + [TestCase("[\"string\", \"null\", \"long\"]", new string[] { "string", "null", "long" })] + public void TestUnion(string s, string[] types) + { + Schema sc = Schema.Parse(s); + Assert.AreEqual(Schema.Type.Union, sc.Tag); + UnionSchema us = sc as UnionSchema; + Assert.AreEqual(types.Length, us.Count); + + for (int i = 0; i < us.Count; i++) + { + Assert.AreEqual(types[i], us[i].Name); + } + testEquality(s, sc); + testToString(sc); + } + + [TestCase("{ \"type\": \"fixed\", \"name\": \"Test\", \"size\": 1}", 1)] + public void TestFixed(string s, int size) + { + Schema sc = Schema.Parse(s); + Assert.AreEqual(Schema.Type.Fixed, sc.Tag); + FixedSchema fs = sc as FixedSchema; + Assert.AreEqual(size, fs.Size); + testEquality(s, sc); + testToString(sc); + } + + [TestCase("a", "o.a.h", "o.a.h.a")] + public void TestFullname(string s1, string s2, string result) + { + var name = new SchemaName(s1, s2, null); + Assert.That(name.Fullname, Is.EqualTo(result)); + } + + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Specific/SpecificTests.cs b/lang/csharp/src/apache/test.dotnetcore/Specific/SpecificTests.cs new file mode 100644 index 00000000000..2ef0c860a8f --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Specific/SpecificTests.cs @@ -0,0 +1,378 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +using System; +using System.Collections; +using System.IO; +using System.Linq; +using NUnit.Framework; +using Avro.IO; +using System.CodeDom; +using System.CodeDom.Compiler; +using Avro.Specific; +using System.Reflection; + +namespace Avro.Test +{ + [TestFixture] + class SpecificTests + { + // The dynamically created assembly used in the test below can only be created + // once otherwise repeated tests will fail as the same type name will exist in + // multiple assemblies and so the type in the test and the type found by ObjectCreator + // will differ. This single CompilerResults only works so long as there is only one test. + // If additional tests are added then each test will need its own CompilerResults. + private static CompilerResults compres; + + [TestCase(@"{ + ""protocol"" : ""MyProtocol"", + ""namespace"" : ""com.foo"", + ""types"" : [ + { + ""type"" : ""record"", + ""name"" : ""A"", + ""fields"" : [ { ""name"" : ""f1"", ""type"" : ""long"" } ] + }, + { + ""type"" : ""enum"", + ""name"" : ""MyEnum"", + ""symbols"" : [ ""A"", ""B"", ""C"" ] + }, + { + ""type"": ""fixed"", + ""size"": 16, + ""name"": ""MyFixed"" + }, + { + ""type"" : ""record"", + ""name"" : ""Z"", + ""fields"" : + [ + { ""name"" : ""myUInt"", ""type"" : [ ""int"", ""null"" ] }, + { ""name"" : ""myULong"", ""type"" : [ ""long"", ""null"" ] }, + { ""name"" : ""myUBool"", ""type"" : [ ""boolean"", ""null"" ] }, + { ""name"" : ""myUDouble"", ""type"" : [ ""double"", ""null"" ] }, + { ""name"" : ""myUFloat"", ""type"" : [ ""float"", ""null"" ] }, + { ""name"" : ""myUBytes"", ""type"" : [ ""bytes"", ""null"" ] }, + { ""name"" : ""myUString"", ""type"" : [ ""string"", ""null"" ] }, + + { ""name"" : ""myInt"", ""type"" : ""int"" }, + { ""name"" : ""myLong"", ""type"" : ""long"" }, + { ""name"" : ""myBool"", ""type"" : ""boolean"" }, + { ""name"" : ""myDouble"", ""type"" : ""double"" }, + { ""name"" : ""myFloat"", ""type"" : ""float"" }, + { ""name"" : ""myBytes"", ""type"" : ""bytes"" }, + { ""name"" : ""myString"", ""type"" : ""string"" }, + { ""name"" : ""myNull"", ""type"" : ""null"" }, + + { ""name"" : ""myFixed"", ""type"" : ""MyFixed"" }, + { ""name"" : ""myA"", ""type"" : ""A"" }, + { ""name"" : ""myE"", ""type"" : ""MyEnum"" }, + { ""name"" : ""myArray"", ""type"" : { ""type"" : ""array"", ""items"" : ""bytes"" } }, + { ""name"" : ""myArray2"", ""type"" : { ""type"" : ""array"", ""items"" : { ""type"" : ""record"", ""name"" : ""newRec"", ""fields"" : [ { ""name"" : ""f1"", ""type"" : ""long""} ] } } }, + { ""name"" : ""myMap"", ""type"" : { ""type"" : ""map"", ""values"" : ""string"" } }, + { ""name"" : ""myMap2"", ""type"" : { ""type"" : ""map"", ""values"" : ""newRec"" } }, + { ""name"" : ""myObject"", ""type"" : [ ""MyEnum"", ""A"", ""null"" ] }, + { ""name"" : ""myArray3"", ""type"" : { ""type"" : ""array"", ""items"" : { ""type"" : ""array"", ""items"" : [ ""double"", ""string"", ""null"" ] } } } + ] + } + ] +}" +, new object[] {3, // index of the schema to serialize + "com.foo.Z", // name of the schema to serialize +@"Console.WriteLine(""Constructing com.foo.Z..."");", // Empty Constructor. +@" + Console.WriteLine(""Populating com.foo.Z...""); + string bytes = ""bytes sample text""; + System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding(); + + myUInt=1; + myULong=2; + myUBool=true; + myUDouble=(double)3; + myUFloat=(float)4.5; + myUBytes = encoding.GetBytes(bytes); + myUString=""Hello""; + + myInt=1; + myLong=2; + myBool=true; + myDouble=(double)3; + myFloat=(float)4.5; + myBytes=encoding.GetBytes(bytes); + myString=""Hello""; + myNull=null; + + string fixedstr = ""My fixed record0""; + myFixed=new MyFixed(); myFixed.Value = encoding.GetBytes(fixedstr); + myA=new A(); myA.f1 = 10; + myE=com.foo.MyEnum.C; + + myArray=new List(); + myArray.Add(encoding.GetBytes(""a"")); + + myArray2 = new List(); + com.foo.newRec rec = new com.foo.newRec(); + rec.f1 = 50; + myArray2.Add(rec); + + myMap = new Dictionary(); + myMap.Add(""key"", ""value""); + myMap2 = new Dictionary(); + com.foo.newRec newrec = new com.foo.newRec(); + newrec.f1 = 1200; + myMap2.Add(""A"", newrec); + myObject = myA; + + IList o1 = new List(); + + o1.Add((double)1123123121); + o1.Add((double)2); + o1.Add(null); + o1.Add(""fred""); + + IList o2 = new List(); + + o2.Add((double)1); + o2.Add((double)32531); + o2.Add((double)4); + o2.Add((double)555); + o2.Add((double)0); + + myArray3 = new List>(); + myArray3.Add(o1); + myArray3.Add(o2); + +"} +)] + public void TestSpecific(string str, object[] result) + { + if(compres == null) + { + Protocol protocol = Protocol.Parse(str); + var codegen = new CodeGen(); + codegen.AddProtocol(protocol); + var compileUnit = codegen.GenerateCode(); + + // add a constructor to the main class using the passed assignment statements + CodeTypeDeclaration ctd = compileUnit.Namespaces[0].Types[(int)result[0]]; + CodeConstructor constructor = new CodeConstructor(); + constructor.Attributes = MemberAttributes.Public; + CodeSnippetExpression snippet = new CodeSnippetExpression((string)result[2]); + constructor.Statements.Add(snippet); + ctd.Members.Add(constructor); + + // add a function to the main class to populate the data + // This has been moved from constructor, as it was causing some tests to pass that shouldn't when referencing a blank object on READ. + + CodeMemberMethod method = new CodeMemberMethod(); + method.Attributes = MemberAttributes.Public; + method.Name = "Populate"; + CodeSnippetExpression snippet2 = new CodeSnippetExpression((string)result[3]); + method.Statements.Add(snippet2); + ctd.Members.Add(method); + + + + // compile + var comparam = new CompilerParameters(new string[] { "mscorlib.dll" }); + comparam.ReferencedAssemblies.Add("System.dll"); + comparam.ReferencedAssemblies.Add("Avro.dll"); + comparam.GenerateInMemory = true; + var ccp = new Microsoft.CSharp.CSharpCodeProvider(); + var units = new CodeCompileUnit[] { compileUnit }; + compres = ccp.CompileAssemblyFromDom(comparam, units); + Assert.IsNotNull(compres); + if (compres.Errors.Count > 0) + { + for (int i = 0; i < compres.Errors.Count; i++) + Console.WriteLine(compres.Errors[i]); + } + Assert.IsTrue(compres.Errors.Count == 0); + } + + // create record + ISpecificRecord rec = compres.CompiledAssembly.CreateInstance((string)result[1]) as ISpecificRecord; + + // Call populate to put some data in it. + Type recType = rec.GetType(); ; + MethodInfo methodInfo = recType.GetMethod("Populate"); + methodInfo.Invoke(rec, null); + + var x1 = compres.CompiledAssembly.FullName; + + Assert.IsFalse(rec == null); + + // serialize + var stream = serialize(rec.Schema, rec); + + // deserialize + var rec2 = deserialize(stream, rec.Schema, rec.Schema); + Assert.IsFalse(rec2 == null); + AssertSpecificRecordEqual(rec, rec2); + } + + [TestCase] + public void TestEnumResolution() + { + Schema writerSchema = Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," + + "\"fields\":[{\"name\":\"enumType\",\"type\": { \"type\": \"enum\", \"name\": \"EnumType\", \"symbols\": [\"FIRST\", \"SECOND\"]} }]}"); + + var testRecord = new EnumRecord(); + + Schema readerSchema = testRecord.Schema; + testRecord.enumType = EnumType.SECOND; + + // serialize + var stream = serialize(writerSchema, testRecord); + + // deserialize + var rec2 = deserialize(stream, writerSchema, readerSchema); + Assert.AreEqual( EnumType.SECOND, rec2.enumType ); + } + + private static S deserialize(Stream ms, Schema ws, Schema rs) where S : class, ISpecificRecord + { + long initialPos = ms.Position; + var r = new SpecificReader(ws, rs); + Decoder d = new BinaryDecoder(ms); + S output = r.Read(null, d); + Assert.AreEqual(ms.Length, ms.Position); // Ensure we have read everything. + checkAlternateDeserializers(output, ms, initialPos, ws, rs); + return output; + } + + private static void checkAlternateDeserializers(S expected, Stream input, long startPos, Schema ws, Schema rs) where S : class, ISpecificRecord + { + input.Position = startPos; + var reader = new SpecificDatumReader(ws, rs); + Decoder d = new BinaryDecoder(input); + S output = reader.Read(null, d); + Assert.AreEqual(input.Length, input.Position); // Ensure we have read everything. + AssertSpecificRecordEqual(expected, output); + } + + private static Stream serialize(Schema ws, T actual) + { + var ms = new MemoryStream(); + Encoder e = new BinaryEncoder(ms); + var w = new SpecificWriter(ws); + w.Write(actual, e); + ms.Flush(); + ms.Position = 0; + checkAlternateSerializers(ms.ToArray(), actual, ws); + return ms; + } + + private static void checkAlternateSerializers(byte[] expected, T value, Schema ws) + { + var ms = new MemoryStream(); + var writer = new SpecificDatumWriter(ws); + var e = new BinaryEncoder(ms); + writer.Write(value, e); + var output = ms.ToArray(); + + Assert.AreEqual(expected.Length, output.Length); + Assert.True(expected.SequenceEqual(output)); + } + + private static void AssertSpecificRecordEqual(ISpecificRecord rec1, ISpecificRecord rec2) + { + var recordSchema = (RecordSchema) rec1.Schema; + for (int i = 0; i < recordSchema.Count; i++) + { + var rec1Val = rec1.Get(i); + var rec2Val = rec2.Get(i); + if (rec1Val is ISpecificRecord) + { + AssertSpecificRecordEqual((ISpecificRecord)rec1Val, (ISpecificRecord)rec2Val); + } + else if (rec1Val is IList) + { + var rec1List = (IList) rec1Val; + if( rec1List.Count > 0 && rec1List[0] is ISpecificRecord) + { + var rec2List = (IList) rec2Val; + Assert.AreEqual(rec1List.Count, rec2List.Count); + for (int j = 0; j < rec1List.Count; j++) + { + AssertSpecificRecordEqual((ISpecificRecord)rec1List[j], (ISpecificRecord)rec2List[j]); + } + } + else + { + Assert.AreEqual(rec1Val, rec2Val); + } + } + else if (rec1Val is IDictionary) + { + var rec1Dict = (IDictionary) rec1Val; + var rec2Dict = (IDictionary) rec2Val; + Assert.AreEqual(rec2Dict.Count, rec2Dict.Count); + foreach (var key in rec1Dict.Keys) + { + var val1 = rec1Dict[key]; + var val2 = rec2Dict[key]; + if (val1 is ISpecificRecord) + { + AssertSpecificRecordEqual((ISpecificRecord)val1, (ISpecificRecord)val2); + } + else + { + Assert.AreEqual(val1, val2); + } + } + } + else + { + Assert.AreEqual(rec1Val, rec2Val); + } + } + } + } + + enum EnumType + { + THIRD, + FIRST, + SECOND + } + + class EnumRecord : ISpecificRecord + { + public EnumType enumType { get; set; } + public Schema Schema + { + get + { + return Schema.Parse("{\"type\":\"record\",\"name\":\"EnumRecord\",\"namespace\":\"Avro.Test\"," + + "\"fields\":[{\"name\":\"enumType\",\"type\": { \"type\": \"enum\", \"name\":" + + " \"EnumType\", \"symbols\": [\"THIRD\", \"FIRST\", \"SECOND\"]} }]}"); + } + } + + public object Get(int fieldPos) + { + return enumType; + } + + public void Put(int fieldPos, object fieldValue) + { + enumType = (EnumType)fieldValue; + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Utils/CaseFinder.cs b/lang/csharp/src/apache/test.dotnetcore/Utils/CaseFinder.cs new file mode 100644 index 00000000000..ed0d7cfaca6 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Utils/CaseFinder.cs @@ -0,0 +1,134 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Text.RegularExpressions; + +namespace Avro.Test.Utils +{ + public class CaseFinder + { + private static string labelRegex = "[a-zA-Z][_a-zA-Z0-9]*"; + private static string newCaseName = "INPUT"; + private static string newCaseMarker = "<<" + newCaseName; + private static string startLinePattern = "^<<("+labelRegex+")(.*)$"; + + /// + /// Scan test-case file streamReader looking for test subcases + /// marked with label. Any such cases are appended + /// (in order) to the "cases" parameter. + /// + /// + /// + /// + /// + public static List Find(StreamReader streamReader, string label, List cases) + { + if (!Regex.IsMatch(label, "^" + labelRegex + "$")) + { + throw new ArgumentException("Bad case subcase label: " + label); + } + + string subcaseMarker = "<<" + label; + + var line = streamReader.ReadLine(); + while (true) + { + while (line != null && !line.StartsWith(newCaseMarker)) + { + line = streamReader.ReadLine(); + } + if (line == null) + { + break; + } + string input = ProcessHereDoc(streamReader, line); + + if (label == newCaseName) + { + cases.Add(new object[] { input, null }); + line = streamReader.ReadLine(); + continue; + } + + do + { + line = streamReader.ReadLine(); + } while (line != null && (!line.StartsWith(newCaseMarker) && !line.StartsWith(subcaseMarker))); + + if (line == null || line.StartsWith(newCaseMarker)) + { + continue; + } + + string expectedOutput = ProcessHereDoc(streamReader, line); + cases.Add(new object[] { input, expectedOutput }); + } + return cases; + } + + private static string ProcessHereDoc(StreamReader streamReader, string docStart) + { + var match = Regex.Match(docStart, startLinePattern); + if (!match.Success) + { + throw new ArgumentException(string.Format("Wasn't given the start of a heredoc (\"{0}\")", docStart)); + } + + string docName = match.Groups[1].Value; + + // Determine if this is a single-line heredoc, and process if it is + string singleLineText = match.Groups[2].Value; + if (singleLineText.Length != 0) + { + if (!singleLineText.StartsWith(" ")) + { + throw new IOException(string.Format("Single-line heredoc missing initial space (\"{0}\")", docStart)); + } + return singleLineText.Substring(1); + } + + // Process multi-line heredocs + var sb = new StringBuilder(); + string line = streamReader.ReadLine(); + string prevLine = string.Empty; + bool firstTime = true; + while (line != null && line != docName) + { + if (!firstTime) + { + sb.Append(prevLine).Append("\n"); + } + else + { + firstTime = false; + } + prevLine = line; + line = streamReader.ReadLine(); + } + if (line == null) + { + throw new IOException(string.Format("Here document ({0}) terminated by end-of-file.", docName)); + } + return sb.Append(prevLine).ToString(); + } + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/Utils/CaseFinderTests.cs b/lang/csharp/src/apache/test.dotnetcore/Utils/CaseFinderTests.cs new file mode 100644 index 00000000000..7ec52e21f61 --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/Utils/CaseFinderTests.cs @@ -0,0 +1,165 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +using System; +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using NUnit.Framework; +using System.IO; + +namespace Avro.Test.Utils +{ + [TestFixture] + public class CaseFinderTests + { + [Test] + public void TestBadDocLabel1() + { + List result = new List(); + Assert.Throws( + () => CaseFinder.Find(Mk("< result = new List(); + Assert.Throws( + () => CaseFinder.Find(Mk("< result = new List(); + Assert.Throws( + () => CaseFinder.Find(Mk("< result = new List(); + Assert.Throws( + () => CaseFinder.Find(Mk("< expectedOutput) + { + List result = new List(); + CaseFinder.Find(Mk(input), label, result); + Assert.True(Eq(result, expectedOutput), Pr(result)); + } + + class OutputTestCases : IEnumerable + { + public IEnumerator GetEnumerator() + { + yield return new object[] { "", "foo", new List { } }; + yield return new object[] { "< { new object[] { "a", "b" } } }; + yield return new object[] { "< { new object[] { "a", "b" } } }; + yield return new object[] { "< { new object[] { "a", "b" } } }; + yield return new object[] { "< { new object[] { "a", "b" } } }; + yield return new object[] { "// This is a test\n< { new object[] { "a", "b" } } }; + yield return new object[] { "< { new object[] { "a", "b" } } }; + yield return new object[] { "< { new object[] { "a", "b" } } }; + yield return new object[] { "< { new object[] { "a", "b\n" } } }; + yield return new object[] { "< { new object[] { "a", "\n b \n" } } }; + yield return new object[] { "< { new object[] { "a", "b" }, new object[] { "c", "d" } } }; + yield return new object[] { "< { new object[] { "a", "b" }, new object[] { "c", "d" } } }; + yield return new object[] { "< { new object[] { "a", "z" } } }; + yield return new object[] { "< { new object[] { "a", null }, new object[] { "c", null }, new object[] { "e", null } } }; + } + } + + private StreamReader Mk(string s) + { + byte[] byteArray = Encoding.ASCII.GetBytes(s); + MemoryStream stream = new MemoryStream(byteArray); + return new StreamReader(stream); + } + + private string Pr(List t) + { + StringBuilder sb = new StringBuilder(); + sb.Append("{ "); + bool firstTime = true; + foreach (var obj in t) + { + if (!firstTime) + { + sb.Append(", "); + } + else + { + firstTime = false; + } + sb.Append("{ \"").Append(obj[0]).Append("\", \"").Append(obj[1]).Append("\" }"); + } + sb.Append("}"); + return sb.ToString(); + } + + private bool Eq(List l1, List l2) + { + if (l1 == null || l2 == null) + { + return l1 == l2; + } + if (l1.Count != l2.Count) + { + return false; + } + for (int i = 0; i < l1.Count; i++) + { + if (!ArraysEqual(l1[i], l2[i])) + { + return false; + } + } + return true; + } + + static bool ArraysEqual(T[] a1, T[] a2) + { + if (ReferenceEquals(a1, a2)) + return true; + + if (a1 == null || a2 == null) + return false; + + if (a1.Length != a2.Length) + return false; + + EqualityComparer comparer = EqualityComparer.Default; + for (int i = 0; i < a1.Length; i++) + { + if (!comparer.Equals(a1[i], a2[i])) return false; + } + return true; + } + + } +} diff --git a/lang/csharp/src/apache/test.dotnetcore/packages.config b/lang/csharp/src/apache/test.dotnetcore/packages.config new file mode 100644 index 00000000000..c7775902d8a --- /dev/null +++ b/lang/csharp/src/apache/test.dotnetcore/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/lang/csharp/src/apache/test/Avro.test.csproj b/lang/csharp/src/apache/test/Avro.test.csproj index 841f4f2df0b..a1df5ceba80 100644 --- a/lang/csharp/src/apache/test/Avro.test.csproj +++ b/lang/csharp/src/apache/test/Avro.test.csproj @@ -1,168 +1,100 @@ - - - - - Debug - AnyCPU - 8.0.30703 - 2.0 - {911D56AB-587B-4E5F-B5EA-D47D8A46F1FA} - Library - Properties - Avro.test - Avro.test - v3.5 - 512 - - - 3.5 - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - - true - full - false - ..\..\..\build\test\Debug\ - DEBUG;TRACE - prompt - 4 - Off - - - none - true - ..\..\..\build\test\Release\ - - - prompt - 4 - Off - - - - False - ..\..\..\..\..\lang\csharp\lib\main\Castle.Core.dll - - - False - ..\..\..\lib\test\nunit.framework.dll - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {3b05043a-dc6c-49b6-85bf-9ab055d0b414} - Avro.ipc - - - {A0A5CA3C-F58C-4D07-98B0-2C7B62AB20F0} - Avro.main - - - - - False - Microsoft .NET Framework 4 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - False - Windows Installer 3.1 - true - - - - - Ipc\mail.avpr - - - - - + + + + + + Debug + AnyCPU + 8.0.30703 + 2.0 + {6C461AC0-8C0F-4538-9256-454F752DD821} + Library + Avro.Test + Avro.Test + v4.6.1 + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + + + true + bin\Release + prompt + 4 + + + + + ..\..\..\packages\Microsoft.CodeCoverage.1.0.3\lib\netstandard1.0\Microsoft.VisualStudio.CodeCoverage.Shim.dll + + + ..\..\..\packages\NUnit.3.9.0\lib\net45\nunit.framework.dll + False + + + + + + Ipc\mail.avpr + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lang/csharp/src/apache/test/packages.config b/lang/csharp/src/apache/test/packages.config new file mode 100644 index 00000000000..c7775902d8a --- /dev/null +++ b/lang/csharp/src/apache/test/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file