Problem detect observable OnCompleted in RX - web-services

I have problem with detect onComplited action in RX.
I'm loading data to ListBox from web service.
Basic situation is working great: - "Complited item" is on bottom
App.ViewModel.LoadData();
IObservable<WebServiceClass.ItemGetValues> observable = App.ViewModel.Items
.ToObservable(Scheduler.NewThread);
var items = new ObservableCollection<WebServiceClass.ItemGetValues>();
ListBox1.ItemsSource = items;
observable.ObserveOnDispatcher().Subscribe(
item => { items.Add( new WebServiceClass.ItemGetValues(item.nazwa, item.skrot, item.id) ); },
() => { items.Add( new WebServiceClass.ItemGetValues("Complited", "", "") ); }
);
But when I call web service for each item with code below the "Complited item" is added at first
App.ViewModel.LoadData();
IObservable<WebServiceClass.ItemGetValues> observable = App.ViewModel.Items
.ToObservable(Scheduler.NewThread);
var items = new ObservableCollection<WebServiceClass.ItemGetValues>();
ListBox1.ItemsSource = items;
observable.ObserveOnDispatcher().Subscribe
(item =>
{
//items.Add(item);
var request = Observable.FromAsyncPattern<string, string>(client.BeginGetLastValue, client.EndGetLastValue);
request(item.skrot).ObserveOnDispatcher().Subscribe(
(it) =>
{
Func<string, WebServiceClass.ItemGetValues> deserializeFirst = r =>
((List<WebServiceClass.ItemGetValues>)JsonConvert
.DeserializeObject(r,
typeof(List<WebServiceClass.ItemGetValues>)))
.First();
item.zm_dzienna = deserializeFirst(it).zm_dzienna;
items.Add(item);
}
);
},
() => { items.Add(new WebServiceClass.ItemGetValues("Complited", "Complited", "0")); }
);
How can I properly detect onComplited action?
Solution
Problem with nullReference exception in deserializeFirst func.
App.ViewModel.LoadData();
IObservable<WebServiceClass.ItemGetValues> observable = App.ViewModel.Items
.ToObservable(Scheduler.NewThread);
var items = new ObservableCollection<WebServiceClass.ItemGetValues>();
ListBox1.ItemsSource = items;
var request = Observable.FromAsyncPattern<string, string>(client.BeginGetLastValue, client.EndGetLastValue);
observable.SelectMany(
item => request(item.skrot).Select(it => {
Func<string, WebServiceClass.ItemGetValues> deserializeFirst = r =>
((List<WebServiceClass.ItemGetValues>)JsonConvert
.DeserializeObject(r,
typeof(List<WebServiceClass.ItemGetValues>)))
.First();
item.zm_dzienna = deserializeFirst(it).zm_dzienna;
return item;
})
).SubscribeOnDispatcher().Subscribe(
result => { Dispatcher.BeginInvoke(delegate { items.Add(result); }); },
() => { Dispatcher.BeginInvoke(delegate { items.Add(new WebServiceClass.ItemGetValues("c","c","c")); }); }
);
Best regards,
Ɓukasz

You need to pull the inner query into to Rx sequence, not run it from your subscription. Doing so gives you the power of Rx, of composability and testability. And gets you the results you want.
This is a start towards what is needed.
Func<string, WebServiceClass.ItemGetValues> deserializeFirst = r =>
((List<WebServiceClass.ItemGetValues>)JsonConvert
.DeserializeObject(r,typeof(List<WebServiceClass.ItemGetValues>)))
.First();
var request = Observable.FromAsyncPattern<string, string>(client.BeginGetLastValue,
client.EndGetLastValue);
observable
.SelectMany((item) => request(item.skrot))
.Select((it) => item.zm_dzienna = deserializeFirst(it).zm_dzienna)
.ObserveOnDispatcher()
.Subscribe(
item => items.Add(item),
() => items.Add(new WebServiceClass.ItemGetValues("Complited", "Complited", "0")));

Related

LINQ query throw an exception when to get a count of a type

