Skip to content

Commit

Permalink
Fixes missing HTTP header X-Goog-User-Project (#2348)
Browse files Browse the repository at this point in the history
Flank does not pass the the HTTP header flag X-Goog-user-Project with project Id when
using end user credentials. This results in HTTP error 403 (PERMISSION_DENIED). This fix
sets the flag so the tests can be run by the user.

Fixes #2347
  • Loading branch information
vinaypotluri authored Mar 9, 2023
1 parent b36137a commit 327033f
Show file tree
Hide file tree
Showing 9 changed files with 54 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package ftl.client.google

import com.google.api.client.http.HttpHeaders
import com.google.testing.model.AndroidDevice
import com.google.testing.model.AndroidDeviceCatalog
import com.google.testing.model.AndroidModel
import com.google.testing.model.Orientation
import ftl.config.FtlConstants.GCS_PROJECT_HEADER
import ftl.http.executeWithRetry
import ftl.presentation.cli.firebase.test.reportmanager.ReportManagerState
import ftl.presentation.publish
Expand All @@ -21,6 +23,7 @@ object AndroidCatalog {
GcTesting.get.testEnvironmentCatalog()
.get("android")
.setProjectId(projectId)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, projectId))
.executeWithRetry()
.androidDeviceCatalog
.filterDevicesWithoutSupportedVersions()
Expand Down
4 changes: 4 additions & 0 deletions test_runner/src/main/kotlin/ftl/client/google/GcTestMatrix.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package ftl.client.google

import com.google.api.client.http.HttpHeaders
import com.google.testing.model.CancelTestMatrixResponse
import com.google.testing.model.TestMatrix
import ftl.config.FtlConstants.GCS_PROJECT_HEADER
import ftl.http.executeWithRetry
import ftl.run.exception.FlankGeneralError
import kotlinx.coroutines.Dispatchers
Expand Down Expand Up @@ -38,6 +40,7 @@ object GcTestMatrix {
suspend fun refresh(testMatrixId: String, projectId: String): TestMatrix {
val getMatrix = withContext(Dispatchers.IO) {
GcTesting.get.projects().testMatrices().get(projectId, testMatrixId)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, projectId))
}
var failed = 0
val maxWait = ofHours(1).seconds
Expand All @@ -57,6 +60,7 @@ object GcTestMatrix {
suspend fun cancel(testMatrixId: String, projectId: String): CancelTestMatrixResponse {
val cancelMatrix = withContext(Dispatchers.IO) {
GcTesting.get.projects().testMatrices().cancel(projectId, testMatrixId)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, projectId))
}
var failed = 0
val maxTries = 3
Expand Down
30 changes: 27 additions & 3 deletions test_runner/src/main/kotlin/ftl/client/google/GcToolResults.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ftl.client.google

import com.google.api.client.http.HttpHeaders
import com.google.api.services.toolresults.ToolResults
import com.google.api.services.toolresults.model.Environment
import com.google.api.services.toolresults.model.Execution
Expand All @@ -16,6 +17,7 @@ import com.google.testing.model.ToolResultsHistory
import com.google.testing.model.ToolResultsStep
import ftl.args.IArgs
import ftl.config.FtlConstants
import ftl.config.FtlConstants.GCS_PROJECT_HEADER
import ftl.config.FtlConstants.JSON_FACTORY
import ftl.config.FtlConstants.applicationName
import ftl.config.FtlConstants.httpTransport
Expand Down Expand Up @@ -44,6 +46,7 @@ object GcToolResults {
.histories()
.list(args.project)
.setFilterByName(args.resultsHistoryName)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, args.project))
.executeWithRetry()
return result?.histories ?: emptyList()
}
Expand All @@ -56,6 +59,7 @@ object GcToolResults {
.projects()
.histories()
.create(args.project, history)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, args.project))
.execute()
}

Expand Down Expand Up @@ -90,6 +94,7 @@ object GcToolResults {
toolResultsStep.historyId,
toolResultsStep.executionId
)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, testExecution.projectId))
.executeWithRetry()
}

Expand All @@ -105,6 +110,7 @@ object GcToolResults {
toolResultsStep.executionId,
toolResultsStep.stepId
)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, toolResultsStep.projectId))
.executeWithRetry()
}

Expand All @@ -121,6 +127,7 @@ object GcToolResults {
toolResultsStep.executionId,
toolResultsStep.stepId
)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, toolResultsStep.projectId))
.executeWithRetry()

// Lists Test Cases attached to a Step
Expand All @@ -141,6 +148,7 @@ object GcToolResults {
toolResultsStep.stepId
)
.setPageToken(pageToken)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, toolResultsStep.projectId))
.executeWithRetry()
}

Expand All @@ -155,12 +163,26 @@ object GcToolResults {
}

fun getDefaultBucket(projectId: String, source: String? = null): String? = try {
service.Projects().initializeSettings(projectId).executeWithRetry().defaultBucket
service.Projects().initializeSettings(projectId)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, projectId))
.executeWithRetry()
.defaultBucket
} catch (ftlProjectError: FTLProjectError) {
// flank needs to rewrap the exception with additional info about project
when (ftlProjectError) {
is PermissionDenied -> throw FlankGeneralError(permissionDeniedErrorMessage(projectId, source, ftlProjectError.message))
is ProjectNotFound -> throw FlankGeneralError(projectNotFoundErrorMessage(projectId, ftlProjectError.message))
is PermissionDenied -> throw FlankGeneralError(
permissionDeniedErrorMessage(
projectId,
source,
ftlProjectError.message
)
)
is ProjectNotFound -> throw FlankGeneralError(
projectNotFoundErrorMessage(
projectId,
ftlProjectError.message
)
)
is FailureToken -> UserAuth.throwAuthenticationError()
}
}
Expand Down Expand Up @@ -190,6 +212,7 @@ object GcToolResults {
)
.setPageToken(pageToken)
.setPageSize(100)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, results.projectId))
.executeWithRetry()

