From af7be8603af631b6c0ff51518a53df42f11d4048 Mon Sep 17 00:00:00 2001 From: Boshi Lian Date: Sun, 1 Nov 2020 12:30:51 -0800 Subject: [PATCH] E2E test with minikube on gh action (#513) * add minikube as e2e test server * fix format * update env * force no skip * fix then * finish skip test * add skip blocker * fix path * output skipped case * enable test env var * final merge * add missing file --- .../workflows/{dotnet.yaml => buildtest.yaml} | 27 ++++++++- Directory.Build.targets | 2 +- kubernetes-client.sln | 34 ++++++++++- tests/E2E.Tests/E2E.Tests.csproj | 29 ++++++++++ tests/E2E.Tests/MinikubeFactAttribute.cs | 12 ++++ tests/E2E.Tests/MnikubeTests.cs | 57 +++++++++++++++++++ tests/SkipTestLogger/SkipTestLogger.cs | 48 ++++++++++++++++ tests/SkipTestLogger/SkipTestLogger.csproj | 11 ++++ 8 files changed, 216 insertions(+), 4 deletions(-) rename .github/workflows/{dotnet.yaml => buildtest.yaml} (63%) create mode 100644 tests/E2E.Tests/E2E.Tests.csproj create mode 100644 tests/E2E.Tests/MinikubeFactAttribute.cs create mode 100644 tests/E2E.Tests/MnikubeTests.cs create mode 100644 tests/SkipTestLogger/SkipTestLogger.cs create mode 100644 tests/SkipTestLogger/SkipTestLogger.csproj diff --git a/.github/workflows/dotnet.yaml b/.github/workflows/buildtest.yaml similarity index 63% rename from .github/workflows/dotnet.yaml rename to .github/workflows/buildtest.yaml index 03804af..b4a9e23 100644 --- a/.github/workflows/dotnet.yaml +++ b/.github/workflows/buildtest.yaml @@ -1,4 +1,4 @@ -name: .NET Core +name: Build and Test jobs: build: @@ -34,6 +34,31 @@ jobs: # path: tests/KubernetesClient.Tests/coverage.netcoreapp2.1.cobertura.xml # repo_token: ${{ secrets.GITHUB_TOKEN }} # minimum_coverage: 0 + e2e: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + with: + fetch-depth: 0 + - name: Setup dotnet SDK 2.1 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '2.1.x' + - name: Setup dotnet SDK 3.1 + uses: actions/setup-dotnet@v1 + with: + dotnet-version: '3.1.x' + - name: Minikube + run: minikube start + - name: Test + run: | + true > skip.log + env K8S_E2E_MINIKUBE=1 dotnet test tests/E2E.Tests --logger "SkipTestLogger;file=$PWD/skip.log" + if [ -s skip.log ]; then + cat skip.log + echo "CASES MUST NOT BE SKIPPED" + exit 1 + fi on: pull_request: diff --git a/Directory.Build.targets b/Directory.Build.targets index b9fbd94..249ac4c 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -4,7 +4,7 @@ All - + All diff --git a/kubernetes-client.sln b/kubernetes-client.sln index 6f1c34a..b087b68 100644 --- a/kubernetes-client.sln +++ b/kubernetes-client.sln @@ -33,9 +33,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "KubernetesWatchGenerator", EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "patch", "examples\patch\patch.csproj", "{04DE2C84-117D-4E21-8B45-B7AE627697BD}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "httpClientFactory", "examples\httpClientFactory\httpClientFactory.csproj", "{A07314A0-02E8-4F36-B233-726D59D28F08}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "httpClientFactory", "examples\httpClientFactory\httpClientFactory.csproj", "{A07314A0-02E8-4F36-B233-726D59D28F08}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "metrics", "examples\metrics\metrics.csproj", "{B9647AD4-F6B0-406F-8B79-6781E31600EC}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "metrics", "examples\metrics\metrics.csproj", "{B9647AD4-F6B0-406F-8B79-6781E31600EC}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "E2E.Tests", "tests\E2E.Tests\E2E.Tests.csproj", "{5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SkipTestLogger", "tests\SkipTestLogger\SkipTestLogger.csproj", "{4D2AE427-F856-49E5-B61D-EA6B17D89051}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -203,6 +207,30 @@ Global {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|x64.Build.0 = Release|Any CPU {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|x86.ActiveCfg = Release|Any CPU {B9647AD4-F6B0-406F-8B79-6781E31600EC}.Release|x86.Build.0 = Release|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|Any CPU.Build.0 = Debug|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|x64.ActiveCfg = Debug|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|x64.Build.0 = Debug|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|x86.ActiveCfg = Debug|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Debug|x86.Build.0 = Debug|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|Any CPU.ActiveCfg = Release|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|Any CPU.Build.0 = Release|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|x64.ActiveCfg = Release|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|x64.Build.0 = Release|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|x86.ActiveCfg = Release|Any CPU + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2}.Release|x86.Build.0 = Release|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|Any CPU.Build.0 = Debug|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|x64.ActiveCfg = Debug|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|x64.Build.0 = Debug|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|x86.ActiveCfg = Debug|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Debug|x86.Build.0 = Debug|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|Any CPU.ActiveCfg = Release|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|Any CPU.Build.0 = Release|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|x64.ActiveCfg = Release|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|x64.Build.0 = Release|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|x86.ActiveCfg = Release|Any CPU + {4D2AE427-F856-49E5-B61D-EA6B17D89051}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -221,6 +249,8 @@ Global {04DE2C84-117D-4E21-8B45-B7AE627697BD} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40} {A07314A0-02E8-4F36-B233-726D59D28F08} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40} {B9647AD4-F6B0-406F-8B79-6781E31600EC} = {B70AFB57-57C9-46DC-84BE-11B7DDD34B40} + {5056C4A2-5E12-4C16-8DA7-8835DA58BFF2} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509} + {4D2AE427-F856-49E5-B61D-EA6B17D89051} = {8AF4A5C2-F0CE-47D5-A4C5-FE4AB83CA509} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {049A763A-C891-4E8D-80CF-89DD3E22ADC7} diff --git a/tests/E2E.Tests/E2E.Tests.csproj b/tests/E2E.Tests/E2E.Tests.csproj new file mode 100644 index 0000000..76f3d18 --- /dev/null +++ b/tests/E2E.Tests/E2E.Tests.csproj @@ -0,0 +1,29 @@ + + + false + true + ..\..\src\KubernetesClient\kubernetes-client.snk + k8s.E2E + netcoreapp3.1 + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + diff --git a/tests/E2E.Tests/MinikubeFactAttribute.cs b/tests/E2E.Tests/MinikubeFactAttribute.cs new file mode 100644 index 0000000..4b7ed3a --- /dev/null +++ b/tests/E2E.Tests/MinikubeFactAttribute.cs @@ -0,0 +1,12 @@ +using System; +using Xunit; + +namespace k8s.E2E +{ + public sealed class MinikubeFactAttribute : FactAttribute + { + private static readonly bool HasEnv = !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("K8S_E2E_MINIKUBE")); + + public override string Skip => !HasEnv ? "K8S_E2_MINIKUBE not set" : null; + } +} diff --git a/tests/E2E.Tests/MnikubeTests.cs b/tests/E2E.Tests/MnikubeTests.cs new file mode 100644 index 0000000..9ea4ccd --- /dev/null +++ b/tests/E2E.Tests/MnikubeTests.cs @@ -0,0 +1,57 @@ +using System; +using System.Linq; +using k8s.Models; +using Microsoft.Rest; +using Xunit; + +namespace k8s.E2E +{ + public class MnikubeTests + { + [MinikubeFact] + public void SimpleTest() + { + var namespaceParameter = "default"; + var podName = "k8s-e2e-pod"; + + var client = CreateClient(); + + void Cleanup() + { + var pods = client.ListNamespacedPod(namespaceParameter); + if (pods.Items.Any(p => p.Metadata.Name == podName)) + { + client.DeleteNamespacedPod(podName, namespaceParameter); + } + } + + try + { + Cleanup(); + + client.CreateNamespacedPod( + new V1Pod() + { + Metadata = new V1ObjectMeta { Name = podName, }, + Spec = new V1PodSpec + { + Containers = new[] { new V1Container() { Name = "k8s-e2e", Image = "nginx", }, }, + }, + }, + namespaceParameter); + + var pods = client.ListNamespacedPod(namespaceParameter); + Assert.Contains(pods.Items, p => p.Metadata.Name == podName); + } + finally + { + Cleanup(); + } + } + + private static IKubernetes CreateClient() + { + return new Kubernetes(KubernetesClientConfiguration.BuildDefaultConfig()); + } + } +} diff --git a/tests/SkipTestLogger/SkipTestLogger.cs b/tests/SkipTestLogger/SkipTestLogger.cs new file mode 100644 index 0000000..a1bcafb --- /dev/null +++ b/tests/SkipTestLogger/SkipTestLogger.cs @@ -0,0 +1,48 @@ +using System; +using System.Collections.Generic; +using System.IO; +using Microsoft.VisualStudio.TestPlatform.ObjectModel; +using Microsoft.VisualStudio.TestPlatform.ObjectModel.Client; + +namespace k8s.E2E +{ + // This TestLogger is to log test cases skipped by accident + // when E2E test runs in github action + + [FriendlyName("SkipTestLogger")] + [ExtensionUri("logger://Microsoft/TestPlatform/SkipTestLogger/v1")] + public class SkipTestLogger : ITestLoggerWithParameters + { + public void Initialize(TestLoggerEvents events, Dictionary parameters) + { + if (parameters.TryGetValue("file", out var file)) + { + InnerInitialize(events, file); + } + else + { + throw new ArgumentNullException("file", "log file path must be set"); + } + } + + private static void InnerInitialize(TestLoggerEvents events, string file) + { + Console.WriteLine($"using {file} for skipped test case log"); + events.TestResult += (sender, args) => + { + using (var w = File.AppendText(file)) + { + if (args.Result.Outcome == TestOutcome.Skipped) + { + w.WriteLine(args.Result.DisplayName); + } + } + }; + } + + public void Initialize(TestLoggerEvents events, string testRunDirectory) + { + InnerInitialize(events, Path.Combine(testRunDirectory, "skip.log")); + } + } +} diff --git a/tests/SkipTestLogger/SkipTestLogger.csproj b/tests/SkipTestLogger/SkipTestLogger.csproj new file mode 100644 index 0000000..0375cb5 --- /dev/null +++ b/tests/SkipTestLogger/SkipTestLogger.csproj @@ -0,0 +1,11 @@ + + + + netstandard2.0 + + + + + + +