I write a test to filter a list.
Service.cs
public async Task<GetAllParticipantsDto> ListAllAsync(GetAllParticipantsRequest queryModel)
{
int count = 0;
var participantsList = participantRepository.AsNoTracking()
.Include(a => a.ParticipantConnections)!.ThenInclude(a => a.Connection)
.Include(a => a.ParticipantApplicationUsers)!.ThenInclude(a => a.ApplicationUser)
.AsQueryable();
if (participantsList != null && !String.IsNullOrEmpty(queryModel.RelatedConnection))
{
participantsList = participantsList.Where(x => x.ParticipantConnections.Any(y => y.Connection.FirstName.ToLower().Contains(queryModel.RelatedConnection.ToLower())) || x.ParticipantConnections.Any(y => y.Connection.LastName.ToLower().Contains(queryModel.RelatedConnection.ToLower())) ||
x.ParticipantConnections.Any(y => (y.Connection.FirstName.ToLower()+ y.Connection.LastName.ToLower()).Contains(queryModel.RelatedConnection.ToLower())) || x.ParticipantConnections.Any(y => (y.Connection.FirstName.ToLower() +" "+ y.Connection.LastName.ToLower()).Contains(queryModel.RelatedConnection.ToLower())));
count = participantsList.Count(); // NullReferenceException Exception thrown in this line
}
}
unit test
public async void ListAllAsync_ShouldReturn_FilterByBy_RelatedConnection()
{
var query = new GetAllParticipantsRequest()
{ // others null
RelatedConnection = "Alice Doe, Bob Doe"
};
Func<DSMP.ApplicationCore.Entities.Participant, bool> exists = n => true; // prepare Func outside of Setup
//1 - create a List<T> with test items
var participantList = ParticipantMockData.ListAllAsyncEntity();
//2 - build mock by extension
var mock = participantList.AsQueryable().BuildMock();
//3 - setup the mock as Queryable for Moq
_participantRepository.Setup(x => x.AsNoTracking(false)).Returns(mock);
var sut = new ParticipantService(
_participantRepository.Object, _participantSupportNeed.Object, _participantConnection.Object, _participantDisability.Object, _participantMedicalCondition.Object, _supportNeed.Object, _disability.Object, _medicalCondition.Object, _participantApplicationUser.Object, _appLogger.Object);
// Act
var result = await sut.ListAllAsync(query);
// Assert
}
The exception
Message - System.NullReferenceException: 'Object reference not set to an instance of an object.'
StackTrace -
" at System.Linq.Enumerable.Any[TSource](IEnumerable1 source, Func2 predicate)\r\n at System.Linq.Enumerable.WhereListIterator1.MoveNext()\r\n at System.Collections.Generic.LargeArrayBuilder1.AddRange(IEnumerable1 items)\r\n at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable1 source)\r\n at System.Linq.Enumerable.ToArray[TSource](IEnumerable1 source)\r\n at System.Linq.SystemCore_EnumerableDebugView1.get_Items()"
I could not find why this error occur.
Can any one help me?

Is it possible to mock the HttpContext for a HubCallerContext?

