Skip to content
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

UI: Upgrade to Ember 4.12 #22122

Merged
merged 28 commits into from Aug 1, 2023
Merged

UI: Upgrade to Ember 4.12 #22122

merged 28 commits into from Aug 1, 2023

Conversation

hashishaw
Copy link
Collaborator

@hashishaw hashishaw commented Jul 28, 2023

This PR upgrades from 4.4 to 4.12, the latest LTS.

Initially we were going to upgrade to 4.8, but we ran into many stable identifier issues in tests and in the app. After bumping to 4.12 instead (see #21955 for comments) the app and tests are more stable.

hashishaw and others added 19 commits July 28, 2023 12:36
Attempting to unload records after test teardown (as initiated in the cluster route deactivate hook) results in error like:
Promise rejected after "test name": Assertion Failed: Expected a stable identifier

reference: https://medium.com/@jenweber/help-my-ember-acceptance-tests-are-leaking-2e48a2e2dce5
- default serializer makes array values empty
- assign this.targets to self so that the array tracks updates
- willDestroy on component called after test unload, which destroys the store
- wrapped model unload call in try/catch so the error doesn't bork the test
* fixes store service unload method overrides

* bumps ember to 4.12

* removes unload method overrides in store service

* bumps ember test-helpers and qunit back down

* fixes memory leaks in tests when rolling back attributes in willDestroy hook

* removes unnecessary logouts from acceptance tests

* updates deprecation filter to also target 5.0 as well as 5.0.0 version strings

* removes model.destroy from unload-model-route mixin

* removes secret-engine and auth-method unloadAll from routes causing issues in tests

* removes mount-config serializer

* converts replication-mode service to native class and makes mode a tracked property -- fixes template not updating when switching between dr and performance replication routes

* updates code-mirror modifier to new api -- fixes issue with editor not installing on element

* fixes pki key issue rolling back attributes after destroyRecord has been called

* fixes enterprise-oidc-namespace test

* adds comment to mfa-form test regarding possible timer issues

* pins node version to 16

* fixes expected stable identifier issue in tests

* adds destroy checks to ObjectProxy in maybe-query-record macro

* fixes issues with v2 secrets

* revert concurrently for npm-run-all

* updates yarn lock

* fixes js lint errors

* fixes hbs lint errors

* fix dupe accessor on secret-engine model

* Move isV2 to getter on secret-edit

---------

Co-authored-by: Chelsea Shaw <cshaw@hashicorp.com>
@hashishaw hashishaw added the ui label Jul 28, 2023
@hashishaw hashishaw added this to the 1.15 milestone Jul 28, 2023
@github-actions github-actions bot added the hashicorp-contributed-pr If the PR is HashiCorp (i.e. not-community) contributed label Jul 28, 2023
model.rollbackAttributes();
}
this._super(...arguments);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Always call this._super(...) last in willDestroy otherwise we get errors in tests

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Database role tests were exiting early, so this was an attempt to stabilize those

