-
Notifications
You must be signed in to change notification settings - Fork 23
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
Add support for timestamped split registry endpoint #97
Conversation
<< platform |
Needs somebody from @Betterment/test_track_core to claim domain review Use the shovel operator to claim, e.g.:
|
@@ -15,7 +15,7 @@ def instance | |||
if faked? | |||
new(fake_instance_attributes(nil)) | |||
else | |||
get('/api/v2/split_registry') | |||
get("/api/v3/builds/#{TestTrack::BuildTimestamp}/split_registry") |
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 may be able to pass in the timestamp as an argument to get
. Though we don’t need url encoding since the timestamp shouldn’t have any funky characters, I think it’s a good practice.
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.
Seems like we're doing string interpolation in the other instances of get with args. Should we stick with that pattern or forge our own path?
elsif File.exist?(BUILD_TIMESTAMP_FILE_PATH) && File.readable?(BUILD_TIMESTAMP_FILE_PATH) && !File.zero?(BUILD_TIMESTAMP_FILE_PATH) | ||
TestTrack::BuildTimestamp = File.read(BUILD_TIMESTAMP_FILE_PATH) | ||
else | ||
raise Exception.new "Failed to read timestamp" |
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 could use more context. If the app fails to startup we should provide plenty of details on why and how to fix.
Something like: “TestTrack failed to load the required build timestamp. Ensure testtrack-cli build-timestamp is run and the timestamp file is present”
Something like that but better 😁
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.
Any reason we're raising a bare exception instead of just the text, which would result in a StandardError?
if Rails.env.test? || Rails.env.development? | ||
TestTrack::BuildTimestamp = Time.zone.now.iso8601 | ||
elsif File.exist?(BUILD_TIMESTAMP_FILE_PATH) && File.readable?(BUILD_TIMESTAMP_FILE_PATH) && !File.zero?(BUILD_TIMESTAMP_FILE_PATH) | ||
TestTrack::BuildTimestamp = File.read(BUILD_TIMESTAMP_FILE_PATH) |
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 think some basic validation of the file content is worthwhile, like is it in iso format. @jmileham does the iOS client do any validation?
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'm not sure, but agreed. Also, this camelization isn't conventional for ruby - it looks like a class. We should either have a property of TestTrack
, a la TestTrack.build_timestamp
, or it should be using constant case, i.e. TestTrack::BUILD_TIMESTAMP
. If we don't intend for it to be mutable, we should do that. Also, the timestamp file should probably be newline terminated, and if so, this should probably be chomping the results during its validation/normalization phase.
next if cli.skip_testtrack_cli? | ||
|
||
if cli.project_initialized? | ||
result = cli.call('generate_timestamp') |
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.
Hmm, the naming of this command and the rake task is inconsistent. I like the more explicit name of the rake task, so probably should change the name of this command to generate_build_timestamp
.
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 update the command in the cli?
@@ -31,3 +42,4 @@ end | |||
task 'db:schema:load' => ['test_track:schema:load'] | |||
task 'db:structure:load' => ['test_track:schema:load'] | |||
task 'db:migrate' => ['test_track:migrate'] | |||
task 'deploy:assets:precompile' => ['test_track:generate_build_timestamp'] |
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.
Would be nice to add a test for this since it’s now pretty critical to building the apps, not sure if we have any examples of testing rake tasks.
@@ -0,0 +1,9 @@ | |||
BUILD_TIMESTAMP_FILE_PATH = 'testtrack/build_timestamp'.freeze | |||
|
|||
if Rails.env.test? || Rails.env.development? |
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.
Getting some tests around this behavior would be great too. Not sure if you can test an initializer. But we could pull this logic into a function, test that and then just call that here
Tafn! This is great. Mostly comments about test coverage. Nice work! |
Needs somebody from @Betterment/test_track_core to claim domain review Use the shovel operator to claim, e.g.:
|
* constant name case * cli task name to match updated go cli * update cli version
removes from the initializer to write tests. Also relies on some assumptions to simplify the conditional logic.
* renames initialzier method to load_build_timestamp * vendorizes new version of cli * adds more error handling around the timestamp loading and reading * uses corerct assets precompile naming
nanda |
Needs somebody from @Betterment/test_track_core to claim domain review Use the shovel operator to claim, e.g.:
|
spec/test_track_spec.rb
Outdated
around { |example| Timecop.freeze(Time.zone.parse('2020-02-01')) { example.run } } | ||
|
||
context 'in a test environment' do | ||
it 'assigns BUILD_TIMESTAMP to now' do |
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 'assigns BUILD_TIMESTAMP to now' do | |
it 'assigns build_timestamp to now' do |
spec/test_track_spec.rb
Outdated
end | ||
|
||
context 'in a development environment' do | ||
it 'assigns BUILD_TIMESTAMP to now' do |
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 'assigns BUILD_TIMESTAMP to now' do | |
it 'assigns build_timestamp to now' do |
spec/test_track_spec.rb
Outdated
end | ||
|
||
context 'with an existing build_timestamp file' do | ||
it 'assigns BUILD_TIMESTAMP to file\'s contents' do |
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 'assigns BUILD_TIMESTAMP to file\'s contents' do | |
it 'assigns build_timestamp to file\'s contents' do |
spec/test_track_spec.rb
Outdated
|
||
before do | ||
allow(File).to receive(:exist?).and_return(file_readable) | ||
allow(File).to receive(:read).and_return("2020-02-01T00:00:00Z\n") |
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.
since you're freezing time on line 191 to the exact same time as what you're stubbed here, its a hard to be confident that we're actually reading from the file and not from frozen time
lib/test_track.rb
Outdated
elsif File.exist?(BUILD_TIMESTAMP_FILE_PATH) | ||
raise "TestTrack's build_timestamp is not formatted properly." unless BUILD_TIMESTAMP_REGEX.match?(_build_timestamp) | ||
|
||
@build_timestamp = _build_timestamp |
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.
very minor nit. you're reading the file twice. on this line and line 61, you could capture build_timestamp in a local var to avoid that
@@ -0,0 +1 @@ | |||
TestTrack.load_build_timestamp |
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 we need test_track
in the filename? may just load_build_timestamp
? since test_track is kinda implied
lib/test_track.rb
Outdated
@build_timestamp = _build_timestamp | ||
else | ||
raise 'TestTrack failed to load the required build timestamp. ' \ | ||
'Ensure `testtrack load_build_timestamp` is run and the build timestamp file is present.' |
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.
'Ensure `testtrack load_build_timestamp` is run and the build timestamp file is present.' | |
'Ensure `test_track:generate_build_timestamp` task is run and the build timestamp file is present.' |
lib/test_track.rb
Outdated
if Rails.env.test? || Rails.env.development? | ||
@build_timestamp = Time.zone.now.iso8601 | ||
elsif File.exist?(BUILD_TIMESTAMP_FILE_PATH) | ||
raise "TestTrack's build_timestamp is not formatted properly." unless BUILD_TIMESTAMP_REGEX.match?(_build_timestamp) |
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.
raise "TestTrack's build_timestamp is not formatted properly." unless BUILD_TIMESTAMP_REGEX.match?(_build_timestamp) | |
raise "./testtrack/build_timestamp is not a valid ISO 8601 timestamp, got '#{_build_timestamp}'" unless BUILD_TIMESTAMP_REGEX.match?(_build_timestamp) |
lib/test_track.rb
Outdated
end | ||
|
||
def build_timestamp | ||
@build_timestamp.presence || raise('build_timestamp is not defined. Ensure `load_build_timestamp` is run.') |
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.
@build_timestamp.presence || raise('build_timestamp is not defined. Ensure `load_build_timestamp` is run.') | |
@build_timestamp.presence || raise('build_timestamp is not defined because `load_build_timestamp` initializer was not run.') |
platformlgtm! looking great! dropped in a couple of minor suggestions around the exception messages. |
Needs somebody from @Betterment/test_track_core to claim domain review Use the shovel operator to claim, e.g.:
|
nanda |
Needs somebody from @Betterment/test_track_core to claim domain review Use the shovel operator to claim, e.g.:
|
lib/test_track.rb
Outdated
end | ||
|
||
def build_timestamp | ||
@build_timestamp.presence || raise('build_timestamp is not defined because `load_build_timestamp` initializer was not run.') |
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 wonder if this should note that it normally runs as part of assets:precompile
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.
(same comment for the error above)
lib/test_track.rb
Outdated
def load_build_timestamp # rubocop:disable Metrics/MethodLength | ||
if Rails.env.test? || Rails.env.development? | ||
@build_timestamp = Time.zone.now.iso8601 | ||
elsif File.exist?(BUILD_TIMESTAMP_FILE_PATH) |
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'm thinking we can maybe combine the error cases so we only have to raise
once (regardless of whether the file exists)
def load_build_timestamp
if Rails.env.test? || Rails.env.development?
@build_timestamp = Time.zone.now.iso8601
elsif _build_timestamp
unless BUILD_TIMESTAMP_REGEX.match?(timestamp)
raise "./testtrack/build_timestamp is not a valid ISO 8601 timestamp, got '#{timestamp}'"
end
@build_timestamp = _build_timestamp
else
raise '...'
end
end
attr_reader :build_timestamp
# ...
def _build_timestamp
File.read(BUILD_TIMESTAMP_FILE_PATH).chomp.presence if File.exist?(BUILD_TIMESTAMP_FILE_PATH)
end
Main thing there is that by calling .presence
sooner and sharing the raise
during the initializer code, we can make build_timestamp
an attr_reader
and read straight off the ivar.
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'm thinking this is a safe strategy because the gem itself defines the initializer and owns load_build_timestamp
, so unless we suspect that somehow folks are gonna skip initialization of the app?)
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.
(Alternatively, I sort of wonder if we could rename load_build_timestamp
to build_timestamp
-- have it fetch all the things internally, run all the checks, etc -- and then basically just pre-heat it from the initializer.)
<< domain LGTM - this looks totally correct to me. I don't want to block you from merging, but I did leave a pile o' structural suggestions, take them or leave them. (Also I'm thinking we could mention the |
Approved! 🌮 💥 💰 |
@@ -31,3 +39,4 @@ end | |||
task 'db:schema:load' => ['test_track:schema:load'] | |||
task 'db:structure:load' => ['test_track:schema:load'] | |||
task 'db:migrate' => ['test_track:migrate'] | |||
task 'assets:precompile' => ['test_track:generate_build_timestamp'] |
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.
going to try reordering the tasks and adding a flag to not run the initializers until this is done here
nanda |
Approved! ✨ 💥 🎯 |
@@ -0,0 +1 @@ | |||
TestTrack.load_build_timestamp unless ENV['SKIP_TIMESTAMP_INIT'] == '1' |
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.
TestTrack.load_build_timestamp unless ENV['SKIP_TIMESTAMP_INIT'] == '1' | |
TestTrack.load_build_timestamp unless ENV['SKIP_TESTTRACK_LOAD_BUILD_TIMESTAMP'] == '1' |
@@ -10,6 +10,19 @@ namespace :test_track do | |||
end | |||
end | |||
|
|||
desc 'Generates build timestamp for consuming applications to build versioned requests to split registry' |
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.
desc 'Generates build timestamp for consuming applications to build versioned requests to split registry' | |
desc 'Generates build timestamp for fetching point-in-time split registries' |
/domain @Betterment/test_track_core
/platform @aburgel @jmileham @effron @smudge
This PR adds the build timestamp to the rails client. We decided to push the timestamp generation and validation up to the build of the client so the app code can assume that the timestamp exists.