fun listAllSteps(results: ToolResultsExecution): MutableList<Step> {
Expand Down Expand Up @@ -217,6 +240,7 @@ object GcToolResults {
)
.setPageToken(pageToken)
.setPageSize(100)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, results.projectId))
.executeWithRetry()
}

Expand Down
3 changes: 3 additions & 0 deletions test_runner/src/main/kotlin/ftl/client/google/IosCatalog.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package ftl.client.google

import com.google.api.client.http.HttpHeaders
import com.google.testing.model.IosDeviceCatalog
import com.google.testing.model.IosModel
import com.google.testing.model.Orientation
import ftl.config.Device
import ftl.config.FtlConstants.GCS_PROJECT_HEADER
import ftl.environment.getLocaleDescription
import ftl.environment.ios.getDescription
import ftl.environment.ios.iosVersionsToCliTable
Expand Down Expand Up @@ -50,6 +52,7 @@ object IosCatalog {
GcTesting.get.testEnvironmentCatalog()
.get("ios")
.setProjectId(projectId)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, projectId))
.executeWithRetry()
.iosDeviceCatalog
.filterDevicesWithoutSupportedVersions()
Expand Down
6 changes: 5 additions & 1 deletion test_runner/src/main/kotlin/ftl/client/google/OsVersion.kt
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package ftl.client.google

import com.google.api.client.http.HttpHeaders
import com.google.testing.model.AndroidVersion
import com.google.testing.model.IosVersion
import ftl.config.FtlConstants.GCS_PROJECT_HEADER
import ftl.http.executeWithRetry

fun androidOsVersions(projectId: String): List<AndroidVersion> =
GcTesting.get.testEnvironmentCatalog()
.get("android")
.setProjectId(projectId)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, projectId))
.executeWithRetry()
.androidDeviceCatalog
.versions
Expand All @@ -17,7 +20,8 @@ fun iosOsVersions(projectId: String): List<IosVersion> =
GcTesting.get.testEnvironmentCatalog()
.get("ios")
.setProjectId(projectId)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, projectId))
.executeWithRetry()
.iosDeviceCatalog
.versions
.orEmpty()
.orEmpty()
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ftl.client.google.run.android

import com.google.api.client.http.HttpHeaders
import com.google.common.annotations.VisibleForTesting
import com.google.testing.Testing
import com.google.testing.model.Account
Expand All @@ -22,6 +23,7 @@ import ftl.api.TestMatrixAndroid
import ftl.client.google.GcTesting
import ftl.client.google.run.toClientInfoDetailList
import ftl.client.google.run.toFileReference
import ftl.config.FtlConstants.GCS_PROJECT_HEADER
import ftl.http.executeWithRetry
import ftl.run.exception.FlankGeneralError
import ftl.util.timeoutToSeconds
Expand All @@ -45,7 +47,9 @@ private suspend fun executeAndroidTestMatrix(
): List<Deferred<TestMatrix>> = coroutineScope {
(0 until config.repeatTests).map { runIndex ->
async(Dispatchers.IO) {
createAndroidTestMatrix(type, config, typeIndex, runIndex).executeWithRetry()
createAndroidTestMatrix(type, config, typeIndex, runIndex)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, config.project))
.executeWithRetry()
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package ftl.client.google.run.ios

import com.google.api.client.http.HttpHeaders
import com.google.testing.Testing
import com.google.testing.model.ClientInfo
import com.google.testing.model.EnvironmentMatrix
Expand All @@ -15,6 +16,7 @@ import ftl.client.google.run.mapGcsPathsToFileReference
import ftl.client.google.run.mapToIosDeviceFiles
import ftl.client.google.run.toClientInfoDetailList
import ftl.client.google.run.toIosDeviceFile
import ftl.config.FtlConstants.GCS_PROJECT_HEADER
import ftl.http.executeWithRetry
import ftl.run.exception.FlankGeneralError
import ftl.util.timeoutToSeconds
Expand All @@ -37,7 +39,9 @@ private suspend fun executeIosTestMatrixAsync(
config: TestMatrixIos.Config
): Deferred<TestMatrix> = coroutineScope {
async(Dispatchers.IO) {
createIosTestMatrix(type, config).executeWithRetry()
createIosTestMatrix(type, config)
.setRequestHeaders(HttpHeaders().set(GCS_PROJECT_HEADER, config.project))
.executeWithRetry()
}
}

Expand Down
1 change: 1 addition & 0 deletions test_runner/src/main/kotlin/ftl/config/FtlConstants.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ object FtlConstants {
const val indent = " "
const val matrixIdsFile = "matrix_ids.json"
const val applicationName = "Flank"
const val GCS_PROJECT_HEADER = "x-goog-user-project"
const val GCS_PREFIX = "gs://"
const val GCS_STORAGE_LINK = "https://console.developers.google.com/storage/browser/"
const val runTimeout = "-1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class BillableMinutesTest {
.testEnvironmentCatalog()
.get(any())
.setProjectId(any())
.setRequestHeaders(any())
.executeWithRetry()
} returns make {
androidDeviceCatalog = make { models = androidModels }
Expand Down

0 comments on commit 327033f

Please sign in to comment.