I am attempting to mock out my SignalR hub for some unit tests. I am running into an issue on my Hubs OnConnectedAsync() call due to using a header to auto join a group if it exists. My issue is lying with the fact that the HubCallerContext.GetHttpContext() method is an extension method and cant be mocked. I dunno if there is a work around to this and I cant seem to find any similarly posted question about this.
OnConnectedAsync() Segment
Context.GetHttpContext().Request.Headers.TryGetValue(SignalRHeaders.GroupHeader, out StringValues header);
if (header.Any())
{
await Groups.AddToGroupAsync(Context.ConnectionId, SignalRConstants.Group);
}
Base Test Class
public DefaultHubBaseTest()
{
var memberId = Guid.NewGuid().ToString();
var orgId = Guid.NewGuid().ToString();
MockClients = new Mock<IHubCallerClients>();
MockClientProxy = new Mock<IClientProxy>();
MockClients.Setup(clients => clients.Group(It.IsAny<string>()))
.Returns(MockClientProxy.Object);
MockGroups = new Mock<IGroupManager>();
MockGroups.Setup(x => x.AddToGroupAsync(It.IsAny<string>(), It.IsAny<string>(), default(CancellationToken))).Returns(Task.CompletedTask);
MockGroups.Setup(x => x.RemoveFromGroupAsync(It.IsAny<string>(), It.IsAny<string>(), default(CancellationToken))).Returns(Task.CompletedTask);
Mock<HttpRequest> MockRequest = new Mock<HttpRequest>();
MockRequest.Setup(x => x.Headers).Returns(new HeaderDictionary()
{
{ SignalRHeaders.GroupHeader, orgId },
{ SignalRHeaders.GroupAdminHeader, "t" },
});
Mock<HttpContext> MockHttpContext = new Mock<HttpContext>();
MockHttpContext.Setup(x => x.Request).Returns(MockRequest.Object);
MockContext = new Mock<HubCallerContext>();
MockContext.Setup(x => x.ConnectionId).Returns("1");
MockContext.Setup(x => x.User.Claims).Returns(new List<Claim>() { new Claim(SignalRConstants.AzureAuthOID, memberId) });
MockContext.Setup(x => x.GetHttpContext()).Returns(MockHttpContext.Object);
DefaultHub = new DefaultHub()
{
Context = MockContext.Object,
Groups = MockGroups.Object,
Clients = MockClients.Object,
};
}
If anyone could help me with this, I would greatly appreciate it. Thanks!

Is there a way to get "Product Type" inside product.tpl? - Prestashop 1.6

