-
Notifications
You must be signed in to change notification settings - Fork 119
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Enhance permission denied exception logs (#875)
- Loading branch information
1 parent
aded032
commit 54930da
Showing
6 changed files
with
226 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
# Flank permissions denied behavior | ||
|
||
Reported on: [Clean flank not authorized error messages #874](https://github.com/Flank/flank/issues/874) | ||
|
||
Changed on: [Enhance permission denied exception logs #875](https://github.com/Flank/flank/pull/875) | ||
|
||
## 1. User don't have permission to project (403) | ||
|
||
When user don't have permission to project Flank should returns message like: | ||
|
||
```json | ||
|
||
Flank encountered a 403 error when running on project $project_name. Please verify this credential is authorized for the project. | ||
Consider authentication a with Service Account https://github.com/Flank/flank#authenticate-with-a-service-account | ||
or with a Google account https://github.com/Flank/flank#authenticate-with-a-google-account | ||
|
||
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden | ||
{ | ||
"code" : 403, | ||
"errors" : [ { | ||
"domain" : "global", | ||
"message" : "The caller does not have permission", | ||
"reason" : "forbidden" | ||
} ], | ||
"message" : "The caller does not have permission", | ||
"status" : "PERMISSION_DENIED" | ||
} | ||
|
||
``` | ||
|
||
You can reproduce the error by setting PROJECT_ID to a project that the firebase account doesn't have permission to access. | ||
|
||
## 2. Project not found (404) | ||
|
||
When project not found on firebase Flank should return message like: | ||
|
||
```json | ||
|
||
Flank was unable to find project $project_name. Please verify the project id. | ||
|
||
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 404 Not Found | ||
{ | ||
"code" : 404, | ||
"errors" : [ { | ||
"domain" : "global", | ||
"message" : "Project not found: $project_name", | ||
"reason" : "notFound" | ||
} ], | ||
"message" : "Project not found: $project_name", | ||
"status" : "NOT_FOUND" | ||
} | ||
|
||
``` | ||
|
||
You can reproduce the error by setting PROJECT_ID to a project that doesn't exist. | ||
|
||
## 3. On this two cases Flank throws FlankCommonException and exit with code: 1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
122 changes: 118 additions & 4 deletions
122
test_runner/src/test/kotlin/ftl/gc/GcToolResultsTest.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,157 @@ | ||
package ftl.gc | ||
|
||
import com.google.api.client.googleapis.json.GoogleJsonResponseException | ||
import com.google.api.client.http.HttpResponseException | ||
import com.google.api.services.testing.model.ToolResultsHistory | ||
import com.google.common.truth.Truth.assertThat | ||
import ftl.args.AndroidArgs | ||
import ftl.config.FtlConstants | ||
import ftl.test.util.FlankTestRunner | ||
import ftl.test.util.TestHelper.getThrowable | ||
import ftl.util.FlankCommonException | ||
import ftl.util.PermissionDenied | ||
import ftl.util.ProjectNotFound | ||
import io.mockk.every | ||
import io.mockk.mockk | ||
import io.mockk.mockkObject | ||
import io.mockk.unmockkAll | ||
import org.junit.After | ||
import org.junit.Assert.assertEquals | ||
import org.junit.Test | ||
import org.junit.runner.RunWith | ||
import java.io.IOException | ||
|
||
@RunWith(FlankTestRunner::class) | ||
class GcToolResultsTest { | ||
|
||
private val projectId = "123" | ||
|
||
@After | ||
fun tearDown() = unmockkAll() | ||
|
||
@Test | ||
fun `createToolResultsHistory null succeeds`() { | ||
val args = mockk<AndroidArgs>() | ||
every { args.project } returns "123" | ||
every { args.project } returns projectId | ||
every { args.resultsHistoryName } returns null | ||
|
||
val expected = ToolResultsHistory().setProjectId("123") | ||
val expected = ToolResultsHistory().setProjectId(projectId) | ||
|
||
assertThat(GcToolResults.createToolResultsHistory(args)).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `createToolResultsHistory succeeds`() { | ||
val args = mockk<AndroidArgs>() | ||
every { args.project } returns "123" | ||
every { args.project } returns projectId | ||
every { args.resultsHistoryName } returns "custom history" | ||
|
||
val expected = ToolResultsHistory() | ||
.setProjectId("123") | ||
.setProjectId(projectId) | ||
.setHistoryId("mockId") | ||
|
||
assertThat(GcToolResults.createToolResultsHistory(args)).isEqualTo(expected) | ||
} | ||
|
||
@Test | ||
fun `getDefaultBucket on 403 error should throw exception with specific message`() { | ||
val expected = """ | ||
Flank encountered a 403 error when running on project $projectId. Please verify this credential is authorized for the project and has the required permissions. | ||
Consider authentication with a Service Account https://github.com/Flank/flank#authenticate-with-a-service-account | ||
or with a Google account https://github.com/Flank/flank#authenticate-with-a-google-account | ||
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden | ||
{ | ||
"code" : 403, | ||
"errors" : [ { | ||
"domain" : "global", | ||
"message" : "The caller does not have permission", | ||
"reason" : "forbidden" | ||
} ], | ||
"message" : "The caller does not have permission", | ||
"status" : "PERMISSION_DENIED" | ||
} | ||
""".trimIndent() | ||
mockkObject(GcToolResults) { | ||
every { GcToolResults.service.applicationName } returns projectId | ||
|
||
val exceptionBuilder = mockk<HttpResponseException.Builder>() | ||
every { exceptionBuilder.message } returns """ | ||
403 Forbidden | ||
{ | ||
"code" : 403, | ||
"errors" : [ { | ||
"domain" : "global", | ||
"message" : "The caller does not have permission", | ||
"reason" : "forbidden" | ||
} ], | ||
"message" : "The caller does not have permission", | ||
"status" : "PERMISSION_DENIED" | ||
} | ||
""".trimIndent() | ||
val mockJSonException = GoogleJsonResponseException(exceptionBuilder, null) | ||
every { GcToolResults.service.Projects().initializeSettings(projectId) } throws PermissionDenied(mockJSonException) | ||
val exception = getThrowable { GcToolResults.getDefaultBucket(projectId) } | ||
assertEquals(expected, exception.message) | ||
} | ||
} | ||
|
||
@Test(expected = FlankCommonException::class) | ||
fun `getDefaultBucket on PermissionDenied error should throw FlankCommonException`() { | ||
mockkObject(GcToolResults) { | ||
every { GcToolResults.service.applicationName } returns projectId | ||
every { GcToolResults.service.Projects().initializeSettings(projectId) } throws PermissionDenied(IOException()) | ||
GcToolResults.getDefaultBucket(projectId) | ||
} | ||
} | ||
|
||
@Test(expected = FlankCommonException::class) | ||
fun `getDefaultBucket on ProjectNotFound error should throw FlankCommonException`() { | ||
mockkObject(GcToolResults) { | ||
every { GcToolResults.service.applicationName } returns projectId | ||
every { GcToolResults.service.Projects().initializeSettings(projectId) } throws ProjectNotFound(IOException()) | ||
GcToolResults.getDefaultBucket(projectId) | ||
} | ||
} | ||
|
||
@Test | ||
fun `getDefaultBucket on 404 error should throw exception with specific message`() { | ||
val expected = """ | ||
Flank was unable to find project $projectId. Please verify the project id. | ||
Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 404 Not Found | ||
{ | ||
"code" : 404, | ||
"errors" : [ { | ||
"domain" : "global", | ||
"message" : "Project not found: $projectId", | ||
"reason" : "notFound" | ||
} ], | ||
"message" : "Project not found: $projectId", | ||
"status" : "NOT_FOUND" | ||
} | ||
""".trimIndent() | ||
mockkObject(GcToolResults) { | ||
every { GcToolResults.service.applicationName } returns FtlConstants.applicationName | ||
|
||
val exceptionBuilder = mockk<HttpResponseException.Builder>() | ||
every { exceptionBuilder.message } returns """ | ||
404 Not Found | ||
{ | ||
"code" : 404, | ||
"errors" : [ { | ||
"domain" : "global", | ||
"message" : "Project not found: $projectId", | ||
"reason" : "notFound" | ||
} ], | ||
"message" : "Project not found: $projectId", | ||
"status" : "NOT_FOUND" | ||
} | ||
""".trimIndent() | ||
val mockJSonException = GoogleJsonResponseException(exceptionBuilder, null) | ||
every { GcToolResults.service.Projects().initializeSettings(projectId) } throws ProjectNotFound(mockJSonException) | ||
val exception = getThrowable { GcToolResults.getDefaultBucket(projectId) } | ||
assertEquals(expected, exception.message) | ||
} | ||
} | ||
} |