-
Notifications
You must be signed in to change notification settings - Fork 190
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
S3 settings functional tests #2837
Merged
Compile-Ninja
merged 16 commits into
s3-application-settings/copy
from
s3-settings-functional-tests
Sep 3, 2024
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
371673a
Add functional tests for S3 storage support
osulzhenko 18696f2
update after review
osulzhenko 7c17435
update after review
osulzhenko 2a9836d
update after review
osulzhenko 4f7deb0
Add clear bucket method
osulzhenko 5594ecf
Add clear bucket method
osulzhenko 2896dbe
Merge remote-tracking branch 'origin/s3-settings-functional-tests' in…
osulzhenko a3d1fdb
Merge branch 'highfivve-github-master' into s3-settings-functional-tests
osulzhenko a0dd561
pending validation for matching records in S3
osulzhenko 1a92ff0
Merge branch 'refs/heads/highfivve-github-master' into s3-settings-fu…
osulzhenko 1880058
update functional tests
osulzhenko b06b0c7
Merge branch 'refs/heads/highfivve-github-master' into s3-settings-fu…
osulzhenko c1bcd04
add force-path-style setting
osulzhenko 479e2d5
Merge remote-tracking branch 'refs/remotes/origin/s3-application-sett…
marki1an e59aedb
Update gdpr
marki1an ab0d4c1
Update secure field
marki1an File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
103 changes: 103 additions & 0 deletions
103
src/test/groovy/org/prebid/server/functional/service/S3Service.groovy
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,103 @@ | ||
package org.prebid.server.functional.service | ||
|
||
import org.prebid.server.functional.model.config.AccountConfig | ||
import org.prebid.server.functional.model.db.StoredImp | ||
import org.prebid.server.functional.model.db.StoredRequest | ||
import org.prebid.server.functional.model.db.StoredResponse | ||
import org.prebid.server.functional.util.ObjectMapperWrapper | ||
import org.testcontainers.containers.localstack.LocalStackContainer | ||
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials | ||
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider | ||
import software.amazon.awssdk.core.sync.RequestBody | ||
import software.amazon.awssdk.regions.Region | ||
import software.amazon.awssdk.services.s3.S3Client | ||
import software.amazon.awssdk.services.s3.model.CreateBucketRequest | ||
import software.amazon.awssdk.services.s3.model.DeleteBucketRequest | ||
import software.amazon.awssdk.services.s3.model.DeleteObjectRequest | ||
import software.amazon.awssdk.services.s3.model.ListObjectsV2Request | ||
import software.amazon.awssdk.services.s3.model.PutObjectRequest | ||
import software.amazon.awssdk.services.s3.model.PutObjectResponse | ||
|
||
final class S3Service implements ObjectMapperWrapper { | ||
|
||
private final S3Client s3PbsService | ||
private final LocalStackContainer localStackContainer | ||
|
||
static final def DEFAULT_ACCOUNT_DIR = 'account' | ||
static final def DEFAULT_IMPS_DIR = 'stored-impressions' | ||
static final def DEFAULT_REQUEST_DIR = 'stored-requests' | ||
static final def DEFAULT_RESPONSE_DIR = 'stored-responses' | ||
|
||
S3Service(LocalStackContainer localStackContainer) { | ||
this.localStackContainer = localStackContainer | ||
s3PbsService = S3Client.builder() | ||
.endpointOverride(localStackContainer.getEndpointOverride(LocalStackContainer.Service.S3)) | ||
.credentialsProvider( | ||
StaticCredentialsProvider.create( | ||
AwsBasicCredentials.create( | ||
localStackContainer.getAccessKey(), | ||
localStackContainer.getSecretKey()))) | ||
.region(Region.of(localStackContainer.getRegion())) | ||
.build() | ||
} | ||
|
||
String getAccessKeyId() { | ||
localStackContainer.accessKey | ||
} | ||
|
||
String getSecretKeyId() { | ||
localStackContainer.secretKey | ||
} | ||
|
||
String getEndpoint() { | ||
"http://${localStackContainer.getNetworkAliases().get(0)}:${localStackContainer.getExposedPorts().get(0)}" | ||
} | ||
|
||
String getRegion() { | ||
localStackContainer.region | ||
} | ||
|
||
void createBucket(String bucketName) { | ||
CreateBucketRequest createBucketRequest = CreateBucketRequest.builder() | ||
.bucket(bucketName) | ||
.build() | ||
s3PbsService.createBucket(createBucketRequest) | ||
} | ||
|
||
void deleteBucket(String bucketName) { | ||
DeleteBucketRequest deleteBucketRequest = DeleteBucketRequest.builder() | ||
.bucket(bucketName) | ||
.build() | ||
s3PbsService.deleteBucket(deleteBucketRequest) | ||
} | ||
|
||
void purgeBucketFiles(String bucketName) { | ||
s3PbsService.listObjectsV2(ListObjectsV2Request.builder().bucket(bucketName).build()).contents().each { files -> | ||
s3PbsService.deleteObject(DeleteObjectRequest.builder().bucket(bucketName).key(files.key()).build()) | ||
} | ||
} | ||
|
||
PutObjectResponse uploadAccount(String bucketName, AccountConfig account, String fileName = account.id) { | ||
uploadFile(bucketName, encode(account), "${DEFAULT_ACCOUNT_DIR}/${fileName}.json") | ||
} | ||
|
||
PutObjectResponse uploadStoredRequest(String bucketName, StoredRequest storedRequest, String fileName = storedRequest.requestId) { | ||
uploadFile(bucketName, encode(storedRequest.requestData), "${DEFAULT_REQUEST_DIR}/${fileName}.json") | ||
} | ||
|
||
PutObjectResponse uploadStoredResponse(String bucketName, StoredResponse storedRequest, String fileName = storedRequest.responseId) { | ||
uploadFile(bucketName, encode(storedRequest.storedAuctionResponse), "${DEFAULT_RESPONSE_DIR}/${fileName}.json") | ||
} | ||
|
||
PutObjectResponse uploadStoredImp(String bucketName, StoredImp storedImp, String fileName = storedImp.impId) { | ||
uploadFile(bucketName, encode(storedImp.impData), "${DEFAULT_IMPS_DIR}/${fileName}.json") | ||
} | ||
|
||
PutObjectResponse uploadFile(String bucketName, String fileBody, String path) { | ||
PutObjectRequest putObjectRequest = PutObjectRequest.builder() | ||
.bucket(bucketName) | ||
.key(path) | ||
.build() | ||
s3PbsService.putObject(putObjectRequest, RequestBody.fromString(fileBody)) | ||
} | ||
} |
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
118 changes: 118 additions & 0 deletions
118
src/test/groovy/org/prebid/server/functional/tests/storage/AccountS3Spec.groovy
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,118 @@ | ||
package org.prebid.server.functional.tests.storage | ||
|
||
import org.prebid.server.functional.model.AccountStatus | ||
import org.prebid.server.functional.model.config.AccountConfig | ||
import org.prebid.server.functional.model.request.auction.BidRequest | ||
import org.prebid.server.functional.service.PrebidServerException | ||
import org.prebid.server.functional.service.PrebidServerService | ||
import org.prebid.server.functional.service.S3Service | ||
import org.prebid.server.functional.testcontainers.PbsServiceFactory | ||
import org.prebid.server.functional.util.PBSUtils | ||
|
||
import static io.netty.handler.codec.http.HttpResponseStatus.UNAUTHORIZED | ||
|
||
class AccountS3Spec extends StorageBaseSpec { | ||
|
||
protected PrebidServerService s3StorageAccountPbsService = PbsServiceFactory.getService(s3StorageConfig + | ||
mySqlDisabledConfig + | ||
['settings.enforce-valid-account': 'true']) | ||
|
||
def "PBS should process request when active account is present in S3 storage"() { | ||
given: "Default BidRequest with account" | ||
def accountId = PBSUtils.randomNumber as String | ||
def bidRequest = BidRequest.defaultBidRequest.tap { | ||
setAccountId(accountId) | ||
} | ||
|
||
and: "Active account config" | ||
def account = new AccountConfig(id: accountId, status: AccountStatus.ACTIVE) | ||
|
||
and: "Saved account in AWS S3 storage" | ||
s3Service.uploadAccount(DEFAULT_BUCKET, account) | ||
|
||
when: "PBS processes auction request" | ||
def response = s3StorageAccountPbsService.sendAuctionRequest(bidRequest) | ||
|
||
then: "Response should contain seatbid" | ||
assert response.seatbid.size() == 1 | ||
} | ||
|
||
def "PBS should throw exception when inactive account is present in S3 storage"() { | ||
given: "Default BidRequest with account" | ||
def accountId = PBSUtils.randomNumber as String | ||
def bidRequest = BidRequest.defaultBidRequest.tap { | ||
setAccountId(accountId) | ||
} | ||
|
||
and: "Inactive account config" | ||
def account = new AccountConfig(id: accountId, status: AccountStatus.INACTIVE) | ||
|
||
and: "Saved account in AWS S3 storage" | ||
s3Service.uploadAccount(DEFAULT_BUCKET, account) | ||
|
||
when: "PBS processes auction request" | ||
s3StorageAccountPbsService.sendAuctionRequest(bidRequest) | ||
|
||
then: "PBS should reject the entire auction" | ||
def exception = thrown(PrebidServerException) | ||
assert exception.statusCode == UNAUTHORIZED.code() | ||
assert exception.responseBody == "Account $accountId is inactive" | ||
} | ||
|
||
def "PBS should throw exception when account id isn't match with bid request account id"() { | ||
given: "Default BidRequest with account" | ||
def accountId = PBSUtils.randomNumber as String | ||
def bidRequest = BidRequest.defaultBidRequest.tap { | ||
setAccountId(accountId) | ||
} | ||
|
||
and: "Account config with different accountId" | ||
def account = new AccountConfig(id: PBSUtils.randomString, status: AccountStatus.ACTIVE) | ||
|
||
and: "Saved account in AWS S3 storage" | ||
s3Service.uploadAccount(DEFAULT_BUCKET, account, accountId) | ||
|
||
when: "PBS processes auction request" | ||
s3StorageAccountPbsService.sendAuctionRequest(bidRequest) | ||
|
||
then: "PBS should reject the entire auction" | ||
def exception = thrown(PrebidServerException) | ||
assert exception.statusCode == UNAUTHORIZED.code() | ||
assert exception.responseBody == "Unauthorized account id: ${accountId}" | ||
} | ||
|
||
def "PBS should throw exception when account is invalid in S3 storage json file"() { | ||
given: "Default BidRequest" | ||
def accountId = PBSUtils.randomNumber as String | ||
def bidRequest = BidRequest.defaultBidRequest.tap { | ||
setAccountId(accountId) | ||
} | ||
|
||
and: "Saved invalid account in AWS S3 storage" | ||
s3Service.uploadFile(DEFAULT_BUCKET, INVALID_FILE_BODY, "${S3Service.DEFAULT_ACCOUNT_DIR}/${accountId}.json") | ||
|
||
when: "PBS processes auction request" | ||
s3StorageAccountPbsService.sendAuctionRequest(bidRequest) | ||
|
||
then: "PBS should reject the entire auction" | ||
def exception = thrown(PrebidServerException) | ||
assert exception.statusCode == UNAUTHORIZED.code() | ||
assert exception.responseBody == "Unauthorized account id: ${accountId}" | ||
} | ||
|
||
def "PBS should throw exception when account is not present in S3 storage and valid account enforced"() { | ||
given: "Default BidRequest" | ||
def accountId = PBSUtils.randomNumber as String | ||
def bidRequest = BidRequest.defaultBidRequest.tap { | ||
setAccountId(accountId) | ||
} | ||
|
||
when: "PBS processes auction request" | ||
s3StorageAccountPbsService.sendAuctionRequest(bidRequest) | ||
|
||
then: "PBS should reject the entire auction" | ||
def exception = thrown(PrebidServerException) | ||
assert exception.statusCode == UNAUTHORIZED.code() | ||
assert exception.responseBody == "Unauthorized account id: ${accountId}" | ||
} | ||
} |
115 changes: 115 additions & 0 deletions
115
src/test/groovy/org/prebid/server/functional/tests/storage/AmpS3Spec.groovy
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,115 @@ | ||
package org.prebid.server.functional.tests.storage | ||
|
||
import org.prebid.server.functional.model.db.StoredRequest | ||
import org.prebid.server.functional.model.request.amp.AmpRequest | ||
import org.prebid.server.functional.model.request.auction.BidRequest | ||
import org.prebid.server.functional.model.request.auction.Site | ||
import org.prebid.server.functional.service.PrebidServerException | ||
import org.prebid.server.functional.service.S3Service | ||
import org.prebid.server.functional.util.PBSUtils | ||
import spock.lang.PendingFeature | ||
|
||
import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST | ||
|
||
class AmpS3Spec extends StorageBaseSpec { | ||
|
||
def "PBS should take parameters from the stored request on S3 service when it's not specified in the request"() { | ||
given: "AMP request" | ||
def ampRequest = new AmpRequest(tagId: PBSUtils.randomString).tap { | ||
account = PBSUtils.randomNumber as String | ||
} | ||
|
||
and: "Default stored request" | ||
def ampStoredRequest = BidRequest.defaultStoredRequest.tap { | ||
site = Site.defaultSite | ||
setAccountId(ampRequest.account) | ||
} | ||
|
||
and: "Stored request in S3 service" | ||
def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest) | ||
s3Service.uploadStoredRequest(DEFAULT_BUCKET, storedRequest) | ||
|
||
when: "PBS processes amp request" | ||
s3StoragePbsService.sendAmpRequest(ampRequest) | ||
|
||
then: "Bidder request should contain parameters from the stored request" | ||
def bidderRequest = bidder.getBidderRequest(ampStoredRequest.id) | ||
|
||
assert bidderRequest.site?.page == ampStoredRequest.site.page | ||
assert bidderRequest.site?.publisher?.id == ampStoredRequest.site.publisher.id | ||
assert !bidderRequest.imp[0]?.tagId | ||
assert bidderRequest.imp[0]?.banner?.format[0]?.height == ampStoredRequest.imp[0].banner.format[0].height | ||
assert bidderRequest.imp[0]?.banner?.format[0]?.weight == ampStoredRequest.imp[0].banner.format[0].weight | ||
assert bidderRequest.regs?.gdpr == ampStoredRequest.regs.gdpr | ||
} | ||
|
||
@PendingFeature | ||
def "PBS should throw exception when trying to take parameters from the stored request on S3 service with invalid id in file"() { | ||
given: "AMP request" | ||
def ampRequest = new AmpRequest(tagId: PBSUtils.randomString).tap { | ||
account = PBSUtils.randomNumber as String | ||
} | ||
|
||
and: "Default stored request" | ||
def ampStoredRequest = BidRequest.defaultStoredRequest.tap { | ||
site = Site.defaultSite | ||
setAccountId(ampRequest.account) | ||
} | ||
|
||
and: "Stored request in S3 service" | ||
def storedRequest = StoredRequest.getStoredRequest(ampRequest, ampStoredRequest).tap { | ||
it.requestId = PBSUtils.randomNumber | ||
} | ||
s3Service.uploadStoredRequest(DEFAULT_BUCKET, storedRequest, ampRequest.tagId) | ||
|
||
when: "PBS processes amp request" | ||
s3StoragePbsService.sendAmpRequest(ampRequest) | ||
|
||
then: "PBS should throw request format error" | ||
def exception = thrown(PrebidServerException) | ||
assert exception.statusCode == BAD_REQUEST.code() | ||
assert exception.responseBody == "Invalid request format: Stored request processing failed: " + | ||
"No stored request found for id: ${ampRequest.tagId}" | ||
} | ||
|
||
def "PBS should throw exception when trying to take parameters from request where id isn't match with stored request id"() { | ||
given: "AMP request" | ||
def ampRequest = new AmpRequest(tagId: PBSUtils.randomString).tap { | ||
account = PBSUtils.randomNumber as String | ||
} | ||
|
||
and: "Default stored request" | ||
def ampStoredRequest = BidRequest.defaultStoredRequest.tap { | ||
site = Site.defaultSite | ||
setAccountId(ampRequest.account) | ||
} | ||
|
||
and: "Stored request in S3 service" | ||
s3Service.uploadFile(DEFAULT_BUCKET, INVALID_FILE_BODY, "${S3Service.DEFAULT_REQUEST_DIR}/${ampRequest.tagId}.json") | ||
|
||
when: "PBS processes amp request" | ||
s3StoragePbsService.sendAmpRequest(ampRequest) | ||
|
||
then: "PBS should throw request format error" | ||
def exception = thrown(PrebidServerException) | ||
assert exception.statusCode == BAD_REQUEST.code() | ||
assert exception.responseBody == "Invalid request format: Stored request processing failed: " + | ||
"Can't parse Json for stored request with id ${ampRequest.tagId}" | ||
} | ||
|
||
def "PBS should throw an exception when trying to take parameters from stored request on S3 service that do not exist"() { | ||
given: "AMP request" | ||
def ampRequest = new AmpRequest(tagId: PBSUtils.randomString).tap { | ||
account = PBSUtils.randomNumber as String | ||
} | ||
|
||
when: "PBS processes amp request" | ||
s3StoragePbsService.sendAmpRequest(ampRequest) | ||
|
||
then: "PBS should throw request format error" | ||
def exception = thrown(PrebidServerException) | ||
assert exception.statusCode == BAD_REQUEST.code() | ||
assert exception.responseBody == "Invalid request format: Stored request processing failed: " + | ||
"No stored request found for id: ${ampRequest.tagId}" | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This test makes sense and currently fails in the pipeline.