-
Notifications
You must be signed in to change notification settings - Fork 16
docs(samples): add UpdateUserEventsJson implementation #388
Conversation
String invalidFilePath = "src/main/resources/user_events_some_invalid.json"; | ||
|
||
updateEventsTimestamp(filePath); | ||
updateEventsTimestamp(invalidFilePath); |
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.
Does the test for these already exist?
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.
There are no tests for classes which in 'setup' package.
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.
- These samples need tests added.
- I really dislike this pattern of relying the main to test. It's inconsistent with how the other java samples are tested, and showing both a valid and an invalid example just makes the example more confusing.
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.
Could you please clarify, what exactly issue with the tests you observe?
Currently, all the tests are relying on the pattern you recommended on past PR’s.
#303 (comment)
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 did not recommend using the main for testing. In fact, I explictly recommended against it: #303 (comment)
Here's example of how it's typically handled (calling the snippet directly): https://github.com/GoogleCloudPlatform/java-docs-samples/blob/e1ec7d8800f83db0bc7dd3b6f02cfa634802ec52/kms/src/main/java/kms/CreateKeyHsm.java#L41
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.
Do you mean to remove main method calls from unit tests? Just call methods directly?
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.
@sborisenkox Yes.
This lets you test for different conditions individually (one test for filepath
and one for invalidFilePath
) and is less confusing for users to navigate.
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.
- These samples need tests added.
- I really dislike this pattern of relying the main to test. It's inconsistent with how the other java samples are tested, and showing both a valid and an invalid example just makes the example more confusing.
- Tests for the setup package were added.
- Unit tests and some classes were refactored.
Please review.
String invalidFilePath = "src/main/resources/user_events_some_invalid.json"; | ||
|
||
updateEventsTimestamp(filePath); | ||
updateEventsTimestamp(invalidFilePath); |
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.
- These samples need tests added.
- I really dislike this pattern of relying the main to test. It's inconsistent with how the other java samples are tested, and showing both a valid and an invalid example just makes the example more confusing.
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.
Please take some time to review the Sample Style Guide. And look at some example snippets. Here's a good example of a snippet following the style guide:
String bucketName = System.getenv("EVENTS_BUCKET_NAME"); | ||
String gcsBucket = String.format("gs://%s", bucketName); | ||
String gcsErrorsBucket = String.format("%s/error", gcsBucket); | ||
String gcsUserEventsObject = "user_events.json"; | ||
// TO CHECK ERROR HANDLING USE THE JSON WITH INVALID USER EVENT: | ||
// gcsEventsObject = "user_events_some_invalid.json" | ||
|
||
ImportUserEventsRequest importEventsGcsRequest = | ||
getImportEventsGcsRequest(gcsUserEventsObject, gcsBucket, gcsErrorsBucket, defaultCatalog); | ||
importUserEventsFromGcs(importEventsGcsRequest); | ||
} |
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.
The main function should be example values only. See Method Structure in the Samples Style Guide.
It should look something like:
public static void main(String[] args) {
// TODO(developer): Replace these variables before running the sample.
String catalog = String.format(
"projects/%s/locations/global/catalogs/%s", "your-project-id" "your-catalog-name")
// Path to a file containing UserEvents to import in a GCS bucket
String gcsFile = String.format("gs://your-bucket-name/path/to/file.json")
importUserEventsFromGcs(catalog, gcsFile);
}
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.
Changed.
|
||
while (!operation.getDone()) { | ||
System.out.println("Please wait till operation is done."); | ||
Thread.sleep(30_000); |
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.
Please use the java.time package here.
Thread.sleep(30_000); | |
TimeUnit.SECONDS.sleep(30); |
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.
Changed.
OperationsClient operationsClient = serviceClient.getOperationsClient(); | ||
Operation operation = operationsClient.getOperation(operationName); | ||
|
||
while (!operation.getDone()) { |
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 would recommend adding a timeout of some form to this loop so it cannot continue indefinitely.
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.
Added.
System.out.printf("Operation result: %s%n", response); | ||
} | ||
} catch (InvalidArgumentException e) { | ||
try (UserEventServiceClient serviceClient = UserEventServiceClient.create()) { |
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.
Make sure to include the comment regarding client best practices.
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.
Done.
public static ImportUserEventsRequest getImportEventsGcsRequest( | ||
String gcsEventsObject, String gcsBucket, String gcsErrorsBucket, String defaultCatalog) { | ||
GcsSource gcsSource = | ||
GcsSource.newBuilder() | ||
.addInputUris(String.format("%s/%s", gcsBucket, gcsEventsObject)) | ||
.build(); | ||
|
||
UserEventInputConfig inputConfig = | ||
UserEventInputConfig.newBuilder().setGcsSource(gcsSource).build(); | ||
|
||
System.out.println("GRS source: " + gcsSource.getInputUrisList()); | ||
|
||
importUserEventsFromGcs(gcsEventsObject, defaultCatalog); | ||
ImportErrorsConfig errorsConfig = | ||
ImportErrorsConfig.newBuilder().setGcsPrefix(gcsErrorsBucket).build(); | ||
|
||
ImportUserEventsRequest importRequest = | ||
ImportUserEventsRequest.newBuilder() | ||
.setParent(defaultCatalog) | ||
.setInputConfig(inputConfig) | ||
.setErrorsConfig(errorsConfig) | ||
.build(); | ||
|
||
System.out.printf("Import user events from google cloud source request: %s%n", importRequest); | ||
|
||
return importRequest; |
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 doesn't need to be a seperate method - we should only be adding additional methods if it improve readability. See Class Structure.
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've changed some classes, but others should have methods calls to prepare snippet resources.
} | ||
} catch (BigQueryException e) { | ||
System.out.printf("Exception message: %s", e.getMessage()); | ||
} catch (InvalidArgumentException e) { |
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.
When can this "InvalidArgumentException" happen? Can we add a try/catch for this exception just where it's relevant?
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's relevant in that case when bucket has no specified file.
Also added PermissionDeniedException for case when env variable bucketName can't be read properly.
Timestamp currentDate = | ||
Timestamp.newBuilder() | ||
.setSeconds(Instant.now().getEpochSecond()) | ||
.setNanos(Instant.now().getNano()) | ||
.build(); |
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 doesn't need to be in main (it should be part of the sample).
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.
We don't need to create a new bucket every time when running the unit test.
In the code sample, bucket name contains timestamp.
In the test class, bucket has static name.
"Given GCS input path was not found. %n%s%n" | ||
+ "Please run CreateTestResources class to create resources.", |
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.
User's typically copy/paste these samples to run. If they need a specific resource, we should explain to them how to make it in a comment at the top of the snippet.
"Given GCS input path was not found. %n%s%n" | |
+ "Please run CreateTestResources class to create resources.", | |
"The specified GCS file does not exist. Please make sure to create one following the instructions at the top of this 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.
Explanation and all setup instructions will be described in a separate space.
Comment was changed.
|
||
private static final String BUCKET_NAME = | ||
String.format("%s_events_%s", PROJECT_ID, CURRENT_DATE.getSeconds()); | ||
|
||
public static void main(String... args) throws IOException { |
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.
these have to be String[]
to be proper main functions.
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.
Done.
// TO CHECK ERROR HANDLING USE THE JSON WITH INVALID USER EVENT: | ||
// gcsEventsObject = "user_events_some_invalid.json" |
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 should just be a separate test in your tests file. You can have one where you call a valid file (e.g.importUimportUserEventsFromGcs("your-catalog", "user-events.json
) and one where you call an invalid file (e.g.importUimportUserEventsFromGcs("your-catalog", "some-invalid-file.json
). You shouldn't be depending on someone to edit a comment out, because that means it's not being run the in the CI.
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.
Added.
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.
Can you please refactor this into smaller CLs? There are 68 changed files here and a diff of +- 2,000 lines. This is way too much to review in a single CL.
Thank you for opening a Pull Request! Before submitting your PR, there are a few things you can do to make sure it goes smoothly:
Fixes #<issue_number_goes_here> ☕️
If you write sample code, please follow the samples format.