Skip to content

Commit e3754ae

Browse files
authored
Setting Up Project Structure (#1)
* Starter code for the .NET SDK * Added documentation * Added newlines at eof * Responding to code review comments * Added logging; More documentation and cleanup * Removed AppOptionsInternal
1 parent 7319830 commit e3754ae

File tree

11 files changed

+753
-1
lines changed

11 files changed

+753
-1
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
bin/
2+
obj/
3+
.vscode/
4+
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.0</TargetFramework>
5+
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Google.Apis.Auth" Version="1.34.0" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.0" />
12+
<PackageReference Include="xunit" Version="2.3.1" />
13+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
14+
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<ProjectReference Include="..\FirebaseAdmin\FirebaseAdmin.csproj" />
19+
</ItemGroup>
20+
<ItemGroup>
21+
<None Update=".\resources\*">
22+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
23+
</None>
24+
</ItemGroup>
25+
26+
</Project>
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netcoreapp2.0</TargetFramework>
5+
6+
<IsPackable>false</IsPackable>
7+
</PropertyGroup>
8+
9+
<ItemGroup>
10+
<PackageReference Include="Google.Apis.Auth" Version="1.34.0" />
11+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.6.0" />
12+
<PackageReference Include="xunit" Version="2.3.1" />
13+
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
14+
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.1" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<ProjectReference Include="..\FirebaseAdmin\FirebaseAdmin.csproj" />
19+
</ItemGroup>
20+
<ItemGroup>
21+
<None Update=".\resources\*">
22+
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
23+
</None>
24+
</ItemGroup>
25+
26+
</Project>
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
// Copyright 2018, Google Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
using System.Threading.Tasks;
17+
using Xunit;
18+
using FirebaseAdmin;
19+
using Google.Apis.Auth.OAuth2;
20+
21+
namespace FirebaseAdmin.Tests
22+
{
23+
public class FirebaseAppTest: IDisposable
24+
{
25+
[Fact]
26+
public void GetNonExistingDefaultInstance()
27+
{
28+
Assert.Null(FirebaseApp.DefaultInstance);
29+
}
30+
31+
[Fact]
32+
public void GetNonExistingInstance()
33+
{
34+
Assert.Null(FirebaseApp.GetInstance("non.existing"));
35+
}
36+
37+
[Fact]
38+
public void DefaultInstance()
39+
{
40+
var app = FirebaseApp.Create();
41+
Assert.Equal("[DEFAULT]", app.Name);
42+
Assert.NotNull(app.Options);
43+
Assert.Same(app, FirebaseApp.DefaultInstance);
44+
Assert.Throws<ArgumentException>(() => FirebaseApp.Create());
45+
app.Delete();
46+
Assert.Null(FirebaseApp.DefaultInstance);
47+
}
48+
49+
[Fact]
50+
public void CreateNamedInstance()
51+
{
52+
const string name = "MyApp";
53+
var app = FirebaseApp.Create(name);
54+
Assert.Equal(name, app.Name);
55+
Assert.NotNull(app.Options);
56+
Assert.Same(app, FirebaseApp.GetInstance(name));
57+
Assert.Throws<ArgumentException>(() => FirebaseApp.Create(name: name));
58+
app.Delete();
59+
Assert.Null(FirebaseApp.GetInstance(name: name));
60+
}
61+
62+
[Fact]
63+
public void CreateWithInvalidName()
64+
{
65+
Assert.Throws<ArgumentException>(() => FirebaseApp.Create((String) null));
66+
Assert.Throws<ArgumentException>(() => FirebaseApp.Create(name: string.Empty));
67+
}
68+
69+
[Fact]
70+
public void GetInstanceWithInvalidName()
71+
{
72+
Assert.Throws<ArgumentException>(() => FirebaseApp.GetInstance(null));
73+
Assert.Throws<ArgumentException>(() => FirebaseApp.GetInstance(string.Empty));
74+
}
75+
76+
[Fact]
77+
public void NoCredential()
78+
{
79+
Assert.Throws<ArgumentNullException>(() => FirebaseApp.Create(new AppOptions()));
80+
}
81+
82+
[Fact]
83+
public void CreateAppOptions()
84+
{
85+
var credential = GoogleCredential.FromAccessToken("token");
86+
var options = new AppOptions()
87+
{
88+
Credential = credential,
89+
ProjectId = "test-project",
90+
ServiceAccountId = "[email protected]",
91+
};
92+
var app = FirebaseApp.Create(options);
93+
Assert.Equal("[DEFAULT]", app.Name);
94+
95+
var copy = app.Options;
96+
Assert.NotSame(options, copy);
97+
Assert.Same(credential, copy.Credential);
98+
Assert.Equal("test-project", copy.ProjectId);
99+
Assert.Equal("[email protected]", copy.ServiceAccountId);
100+
}
101+
102+
[Fact]
103+
public void ServiceAccountCredentialScoping()
104+
{
105+
var credential = GoogleCredential.FromFile("./resources/service_account.json");
106+
var options = new AppOptions()
107+
{
108+
Credential = credential,
109+
};
110+
var app = FirebaseApp.Create(options);
111+
Assert.Equal("[DEFAULT]", app.Name);
112+
113+
var copy = app.Options;
114+
Assert.NotSame(options, copy);
115+
Assert.NotSame(credential, copy.Credential);
116+
Assert.IsType<ServiceAccountCredential>(copy.Credential.UnderlyingCredential);
117+
var credentialScopes = (copy.Credential.UnderlyingCredential as ServiceAccountCredential).Scopes;
118+
foreach (var scope in FirebaseApp.DefaultScopes)
119+
{
120+
Assert.Contains(scope, credentialScopes);
121+
}
122+
}
123+
124+
[Fact]
125+
public void GetProjectIdFromOptions()
126+
{
127+
var options = new AppOptions()
128+
{
129+
Credential = GoogleCredential.FromAccessToken("token"),
130+
ProjectId = "test-project",
131+
};
132+
var app = FirebaseApp.Create(options);
133+
Assert.Equal("test-project", app.GetProjectId());
134+
}
135+
136+
[Fact]
137+
public void GetOrInitService()
138+
{
139+
ServiceFactory<MockService> factory = () => {
140+
return new MockService();
141+
};
142+
var app = FirebaseApp.Create();
143+
var service1 = app.GetOrInit("MockService", factory);
144+
var service2 = app.GetOrInit("MockService", factory);
145+
Assert.Same(service1, service2);
146+
Assert.Throws<InvalidCastException>(() => {
147+
app.GetOrInit("MockService", () => { return new OtherMockService(); });
148+
});
149+
150+
Assert.False(service1.Deleted);
151+
app.Delete();
152+
Assert.True(service1.Deleted);
153+
Assert.Throws<InvalidOperationException>(() =>
154+
{
155+
app.GetOrInit("MockService", factory);
156+
});
157+
}
158+
159+
public void Dispose()
160+
{
161+
FirebaseApp.DeleteAll();
162+
}
163+
}
164+
165+
internal class MockService: IFirebaseService
166+
{
167+
public bool Deleted { get; private set; }
168+
169+
public void Delete()
170+
{
171+
Deleted = true;
172+
}
173+
}
174+
175+
internal class OtherMockService: IFirebaseService
176+
{
177+
public void Delete() {}
178+
}
179+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"type": "service_account",
3+
"project_id": "test-project",
4+
"private_key_id": "test-key-id",
5+
"private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC0LY4/Nn6pGauH\nk2ZRcaRViS2DMD7kq0PtD4HOW83nPArHnlpgzb/aFrxczHBjtKWOhjj+msy5CFJa\ny9/zqgFx2xtzzccnD13QNoXAAcSoKzcRg9T8aFssgykKDogXL8K2lqBheTM3WJeb\nhv3OhUGiizFNL3p9kZUR1r3aiCG7jHzexZ75XQK31xpkBLSKAaDc+K5d8OP2yDK9\nYsfEW3YThuRPY36ibMS4ejDynH3lXsLSpYVwEqfJS0dV6PRedMYBm1x6GpIbcHJG\ndSj02SNnWw70mq7ubltfZ/wmurSD8kp2rGNzNeI9IosRyLVW3jnUlGntScX9XCcE\nq5TBo7x3AgMBAAECggEAD8hzzvQU7qF/MJOdYWICjV7vBoW55Km0prX2iXSU71Nc\n9bUt4TqfZS5xAUdZSv/z3AMZnVftugGmxn8DFvhGmHTN4qbdHKilxPZEYMLm4/z7\nyG7TapQw9GUS5Gd3Ird+J3oUrM/YnYRcV3U2PhqB2t1gNreDfoS7rwHaxKNVzR9b\nFzlsAUqYnxKN35V6dsXXZ15uRxqPEMsLnBEosQnTd24mkgusdmqIDK3IQJfiLwdH\nSarWEwkuOX7mWsX7FoGXI0fb/HCAh4Cob8eeK4kNQ2EC7LoA/57e01pXVM8Fq1wo\nrwHlcZvGCZ4/MeVbhzAGGGzxnhCAZAoEWd2t98eFlQKBgQD6p+RojhISBJ9dODJm\nA0cz8Od23Ya6HGQopUNMYva6eCUtZMMSw/U3kAsnP5b52pvAT4PaiVO2N68ShWHM\nET/57JBJooo0SzUOu9dD6XuCA3brg3EM9g7wBXGWKgm2MA+ePSOQ6EEwhEmdd0lE\n8PTLBQfLxavndxsbL1AwoVEcUwKBgQC4BPy7IfpErPtVO+dh1MoKOpSO9iO+bZoE\nFYRmG7lNjECHrTBrLmZgk/oS74Fy/yO7gCVMbgHBHkXQevvkjQDRXWFg6SgFSBTs\nPHNXLEPugHDM6A7HHEiCKmHG8o97oaA2bswKdkUae529T39tddvg/jEPMnwOFLPa\n+OsdIP36zQKBgBLZDRPPmww/zLv1vdRt6qy9MKp/feIAwIdN5gGYb3UWE7WWHhUL\nJyVGb5BD99ZR2eRcFk4YhXLuPPvni7MMmQLyBueCkWHdReAVv9obdG4SVJ7hA182\nIWlq/1+LSa+pbYM4lbQPwtcjG2X70kac18tsVWm9M2/0RNWGeUEu4CqBAoGBAKwl\n1jxF2/d1D6Y75QhrZRrOlH1tHCEgLS3W50YSd3ZpV1DVnu8VuCZvKEmgjywCLO5S\nQhJO8wszg8I12wGDOxmhTuC3HX5bYV9iadBKE77Bn0TBblmsRtSmS1QvRDU3DUb+\nvZin7ZuJuxYHkcDXufuwMDr0UoNlsJ+Pr3tPiumdAoGAcP3xjmOeuHOgJM8q8Cph\n2mldP9Xg4NKONsDdQef9KEz5kXca2CIMCnPvbzTUD2CUtfhkrIEvqdS0jF1b65Un\nrUnGyoLQFMKhXV9JmO6YLwqWAdgAXoK5UIDdTPcjXkj2QE5U5oLTSm5UB0DpXcqU\njcLQwGUJgvrvI/st5Ubxan0=\n-----END PRIVATE KEY-----\n",
6+
"client_email": "[email protected]",
7+
"client_id": "test-client-id",
8+
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
9+
"token_uri": "https://accounts.google.com/o/oauth2/token",
10+
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
11+
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test-cert.iam.gserviceaccount.com"
12+
}

FirebaseAdmin/FirebaseAdmin.sln

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio 15
4+
VisualStudioVersion = 15.0.26124.0
5+
MinimumVisualStudioVersion = 15.0.26124.0
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FirebaseAdmin", "FirebaseAdmin\FirebaseAdmin.csproj", "{20D3B9D9-7461-441A-A798-6B124417F7A3}"
7+
EndProject
8+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FirebaseAdmin.Tests", "FirebaseAdmin.Tests\FirebaseAdmin.Tests.csproj", "{112BBB08-E51B-422B-864D-023FCCF212D2}"
9+
EndProject
10+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FirebaseAdmin.IntegrationTests", "FirebaseAdmin.IntegrationTests\FirebaseAdmin.IntegrationTests.csproj", "{709FCC13-249A-4752-972F-B770B0652919}"
11+
EndProject
12+
Global
13+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
14+
Debug|Any CPU = Debug|Any CPU
15+
Debug|x64 = Debug|x64
16+
Debug|x86 = Debug|x86
17+
Release|Any CPU = Release|Any CPU
18+
Release|x64 = Release|x64
19+
Release|x86 = Release|x86
20+
EndGlobalSection
21+
GlobalSection(SolutionProperties) = preSolution
22+
HideSolutionNode = FALSE
23+
EndGlobalSection
24+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
25+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
26+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
27+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Debug|x64.ActiveCfg = Debug|x64
28+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Debug|x64.Build.0 = Debug|x64
29+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Debug|x86.ActiveCfg = Debug|x86
30+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Debug|x86.Build.0 = Debug|x86
31+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
32+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Release|Any CPU.Build.0 = Release|Any CPU
33+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Release|x64.ActiveCfg = Release|x64
34+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Release|x64.Build.0 = Release|x64
35+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Release|x86.ActiveCfg = Release|x86
36+
{20D3B9D9-7461-441A-A798-6B124417F7A3}.Release|x86.Build.0 = Release|x86
37+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
38+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Debug|Any CPU.Build.0 = Debug|Any CPU
39+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Debug|x64.ActiveCfg = Debug|x64
40+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Debug|x64.Build.0 = Debug|x64
41+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Debug|x86.ActiveCfg = Debug|x86
42+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Debug|x86.Build.0 = Debug|x86
43+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Release|Any CPU.ActiveCfg = Release|Any CPU
44+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Release|Any CPU.Build.0 = Release|Any CPU
45+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Release|x64.ActiveCfg = Release|x64
46+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Release|x64.Build.0 = Release|x64
47+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Release|x86.ActiveCfg = Release|x86
48+
{112BBB08-E51B-422B-864D-023FCCF212D2}.Release|x86.Build.0 = Release|x86
49+
{709FCC13-249A-4752-972F-B770B0652919}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
50+
{709FCC13-249A-4752-972F-B770B0652919}.Debug|Any CPU.Build.0 = Debug|Any CPU
51+
{709FCC13-249A-4752-972F-B770B0652919}.Debug|x64.ActiveCfg = Debug|Any CPU
52+
{709FCC13-249A-4752-972F-B770B0652919}.Debug|x64.Build.0 = Debug|Any CPU
53+
{709FCC13-249A-4752-972F-B770B0652919}.Debug|x86.ActiveCfg = Debug|Any CPU
54+
{709FCC13-249A-4752-972F-B770B0652919}.Debug|x86.Build.0 = Debug|Any CPU
55+
{709FCC13-249A-4752-972F-B770B0652919}.Release|Any CPU.ActiveCfg = Release|Any CPU
56+
{709FCC13-249A-4752-972F-B770B0652919}.Release|Any CPU.Build.0 = Release|Any CPU
57+
{709FCC13-249A-4752-972F-B770B0652919}.Release|x64.ActiveCfg = Release|Any CPU
58+
{709FCC13-249A-4752-972F-B770B0652919}.Release|x64.Build.0 = Release|Any CPU
59+
{709FCC13-249A-4752-972F-B770B0652919}.Release|x86.ActiveCfg = Release|Any CPU
60+
{709FCC13-249A-4752-972F-B770B0652919}.Release|x86.Build.0 = Release|Any CPU
61+
EndGlobalSection
62+
EndGlobal
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright 2018, Google Inc. All rights reserved.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
using System;
16+
using System.Collections.Generic;
17+
using Google.Apis.Auth.OAuth2;
18+
19+
namespace FirebaseAdmin
20+
{
21+
/// <summary>
22+
/// Configurable options that can be specified when creating a <see cref="FirebaseApp"/>.
23+
/// See <a href="https://firebase.google.com/docs/admin/setup#initialize_the_sdk">
24+
/// Initialize the SDK</a> for code samples and detailed documentation.
25+
/// </summary>
26+
public sealed class AppOptions
27+
{
28+
/// <summary>
29+
/// <see cref="GoogleCredential"/> used to authorize an app. All service calls made by
30+
/// the app will be authorized using this.
31+
/// </summary>
32+
public GoogleCredential Credential { get; set; }
33+
34+
/// <summary>
35+
/// The Google Cloud Platform project ID that should be associated with an app.
36+
/// </summary>
37+
public string ProjectId { get; set; }
38+
39+
/// <summary>
40+
/// The unique ID of the service account that should be associated with an app.
41+
/// <para>This is used to <a href="https://firebase.google.com/docs/auth/admin/create-custom-tokens">
42+
/// create custom auth tokens</a> when service account credentials are not available. The
43+
/// service account ID can be found in the <c>client_email</c> field of the service account
44+
/// JSON.</para>
45+
/// </summary>
46+
public string ServiceAccountId { get; set; }
47+
48+
/// <summary>
49+
/// Creates a new <see cref="AppOptions"/> instance.
50+
/// </summary>
51+
public AppOptions() {}
52+
53+
internal AppOptions(AppOptions options)
54+
{
55+
Credential = options.Credential;
56+
ProjectId = options.ProjectId;
57+
ServiceAccountId = options.ServiceAccountId;
58+
}
59+
}
60+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>netstandard1.5</TargetFramework>
5+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
6+
<Copyright>Copyright 2018 Google LLC</Copyright>
7+
<Authors>Google Inc.</Authors>
8+
</PropertyGroup>
9+
10+
<ItemGroup>
11+
<PackageReference Include="Google.Apis.Auth" Version="1.34.0" />
12+
<PackageReference Include="System.Collections.Immutable" Version="1.5.0" />
13+
</ItemGroup>
14+
15+
</Project>

0 commit comments

Comments
 (0)