@@ -10,10 +10,10 @@ export function initialize() {
registerDeprecationHandler((message, options, next) => {
// filter deprecations that are scheduled to be removed in a specific version
// when upgrading or addressing deprecation warnings be sure to update this or remove if not needed
if (options?.until !== '5.0.0') {
next(message, options);
if (options?.until.includes('5.0')) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

deprecations are returning 5.0 and 5.0.0

@@ -78,7 +78,7 @@
</div>
{{#if backend.accessor}}
<code class="has-text-grey is-size-8">
{{backend.accessor}}
{{if (eq backend.version 2) (concat "v2 " backend.accessor) backend.accessor}}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer conflating accessor with the version

@@ -3,7 +3,7 @@
"packages": [
{
"name": "ember-cli",
"version": "4.4.0",
"version": "4.12.1",
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

@@ -1,7 +1,6 @@
<div class="navigate-filter">
<div class="field" data-test-nav-input>
<p class="control has-icons-left">
{{! template-lint-disable no-down-event-binding }}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No longer a rule 🎉

@@ -45,7 +45,6 @@ export default class TtlPickerComponent extends Component {
@tracked recalculateSeconds = false;
@tracked time = ''; // if defaultValue is NOT set, then do not display a defaultValue.
@tracked unit = 's';
@tracked recalculateSeconds = false;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate attr

}
if (this._editor.getValue() !== this.args.named.content) {
this._editor.setValue(this.args.named.content);
modify(element, positionalArgs, namedArgs) {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codemirror API changed -- see commit for context

@@ -19,10 +18,6 @@ module('Acceptance | Enterprise | /access/namespaces', function (hooks) {
return authPage.login();
});

hooks.afterEach(function () {
Copy link
Collaborator Author

@hashishaw hashishaw Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

authPage.login logs out before each test, so logout after each is unnecessary.

});
hooks.afterEach(function () {
// Manually clear token after each so that future tests don't get into a weird state
this.auth.deleteCurrentToken();
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was a weird one. If I tried to visit logout in the afterEach hook, one of these tests would fail because it queried the MFA verification more than once. Rather than open that can of worms this fixes the test for now, but we should double-verify with smoke tests that the MFA flow is working as intended. In any case, even if the flow is making multiple requests that shouldn't break the flow

@@ -34,15 +33,11 @@ module('Acceptance | oidc-config clients and assignments', function (hooks) {
ENV['ember-cli-mirage'].handler = 'oidcConfig';
});

hooks.beforeEach(async function () {
this.store = await this.owner.lookup('service:store');
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this.owner.lookup isn't a promise

]);
const token = consoleComponent.lastTextOutput;
await logout.visit();
await navToConnection(backend, connection);
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Visiting the connection page directly was not re-querying the capabilities correctly. I was unable to replicate this behavior in the app, so navigating via the UI seems to resolve the test issue

@@ -682,7 +681,8 @@ module('Acceptance | secrets/secret/create, read, delete', function (hooks) {
await deleteEngine(enginePath, assert);
});

test('version 2: with metadata no read or list but with delete access and full access to the data endpoint', async function (assert) {
// TODO VAULT-16258: revisit when KV-V2 is engine
test.skip('version 2: with metadata no read or list but with delete access and full access to the data endpoint', async function (assert) {
Copy link
Collaborator Author

@hashishaw hashishaw Jul 31, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one is being all sorts of weird. But a use case to make sure we cover in the KV engine work.
I did test in the app and it seemed to work as intended

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this test helper so we can quickly make things happen in the app that we're not testing the workflow for exactly, but nonetheless need them to happen for the test scenario. I expect this to grow over time! If anyone has suggestions for clearer verbage please comment 🙏

@hashishaw hashishaw marked this pull request as ready for review July 31, 2023 14:44
@github-actions
Copy link

Build Results:
All builds succeeded! ✅

@github-actions
Copy link

CI Results:
All Go tests succeeded! ✅

@@ -219,6 +219,8 @@ export default Component.extend(DEFAULTS, {
};
})
);
// without unloading the records there will be an issue where all methods set to list when unauthenticated will appear for all namespaces
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this because of the upgrade? I thought since we sent the namespace as the header, the /sys/internal/ui/mounts requests only fires for that namespac

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, but we have to unload the store here or else that call will just append to the store we already have. This note is just to clarify what the below is doing, so that we can remove it later (unloadAll was causing issues throughout tests)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh I see - I thought the store cleared with the new request. Thanks for clarifying!

Copy link
Contributor

@hellobontempo hellobontempo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

some comments so far! (note to self, left off at 65/113 files)

@@ -7,6 +7,23 @@ import { computed } from '@ember/object';
import ObjectProxy from '@ember/object/proxy';
import PromiseProxyMixin from '@ember/object/promise-proxy-mixin';
import { resolve } from 'rsvp';
/**
* after upgrading to Ember 4.12 a secrets test was erroring with "Cannot create a new tag for `<model::capabilities:undefined>` after it has been destroyed"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this is an error I've also seen while developing - I wonder if the test was finally catching it now after the upgrade? Or do you think this behavior is just isolated to tests?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could be, but I thought in the app we saw an id instead of undefined 🤔 FWIW tests were failing with A record in a disconnected state cannot utilize the store. This typically means the record has been destroyed, most commonly by unloading it. when I ran the test suite reverting this change but keeping all others.
The good/bad news is that we aren't the only ones seeing this. But, it seems to be most problematic in tests but making a note here to test the application with varying capabilities to make sure workflows aren't broken with this change

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah yeah, that error is familiar too. Sounds good!

return !!this.nodes.findBy('sealed', false);
}),
get unsealed() {
return !!this.nodes.find((node) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.findBy is still an ember method, right? No need to change - just curious! 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just checked -- it is! It isn't an MDN Array method though, which is probably what I was thinking of

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep - it's a special ember function from what I remembered


//replication mode - will only ever be 'unsupported'
//otherwise the particular mode will have the relevant mode attr through replication-attributes
mode: attr('string'),
allReplicationDisabled: and('{dr,performance}.replicationDisabled'),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm so glad this syntax isn't a thing in octane 😅

replicationAttrs: computed('dr.mode', 'performance.mode', 'replicationMode', function () {
return !this.dr?.mode || !this.performance?.mode;
}
get replicationAttrs() {
const replicationMode = this.replicationMode;
return replicationMode ? get(this, replicationMode) : null;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this get be updated? or can it remain get()

Suggested change
return replicationMode ? get(this, replicationMode) : null;
return replicationMode ? this.replicationMode : null;

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that, and since replicationMode is a dynamic string get is the only way i got this to work. It would have to be something like this[replicationMode] which, in testing, didn't work. I also learned that get is the only way to get nested paths, so if something was at foo.bar.baz you could do get(foo, "bar.baz") but not foo["bar.baz"]

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay - thanks for explaining!

@@ -34,12 +34,13 @@ export default class MfaLoginEnforcementSerializer extends ApplicationSerializer
}
return payload;
}
serialize() {
serialize(snapshot) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does snapshot need to be passed in here? This is also something caught by the pki role serializer here

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

snapshot is used on line 41-42, because the serialized value json was empty for those arrays 😕 I can investigate this again, but I assumed when I made this change that something changed in the ember-data serializer. I'll check PKI as well, since there might not have been a test that caught that one

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh okay. For added context, I remember that when those values were serialized, the keys were removed all together so checking that the key existed on the json was sufficient, because if it didn't exist then it meant it was empty.

If the json value exists and is empty for those arrays now, then that means we can probably remove this code all together as it sounds like the problem may have been fixed on an ember data level ?!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohh interesting -- turns out the component was using addObject on the model attribute which is supposed to be an array, but using that method instead of setting it to something directly (model.thing = thing) doesn't trigger an update to the snapshot that gets passed into the serializer 😱 Looking at PKI, the component does set it directly, so I'm updating the MFA component to set it like that instead.

{{/if}}
</EmptyState>
{{/each-in}}
{{else}}{{#if this.noReadAccess}}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oof, I think this conditional arrangement is something that we improved when Angel updated the KV engine metadata read page

assert.strictEqual(currentURL(), `/vault/secrets/${backend}/list`, 'Cancel button links to list view');
});
}
test('database connection create and edit: vault-plugin-database-oracle', async function (assert) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👏

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😍

Copy link
Contributor

@zofskeez zofskeez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 🚀 🚢
LGTM. Nothing stands out from the review but I think the sooner we can get this merged for use in development the better to flush out any bugs that may still be lurking.

@hashishaw hashishaw merged commit 8731cee into main Aug 1, 2023
99 checks passed
@hashishaw hashishaw deleted the ui/VAULT-16197/upgrade-ember-4.12 branch August 1, 2023 19:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
hashicorp-contributed-pr If the PR is HashiCorp (i.e. not-community) contributed ui
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants