[CORD-2827] Fixed unauthorized error handling
Change-Id: I6ddef7f869c17db4d8479f23f6e8734f6002d8fc
diff --git a/src/app/datasources/helpers/model-discoverer.service.ts b/src/app/datasources/helpers/model-discoverer.service.ts
index fca593c..3ee5a15 100644
--- a/src/app/datasources/helpers/model-discoverer.service.ts
+++ b/src/app/datasources/helpers/model-discoverer.service.ts
@@ -44,7 +44,7 @@
// Service
export interface IXosModelDiscovererService {
- discover(): ng.IPromise<boolean>;
+ discover(): ng.IPromise<string>;
getApiUrlFromModel(model: IXosModel): string;
areModelsLoaded(): boolean;
}
@@ -127,28 +127,42 @@
return this.$q.resolve('true');
})
.catch(err => {
- this.$log.error(`[XosModelDiscovererService] Model ${model.name} NOT stored`, err);
+ this.$log.warn(`[XosModelDiscovererService] Model ${model.name} NOT stored`, err);
+ const isAuthError = this.AuthService.isAuthError(err);
+ if (isAuthError) {
+ this.$log.warn(`[XosModelDiscovererService] User is not authentincated`);
+ return this.$q.reject(err);
+ }
return this.$q.resolve('false');
});
pArray.push(p);
});
+
+
this.$q.all(pArray)
.then((res) => {
- // the Model Loader promise won't ever be reject, in case it will be resolve with value false,
+ // the ModelLoader promise won't ever be reject, in case it will be resolve with value false,
// that's because we want to wait anyway for all the models to be loaded
if (res.indexOf('false') > -1) {
return d.resolve(false);
}
d.resolve(true);
+ this.modelsLoaded = true;
})
.catch((e) => {
- this.$log.error(`[XosModelDiscovererService]`, e);
- d.resolve(false);
+ this.XosModelStore.clean(); // reset all the observable otherwise they'll store login errors
+ this.$log.warn(`[XosModelDiscovererService]`, e);
+ // the ModelLoader promise will be rejected in case of authentication error
+ d.reject(e);
})
.finally(() => {
this.progressBar.complete();
- this.modelsLoaded = true;
});
+ })
+ .catch(err => {
+ this.progressBar.complete();
+ this.$log.error(`[XosModelDiscovererService] Cannot load model defs`, err);
+ return d.resolve('chameleon');
});
return d.promise;
}
@@ -249,16 +263,17 @@
}
private cacheModelEntries(model: IXosModel): ng.IPromise<IXosModel> {
+
const d = this.$q.defer();
const apiUrl = this.getApiUrlFromModel(model);
this.XosModelStore.query(model.name, apiUrl)
+ .skip(1) // NOTE observables returns as first an empty array, so skip it
.subscribe(
() => {
return d.resolve(model);
},
err => {
- this.AuthService.handleUnauthenticatedRequest(err);
return d.reject(err);
}
);
diff --git a/src/app/datasources/helpers/model.discoverer.service.spec.ts b/src/app/datasources/helpers/model.discoverer.service.spec.ts
index a6e6340..5deb444 100644
--- a/src/app/datasources/helpers/model.discoverer.service.spec.ts
+++ b/src/app/datasources/helpers/model.discoverer.service.spec.ts
@@ -73,9 +73,13 @@
};
const MockXosModelStore = {
query: jasmine.createSpy('modelStore.query')
- .and.callFake(() => {
+ .and.callFake((model) => {
const list = new BehaviorSubject([]);
list.next([]);
+ window.setTimeout(() => {
+ // NOTE force the Observable to call next two times, as cacheModelEntries is not caching the first result (since it's generated)
+ list.next([]);
+ }, 100);
return list.asObservable();
})
};
@@ -165,6 +169,22 @@
expect(service['getParentStateFromModel']({name: 'Tenant', app: 'services.vsg'})).toBe('xos.vsg');
});
+ it('should add an item to navigation', () => {
+ service['addNavItem']({name: 'Tenant', app: 'services.vsg'});
+ expect(MockXosNavigationService.add).toHaveBeenCalledWith({
+ label: 'Tenants',
+ state: 'xos.vsg.tenant',
+ parent: 'xos.vsg'
+ });
+
+ service['addNavItem']({name: 'Tenant', verbose_name: 'Verbose', app: 'services.vsg'});
+ expect(MockXosNavigationService.add).toHaveBeenCalledWith({
+ label: 'Verboses',
+ state: 'xos.vsg.tenant',
+ parent: 'xos.vsg'
+ });
+ });
+
it('should add a new service entry in the system', () => {
service['addService']({name: 'Tenant', app: 'services.vsg'});
expect(MockXosRuntimeStates.addState).toHaveBeenCalledWith('xos.vsg', {
@@ -226,22 +246,6 @@
scope.$apply();
});
- it('should add an item to navigation', () => {
- service['addNavItem']({name: 'Tenant', app: 'services.vsg'});
- expect(MockXosNavigationService.add).toHaveBeenCalledWith({
- label: 'Tenants',
- state: 'xos.vsg.tenant',
- parent: 'xos.vsg'
- });
-
- service['addNavItem']({name: 'Tenant', verbose_name: 'Verbose', app: 'services.vsg'});
- expect(MockXosNavigationService.add).toHaveBeenCalledWith({
- label: 'Verboses',
- state: 'xos.vsg.tenant',
- parent: 'xos.vsg'
- });
- });
-
it('should cache a model', () => {
service['cacheModelEntries']({name: 'Tenant', app: 'services.vsg'});
expect(MockXosModelStore.query).toHaveBeenCalledWith('Tenant', '/vsg/tenants');
@@ -276,7 +280,7 @@
service.discover()
.then((res) => {
expect(MockProgressBar.start).toHaveBeenCalled();
- expect(MockXosModelDefs.get).toHaveBeenCalled(); // FIXME replace correct spy
+ expect(MockXosModelDefs.get).toHaveBeenCalled();
expect(service['cacheModelEntries'].calls.count()).toBe(2);
expect(service['addState'].calls.count()).toBe(2);
expect(service['addNavItem'].calls.count()).toBe(2);
@@ -287,6 +291,10 @@
done();
});
scope.$apply();
+ window.setTimeout(() => {
+ // resolve promises after the observable.next as been called twice (cacheModelEntries requires it)
+ scope.$apply();
+ }, 101);
});
});
});