-
Notifications
You must be signed in to change notification settings - Fork 55
test: allow e2e service tests to be checked in #283
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
Conversation
| return true | ||
| } | ||
| // ensure the request context hasn't been cancelled | ||
| callContext.ensureActive() |
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 will throw a cancellation exception if the request context was cancelled. It doesn't fix the issue but will keep us from looping endlessly if the outer context is cancelled...
| /** | ||
| * Test utility InputStream implementation that generates random ASCII data when | ||
| * read, up to the size specified when constructed. | ||
| * NOTE: Adapted from |
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.
Question: Adapted from where?
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.
Will remove, it's unimportant. This was converted from v2 Java SDK utils though.
| * read, up to the size specified when constructed. | ||
| * NOTE: Adapted from | ||
| */ | ||
| public class RandomInputStream @JvmOverloads constructor( |
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.
Question: Why is @JvmOverloads necessary?
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.
It probably isn't, auto convert added it and I didn't question it (until now).
| val bytes = ByteArray(bytesToRead) | ||
| Random.nextBytes(bytes) | ||
| System.arraycopy(bytes, 0, b, off, bytesToRead) |
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.
Nit: This is less performant than simply writing to the final array:
Random.nextBytes(b, off, bytesToRead)| val bytes = ByteArray(1) | ||
| Random.nextBytes(bytes) | ||
| bytes[0].toInt() |
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.
Nit: This is less performant than simply getting a single byte via int conversion:
Random.nextInt().toByte()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.
Yup, stupid auto conversion. Be smarter.
| /** | ||
| * Creates, and fills, a temp file with a randomly generated name and specified size of random ASCII data. | ||
| * | ||
| * @param sizeInBytes The amount of random ASCII data, in bytes, for the new temp | ||
| * file. | ||
| * @throws IOException If any problems were encountered creating the new temp file. | ||
| */ | ||
| public constructor(sizeInBytes: Long) : this(UUID.randomUUID().toString(), sizeInBytes, false) | ||
|
|
||
| /** | ||
| * Creates, and fills, a temp file with the specified name and specified | ||
| * size of random ASCII data. | ||
| * | ||
| * @param filename | ||
| * The name for the new temporary file, within the Java temp | ||
| * directory as declared in the JRE's system properties. | ||
| * @param sizeInBytes | ||
| * The amount of random ASCII data, in bytes, for the new temp | ||
| * file. | ||
| * | ||
| * @throws IOException | ||
| * If any problems were encountered creating the new temp file. | ||
| */ | ||
| public constructor(filename: String, sizeInBytes: Int) : this(filename, sizeInBytes.toLong(), false) | ||
|
|
||
| /** | ||
| * Creates, and fills, a temp file with the specified name and specified | ||
| * size of random binary or character data. | ||
| * | ||
| * @param filename | ||
| * The name for the new temporary file, within the Java temp | ||
| * directory as declared in the JRE's system properties. | ||
| * @param sizeInBytes | ||
| * The amount of random ASCII data, in bytes, for the new temp | ||
| * file. | ||
| * @param binaryData Whether to fill the file with binary or character data. | ||
| * | ||
| * @throws IOException | ||
| * If any problems were encountered creating the new temp file. | ||
| */ | ||
| /** | ||
| * Creates, and fills, a temp file with the specified name and specified | ||
| * size of random ASCII data. | ||
| * | ||
| * @param filename | ||
| * The name for the new temporary file, within the Java temp | ||
| * directory as declared in the JRE's system properties. | ||
| * @param sizeInBytes | ||
| * The amount of random ASCII data, in bytes, for the new temp | ||
| * file. | ||
| * | ||
| * @throws IOException | ||
| * If any problems were encountered creating the new temp file. | ||
| */ | ||
| @JvmOverloads | ||
| public constructor(filename: String, sizeInBytes: Long, binaryData: Boolean = false) : super( | ||
| TEMP_DIR + separator + System.currentTimeMillis().toString() + "-" + filename | ||
| ) { | ||
| this.binaryData = binaryData | ||
| createFile(sizeInBytes) | ||
| } | ||
|
|
||
| public constructor(root: File?, filename: String?, sizeInBytes: Long) : super(root, filename) { | ||
| binaryData = false | ||
| createFile(sizeInBytes) | ||
| } |
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.
Comment: Seems like all these overloads could be replaced by a single constructor with default params.
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.
Yeah I'll take another look at what was converted and collapse the ones that make sense.
| val buffer = ByteArray(1024) | ||
| var bytesRead: Int | ||
| while (inputStream.read(buffer).also { bytesRead = it } > -1) { | ||
| bufferedOutputStream.write(buffer, 0, bytesRead) | ||
| } |
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.
Nit: Could be replaced by copyTo:
inputStream.copyTo(bufferedOutputStream)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.
Sure will update.
| public fun randomUncreatedFile(): File = | ||
| File(TEMP_DIR, UUID.randomUUID().toString()).also { it.deleteOnExit() } |
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.
Question: Unused?
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.
Yeah this entire file was copy paste, auto convert to Kotlin from Java (with very minor fixes/updates). We can probably delete though as Files.createTempFile(..) would serve same purpose I think.
| val contents = """ | ||
| Are you suggesting coconuts migrate? | ||
| Not at all, they could be carried. | ||
| What -- a swallow carrying a coconut? | ||
| It could grip it by the husk. | ||
| It's not a question of where he grips it! It's a simple question of weight ratios! A five ounce bird could not carry a 1 pound coconut. | ||
| Well, it doesn't matter. Will you go and tell your master that Arthur from the Court of Camelot is here. | ||
| Listen, in order to maintain air-speed velocity, a swallow needs to beat its wings 43 times times every second, right? | ||
| ... | ||
| It could be carried by an African swallow! | ||
| Oh yeah, an African swallow maybe, but not a European swallow. That's my point. | ||
| Oh, yeah, I agree with that. | ||
| """.trimIndent() |
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.
Correctness: This conflicts with the copyright header of the file.
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.
Touché...also no fun. Will update
| do { | ||
| val bucketExists = try { | ||
| client.headBucket { bucket = testBucket } | ||
| true | ||
| } catch (ex: NotFound) { | ||
| delay(300) | ||
| false | ||
| } | ||
| } while (!bucketExists) |
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.
Comment: Consider timing out after a while (e.g., 60 seconds) so this doesn't run forever.
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.
Yeah, ideally we would use waiters but of course we aren't there yet. I'll add a timeout for now.
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.
I guess that means "hurry up and finish waiters". Message received. 😉
| suspend fun getTestBucket(client: S3Client): String = getBucketWithPrefix(client, TEST_BUCKET_PREFIX) | ||
|
|
||
| suspend fun getBucketWithPrefix(client: S3Client, prefix: String): String { | ||
| var testBucket = client.listBuckets {} | ||
| .buckets | ||
| ?.mapNotNull { it.name } | ||
| ?.firstOrNull { it.startsWith(prefix) } |
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.
Comment: This pair of functions gets or creates a bucket but the only place they're used is in the @BeforeAll block of S3BucketOpsIntegrationTest. In that situation, all we really want is create since we'll delete afterwards. You could simplify this into just createTestBucket and skip searching for an existing bucket.
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.
Many of the utils were just adapted from the v2 Java test suite. I kept the behavior because it is a sort of self cleaning mechanism. If a test invocation crashes or otherwise fails to cleanup it will do so on the next run because it will re-use an existing bucket.
| /** | ||
| * Tests for bucket operations | ||
| */ | ||
| @TestInstance(TestInstance.Lifecycle.PER_CLASS) |
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.
question
for my understanding is this annotation property an optimization or necessary? if the latter why?
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.
It changes the default behavior to create a single instance for all of the test methods instead of creating a new one per test. I did this to only create the bucket once and re-use it for all of the tests.
See https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-instance-lifecycle for more info
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.
So to answer your question directly, probably more of an optimization.
|
|
||
| apply(from = rootProject.file("gradle/publish.gradle")) | ||
|
|
||
| if (project.file("e2eTest").exists()) { |
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.
question
what (if any) is the difference between putting tests in the tests sourceset vs this sourceset? Semantically of course the unit tests would go into one but I'm asking if there are any differences between the two?
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.
Yeah there are definitely differences. If we put these into the unit test sourceSet they would run with the rest of the (unit) tests of course which is not what we want. This allows us to separate out these kinds of tests as an independent compilation and setup test tasks dedicated to them.
Issue #
N/A
Description of changes
e2eTestsourceSet. To add e2e style tests to a service merely add the folder and start adding tests. These tests can be run like normal unit tests from Intellij or from command line with thee2eTesttask.Scope
By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.