I'm using PS 1.6.1.16 and I'm wondering if there is a way to display "additional" or "different" content on product.tpl if the product type is "Virtual" (set in BO).
Additionally, is there a way to create a category page for all these "Virtual" products?
Thanks in advance.
In tpl condition is :
{if $product->is_virtual} IS VIRTUAL PRODUCT {else} NO VIRTUAL PRODUCT {/if}
To have a dedicated page is different, here is an example of product override to put in ROOT/override/controllers/front/ProductController.php which allows you to load a new TPL for virtual products. It is therefore necessary in the theme to add a product_virtual.tpl file
<?php
class ProductController extends ProductControllerCore
{
public function initContent()
{
parent::initContent();
if (!$this->errors) {
if (Pack::isPack((int)$this->product->id) && !Pack::isInStock((int)$this->product->id)) {
$this->product->quantity = 0;
}
$this->product->description = $this->transformDescriptionWithImg($this->product->description);
// Assign to the template the id of the virtual product. "0" if the product is not downloadable.
$this->context->smarty->assign('virtual', ProductDownload::getIdFromIdProduct((int)$this->product->id));
$this->context->smarty->assign('customizationFormTarget', Tools::safeOutput(urldecode($_SERVER['REQUEST_URI'])));
if (Tools::isSubmit('submitCustomizedDatas')) {
// If cart has not been saved, we need to do it so that customization fields can have an id_cart
// We check that the cookie exists first to avoid ghost carts
if (!$this->context->cart->id && isset($_COOKIE[$this->context->cookie->getName()])) {
$this->context->cart->add();
$this->context->cookie->id_cart = (int)$this->context->cart->id;
}
$this->pictureUpload();
$this->textRecord();
$this->formTargetFormat();
} elseif (Tools::getIsset('deletePicture') && !$this->context->cart->deleteCustomizationToProduct($this->product->id, Tools::getValue('deletePicture'))) {
$this->errors[] = Tools::displayError('An error occurred while deleting the selected picture.');
}
$pictures = array();
$text_fields = array();
if ($this->product->customizable) {
$files = $this->context->cart->getProductCustomization($this->product->id, Product::CUSTOMIZE_FILE, true);
foreach ($files as $file) {
$pictures['pictures_'.$this->product->id.'_'.$file['index']] = $file['value'];
}
$texts = $this->context->cart->getProductCustomization($this->product->id, Product::CUSTOMIZE_TEXTFIELD, true);
foreach ($texts as $text_field) {
$text_fields['textFields_'.$this->product->id.'_'.$text_field['index']] = str_replace('<br />', "\n", $text_field['value']);
}
}
$this->context->smarty->assign(array(
'pictures' => $pictures,
'textFields' => $text_fields));
$this->product->customization_required = false;
$customization_fields = $this->product->customizable ? $this->product->getCustomizationFields($this->context->language->id) : false;
if (is_array($customization_fields)) {
foreach ($customization_fields as $customization_field) {
if ($this->product->customization_required = $customization_field['required']) {
break;
}
}
}
// Assign template vars related to the category + execute hooks related to the category
$this->assignCategory();
// Assign template vars related to the price and tax
$this->assignPriceAndTax();
// Assign template vars related to the images
$this->assignImages();
// Assign attribute groups to the template
$this->assignAttributesGroups();
// Assign attributes combinations to the template
$this->assignAttributesCombinations();
// Pack management
$pack_items = Pack::isPack($this->product->id) ? Pack::getItemTable($this->product->id, $this->context->language->id, true) : array();
$this->context->smarty->assign('packItems', $pack_items);
$this->context->smarty->assign('packs', Pack::getPacksTable($this->product->id, $this->context->language->id, true, 1));
if (isset($this->category->id) && $this->category->id) {
$return_link = Tools::safeOutput($this->context->link->getCategoryLink($this->category));
} else {
$return_link = 'javascript: history.back();';
}
$accessories = $this->product->getAccessories($this->context->language->id);
if ($this->product->cache_is_pack || count($accessories)) {
$this->context->controller->addCSS(_THEME_CSS_DIR_.'product_list.css');
}
if ($this->product->customizable) {
$customization_datas = $this->context->cart->getProductCustomization($this->product->id, null, true);
}
$this->context->smarty->assign(array(
'stock_management' => Configuration::get('PS_STOCK_MANAGEMENT'),
'customizationFields' => $customization_fields,
'id_customization' => empty($customization_datas) ? null : $customization_datas[0]['id_customization'],
'accessories' => $accessories,
'return_link' => $return_link,
'product' => $this->product,
'product_manufacturer' => new Manufacturer((int)$this->product->id_manufacturer, $this->context->language->id),
'token' => Tools::getToken(false),
'features' => $this->product->getFrontFeatures($this->context->language->id),
'attachments' => (($this->product->cache_has_attachments) ? $this->product->getAttachments($this->context->language->id) : array()),
'allow_oosp' => $this->product->isAvailableWhenOutOfStock((int)$this->product->out_of_stock),
'last_qties' => (int)Configuration::get('PS_LAST_QTIES'),
'HOOK_EXTRA_LEFT' => Hook::exec('displayLeftColumnProduct'),
'HOOK_EXTRA_RIGHT' => Hook::exec('displayRightColumnProduct'),
'HOOK_PRODUCT_OOS' => Hook::exec('actionProductOutOfStock', array('product' => $this->product)),
'HOOK_PRODUCT_ACTIONS' => Hook::exec('displayProductButtons', array('product' => $this->product)),
'HOOK_PRODUCT_TAB' => Hook::exec('displayProductTab', array('product' => $this->product)),
'HOOK_PRODUCT_TAB_CONTENT' => Hook::exec('displayProductTabContent', array('product' => $this->product)),
'HOOK_PRODUCT_CONTENT' => Hook::exec('displayProductContent', array('product' => $this->product)),
'display_qties' => (int)Configuration::get('PS_DISPLAY_QTIES'),
'display_ht' => !Tax::excludeTaxeOption(),
'jqZoomEnabled' => Configuration::get('PS_DISPLAY_JQZOOM'),
'ENT_NOQUOTES' => ENT_NOQUOTES,
'outOfStockAllowed' => (int)Configuration::get('PS_ORDER_OUT_OF_STOCK'),
'errors' => $this->errors,
'body_classes' => array(
$this->php_self.'-'.$this->product->id,
$this->php_self.'-'.$this->product->link_rewrite,
'category-'.(isset($this->category) ? $this->category->id : ''),
'category-'.(isset($this->category) ? $this->category->getFieldByLang('link_rewrite') : '')
),
'display_discount_price' => Configuration::get('PS_DISPLAY_DISCOUNT_PRICE'),
));
}
if (ProductDownload::getIdFromIdProduct((int)$this->product->id) == 0)
$this->setTemplate(_PS_THEME_DIR_.'product.tpl');
else
$this->setTemplate(_PS_THEME_DIR_.'product_virtual.tpl');
}
}

Shorting list by name - Angular 5 + Firebase

I have created a service where I get all the elements of my database:
Service
getElements() {
return (this.eleList= this.firebase.list("elements"));
}
Component
eleList: Element[];
getBets() {
return this.databaseService
.getElements()
.snapshotChanges()
.subscribe(item => {
this.eleList= [];
item.forEach(element => {
let x = element.payload.toJSON();
x["$key"] = element.key;
this.eleList.push(x as Element);
});
});
}
With these two methods what I do is to store all my elements in this.eleList.
I would like to create a new method, named filterByName(name), where I would update this.eleList to an array which contains only the ones that contain namein the object, for example, this.eleList[1].name
I do not know if Firebase provides a way to short it, or I need to use Javascript/Typescript for it.
Firebase takes full advantage of the observables and async pipes.
You should take advantage of that :
eleList$ = new Subject();
getElements() {
this.this.firebase.list("elements")
.pipe(take(1))
.subscribe(list => this.eleList$.next(list));
}
getBets() {
this.databaseService
.getElements()
.snapshotChanges()
.pipe(
map(item => items.map(element => ({
...element.payload.toJSON(),
'$key': element.key
})))
)
.subscribe(elements => this.eleList$.next(list));
}
Now for a sorted list :
sortedList$ = this.eleList$.pipe(
map(elements => elements.filter(element => !!element.name))
);

Unit tests - entity framework

I use NUnitAdapter. I have unit test for my update method:
[Test]
public void UpdateBuisness()
{
var buis = new Buisness()
{
Name = "a",
Id = 4,
Enabled = true
};
_buisnessRepository.Insert(buis);
buis.Name = "b";
_buisnessRepository.Update(buis);
Assert.AreEqual(buis.Name, _buisnesses.Last().Name);
}
Update method:
public void Update(Buisness entity)
{
_context.Entry(entity).State = EntityState.Modified;
}
And I get error:
This is weird, because for my co-workers all works.
My mock:
var mockBuisnessesDbSet = new Mock<DbSet<Buisness>>();
mockBuisnessesDbSet.As<IQueryable<Buisness>>().Setup(m => m.Provider)
.Returns(new TestDbAsyncQueryProvider<Buisness>(_buisnesses.Provider));
mockBuisnessesDbSet.As<IQueryable<Buisness>>().Setup(m => m.Expression).Returns(_buisnesses.Expression);
mockBuisnessesDbSet.As<IQueryable<Buisness>>().Setup(m => m.ElementType).Returns(_buisnesses.ElementType);
mockBuisnessesDbSet.As<IDbAsyncEnumerable<Buisness>>()
.Setup(m => m.GetAsyncEnumerator())
.Returns(new TestDbAsyncEnumerator<Buisness>(_buisnesses.GetEnumerator()));
mockBuisnessesDbSet.As<IQueryable<Buisness>>().Setup(m => m.GetEnumerator()).Returns(_buisnesses.GetEnumerator());
mockBuisnessesDbSet.Setup(x => x.Add(It.IsAny<Buisness>()))
.Callback((Buisness bis) => _buisnesses = _buisnesses.Concat(new[] { bis }));
mockBuisnessesDbSet.Setup(x => x.Remove(It.IsAny<Buisness>()))
.Callback((Buisness bis) => _buisnesses = _buisnesses.Where(x => x.Id != bis.Id));
_mockContex = new Mock<ApplicationDbContext>() { CallBase = true };
_mockContex.Setup(x => x.Buisnesses).Returns(mockBuisnessesDbSet.Object);
_buisnessRepository = new BuisnessRepository(_mockContex.Object);
I have no idea what is causing this.