rustix_bl/
rustix_backend.rs

1use datastore;
2use datastore::UserGroup;
3use persistencer;
4use rustix_event_shop;
5use persistencer::LMDBPersistencer;
6use persistencer::Persistencer;
7use serde_json;
8use serde_yaml;
9use std;
10use std::fs::File;
11use std::io::prelude::*;
12use datastore::Datastore;
13
14#[derive(Debug)]
15pub struct RustixBackend {
16    pub datastore: datastore::Datastore,
17    pub persistencer: persistencer::FilePersister,
18}
19/*
20
21    CreateItem{itemname: String, price_cents: u32, category: Option<String>},
22    CreateUser{username: String},
23    DeleteItem{item_id: u32},
24    DeleteUser{user_id: u32},
25    MakeSimplePurchase{user_id: u32, item_id: u32, timestamp: u32},
26    CreateBill{timestamp: u32, user_ids: UserGroup, comment: String},
27*/
28
29pub trait WriteBackend {
30
31    fn apply(&mut self, event: &rustix_event_shop::BLEvents) -> bool;
32
33    fn snapshot(&mut self) -> Option<u64>;
34
35    fn load_snapshot(&mut self) -> Option<u64>;
36
37    fn create_bill(&mut self, timestamp_from: i64, timestamp_to: i64, user_ids: UserGroup, comment: String) -> bool;
38    fn create_item(&mut self, itemname: String, price_cents: u32, category: Option<String>)
39                   -> bool;
40    fn create_user(&mut self, username: String) -> bool;
41    fn update_item(&mut self, item_id: u32, itemname: String, price_cents: u32, category: Option<String>)
42                   -> bool;
43    fn update_user(&mut self, user_id: u32, username: String, is_billed: bool, is_highlighted: bool, external_user_id: Option<String>, is_sepa: bool) -> bool;
44
45    fn delete_user(&mut self, user_id: u32) -> bool;
46    fn delete_item(&mut self, item_id: u32) -> bool;
47
48    fn purchase(&mut self, user_id: u32, item_id: u32, millis_timestamp: i64) -> bool;
49
50    fn special_purchase(&mut self, user_id: u32, special_name: String, millis_timestamp: i64) -> bool;
51
52    fn cart_purchase(&mut self, user_id: u32, specials: Vec<String>, item_ids: Vec<u32>, millis_timestamp: i64) -> bool;
53
54    fn ffa_purchase(&mut self, ffa_id: u64, item_id: u32, millis_timestamp: i64) -> bool;
55
56    fn create_ffa(&mut self, allowed_categories : Vec<String>,
57                         allowed_drinks : Vec<u32>,
58                         allowed_number_total : u16,
59                         text_message : String,
60                         created_timestamp : i64,
61                         donor : u32) -> bool;
62
63    fn create_free_budget(&mut self, cents_worth_total : u64,
64                          text_message : String,
65                          created_timestamp : i64,
66                          donor : u32,
67                          recipient : u32) -> bool;
68
69    fn create_free_count(&mut self, allowed_categories : Vec<String>,
70                         allowed_drinks : Vec<u32>,
71                         allowed_number_total : u16,
72                         text_message : String,
73                         created_timestamp : i64,
74                         donor : u32,
75                         recipient : u32) -> bool;
76
77    fn undo_purchase(&mut self, unique_id: u64) -> bool;
78
79    fn reload(&mut self) -> Result<u64, persistencer::RustixError>;
80}
81
82
83impl WriteBackend for RustixBackend {
84    fn create_bill(&mut self, timestamp_from: i64, timestamp_to: i64, user_ids: UserGroup, comment: String) -> bool {
85        return self.persistencer.test_store_apply(
86            &rustix_event_shop::BLEvents::CreateBill {
87                timestamp_from: timestamp_from,
88                timestamp_to: timestamp_to,
89                user_ids: user_ids,
90                comment: comment,
91            },
92            &mut self.datastore,
93        );
94    }
95
96    fn create_item(
97        &mut self,
98        itemname: String,
99        price_cents: u32,
100        category: Option<String>,
101    ) -> bool {
102        return self.persistencer.test_store_apply(
103            &rustix_event_shop::BLEvents::CreateItem {
104                itemname: itemname,
105                price_cents: price_cents,
106                category: category,
107            },
108            &mut self.datastore,
109        );
110    }
111
112    fn create_user(&mut self, username: String) -> bool {
113        return self.persistencer.test_store_apply(
114            &rustix_event_shop::BLEvents::CreateUser { username: username },
115            &mut self.datastore,
116        );
117    }
118
119    fn delete_user(&mut self, user_id: u32) -> bool {
120        return self.persistencer.test_store_apply(
121            &rustix_event_shop::BLEvents::DeleteUser { user_id: user_id },
122            &mut self.datastore,
123        );
124    }
125
126    fn delete_item(&mut self, item_id: u32) -> bool {
127        return self.persistencer.test_store_apply(
128            &rustix_event_shop::BLEvents::DeleteItem { item_id: item_id },
129            &mut self.datastore,
130        );
131    }
132
133    fn purchase(&mut self, user_id: u32, item_id: u32, millis_timestamp: i64) -> bool {
134        return self.persistencer.test_store_apply(
135            &rustix_event_shop::BLEvents::MakeSimplePurchase {
136                user_id: user_id,
137                item_id: item_id,
138                timestamp: millis_timestamp,
139            },
140            &mut self.datastore,
141        );
142    }
143
144
145    fn reload(&mut self) -> Result<u64, persistencer::RustixError> {
146        let counter = self.load_snapshot();
147        return self.persistencer.reload_from_filepath(&mut self.datastore);
148    }
149    fn undo_purchase(&mut self, unique_id: u64) -> bool {
150        return self.persistencer.test_store_apply(
151            &rustix_event_shop::BLEvents::UndoPurchase {
152                unique_id: unique_id,
153            },
154            &mut self.datastore,
155        );
156    }
157    fn special_purchase(&mut self, user_id: u32, special_name: String, millis_timestamp: i64) -> bool {
158        return self.persistencer.test_store_apply(
159            &rustix_event_shop::BLEvents::MakeSpecialPurchase {
160                user_id: user_id,
161                special_name: special_name,
162                timestamp: millis_timestamp,
163            },
164            &mut self.datastore,
165        );
166    }
167
168    fn ffa_purchase(&mut self, ffa_id: u64, item_id: u32, millis_timestamp: i64) -> bool {
169        return self.persistencer.test_store_apply(
170            &rustix_event_shop::BLEvents::MakeFreeForAllPurchase {
171            ffa_id: ffa_id,
172                item_id: item_id,
173            timestamp: millis_timestamp,
174            },
175            &mut self.datastore,
176        );
177    }
178
179    fn create_ffa(&mut self, allowed_categories: Vec<String>, allowed_drinks: Vec<u32>, allowed_number_total: u16, text_message: String, created_timestamp: i64, donor: u32) -> bool {
180        return self.persistencer.test_store_apply(
181            &rustix_event_shop::BLEvents::CreateFreeForAll {
182                allowed_categories: allowed_categories,
183                allowed_drinks: allowed_drinks,
184                allowed_number_total: allowed_number_total,
185                text_message: text_message,
186                created_timestamp: created_timestamp,
187                donor: donor,
188            },
189            &mut self.datastore,
190        );
191    }
192
193    fn create_free_budget(&mut self, cents_worth_total: u64, text_message: String, created_timestamp: i64, donor: u32, recipient: u32) -> bool {
194
195        return self.persistencer.test_store_apply(
196            &rustix_event_shop::BLEvents::CreateFreeBudget {
197                cents_worth_total: cents_worth_total,
198                text_message: text_message,
199                created_timestamp: created_timestamp,
200                donor: donor,
201                recipient: recipient,
202            },
203            &mut self.datastore,
204        );
205    }
206
207    fn create_free_count(&mut self, allowed_categories: Vec<String>, allowed_drinks: Vec<u32>, allowed_number_total: u16, text_message: String, created_timestamp: i64, donor: u32, recipient: u32) -> bool {
208
209        return self.persistencer.test_store_apply(
210            &rustix_event_shop::BLEvents::CreateFreeCount {
211                allowed_categories: allowed_categories,
212                allowed_drinks: allowed_drinks,
213                allowed_number_total: allowed_number_total,
214                text_message: text_message,
215                created_timestamp: created_timestamp,
216                donor: donor,
217                recipient: recipient,
218            },
219            &mut self.datastore,
220        );
221    }
222    fn cart_purchase(&mut self, user_id: u32, specials: Vec<String>, item_ids: Vec<u32>, millis_timestamp: i64) -> bool {
223        return self.persistencer.test_store_apply(
224            &rustix_event_shop::BLEvents::MakeShoppingCartPurchase {
225                user_id: user_id,
226                specials: specials,
227                item_ids: item_ids,
228                timestamp: millis_timestamp,
229            },
230            &mut self.datastore,
231        );
232    }
233    fn update_item(&mut self, item_id: u32, itemname: String, price_cents: u32, category: Option<String>) -> bool {
234        return self.persistencer.test_store_apply(
235            &rustix_event_shop::BLEvents::UpdateItem {
236                item_id: item_id,
237                itemname: itemname,
238                price_cents: price_cents,
239                category: category,
240            },
241            &mut self.datastore,
242        );
243    }
244
245    fn update_user(&mut self, user_id: u32, username: String, is_billed: bool, is_highlighted: bool, external_user_id: Option<String>, is_sepa: bool) -> bool {
246        return self.persistencer.test_store_apply(
247            &rustix_event_shop::BLEvents::UpdateUser {
248                user_id: user_id,
249                username: username,
250                is_billed: is_billed,
251                is_highlighted: is_highlighted,
252                external_user_id: external_user_id,
253                is_sepa: is_sepa,
254            },
255            &mut self.datastore,
256        );
257    }
258    fn apply(&mut self, event: &rustix_event_shop::BLEvents) -> bool {
259        return self.persistencer.test_store_apply(event, &mut self.datastore);
260    }
261
262    fn snapshot(&mut self) -> Option<u64> {
263        //only if persistence layer
264        if !self.persistencer.config.use_persistence {
265            println!("snapshot() called, but not using persistence");
266            return None;
267        }
268
269        //take path of dir: <path>/snapshot.yaml
270        let filepath = self.persistencer.config.persistence_file_path.to_owned() + "/snapshot.yaml";
271        println!("snapshot() called, with file = {}", &filepath);
272
273        //println!("datastore = {:?}", &self.datastore);
274
275        //take current state and turn it into json
276        match serde_yaml::to_string(&self.datastore) {
277            Ok(json) => {
278
279                println!("snapshot() called, writing json");
280                //write to file
281                let mut file_res = std::fs::File::create(filepath);
282                match file_res {
283                    Ok(mut file) => {
284                        let res = file.write_all(&json.into_bytes());
285                        match res {
286                            Ok(e) => {
287                                //if successful, return version of aggregate
288                                println!("Success on snapshot()");
289                                return Some(self.datastore.version);
290                            },
291                            Err(e) => {
292                                println!("Eror writing file on snapshot(): {:?}", e);
293                                return None
294                            },
295                        }
296                    },
297                    Err(e) => {
298                        println!("Error opening file on snapshot(): {:?}", e);
299                        return None
300                    },
301                }
302            },
303            //if failure, return None
304            Err(e) => {
305                println!("Error creating json on snapshot(): {:?}", e);
306                return None
307            },
308        }
309    }
310    fn load_snapshot(&mut self) -> Option<u64> {
311        //only if using persistence
312        if !self.persistencer.config.use_persistence {
313            return None;
314        }
315
316        //take <persistence_path>/snapshot.yaml and load it
317        let filepath = self.persistencer.config.persistence_file_path.to_owned() + "/snapshot.yaml";
318
319        let mut file_raw= File::open(filepath);
320        if file_raw.is_err() {
321            return None;
322        }
323        let mut file = file_raw.unwrap();
324        let mut contents: String = String::new();
325        if file.read_to_string(&mut contents).is_err() {
326            return None
327        }
328
329        //extract datastore from json
330        let ds_raw = serde_yaml::from_str(&contents);
331        if ds_raw.is_err() {
332            return None;
333        }
334        let ds: Datastore = ds_raw.unwrap();
335
336        //write datastore to backend
337        let version: u64 = ds.version;
338        self.datastore = ds;
339
340        //if successful, return counter / version
341        return Some(version);
342    }
343}
344
345
346//TODO: write full test suite in here, testing without file persistencer
347
348
349#[cfg(test)]
350mod tests {
351    use rustix_event_shop;
352    use rustix_event_shop::BLEvents;
353    use serde_json;
354    use rustix_backend::RustixBackend;
355    use std;
356    use datastore;
357    use persistencer;
358    use config;
359    use std::collections::HashSet;
360    use datastore::UserGroup::AllUsers;
361    use suffix_rs::KDTree;
362    use datastore::*;
363    use datastore::PurchaseFunctions;
364    use datastore::DatastoreQueries;
365    use rustix_backend::WriteBackend;
366    use rustix_event_shop::BLEvents::SetPriceForSpecial;
367
368    fn build_test_backend() -> RustixBackend {
369        let config = config::StaticConfig::default();
370        return RustixBackend {
371            datastore: datastore::Datastore::default(),
372            persistencer: persistencer::FilePersister::new(config).unwrap(),
373        };
374    }
375
376    #[test]
377    fn simple_create_user_on_backend() {
378        let mut backend = build_test_backend();
379        backend.create_user("klaus".to_string());
380        println!("{:?}", backend);
381        assert_eq!(backend.datastore.users.len(), 1);
382        assert_eq!(backend.datastore.user_id_counter, 1);
383        assert_eq!(
384            backend.datastore.users.get(&0).unwrap().username,
385            "klaus".to_string()
386        );
387    }
388
389    #[test]
390    fn simple_create_item_on_backend() {
391        let mut backend = build_test_backend();
392        backend.create_item("beer".to_string(), 95, Some("Alcohol".to_string()));
393        backend.create_item("soda".to_string(), 75, None);
394        assert_eq!(backend.datastore.items.len(), 2);
395        assert_eq!(backend.datastore.item_id_counter, 2);
396        assert_eq!(
397            backend.datastore.items.get(&0).unwrap().name,
398            "beer".to_string()
399        );
400        assert_eq!(
401            backend.datastore.items.get(&1).unwrap().name,
402            "soda".to_string()
403        );
404        assert_eq!(
405            backend
406                .datastore
407                .items
408                .get(&0)
409                .unwrap()
410                .category
411                .clone()
412                .unwrap(),
413            "Alcohol".to_string()
414        );
415        assert_eq!(backend.datastore.items.get(&1).unwrap().cost_cents, 75);
416        assert_eq!(backend.datastore.categories.len(), 1);
417    }
418
419    #[test]
420    fn simple_delete_item() {
421        let mut backend = build_test_backend();
422        backend.create_item("beer".to_string(), 95, Some("Alcohol".to_string()));
423        backend.create_item("soda".to_string(), 75, None);
424        assert_eq!(backend.datastore.items.len(), 2);
425        assert_eq!(backend.datastore.item_id_counter, 2);
426        assert_eq!(
427            backend.datastore.items.get(&0).unwrap().name,
428            "beer".to_string()
429        );
430        assert_eq!(
431            backend.datastore.items.get(&1).unwrap().name,
432            "soda".to_string()
433        );
434        assert_eq!(
435            backend
436                .datastore
437                .items
438                .get(&0)
439                .unwrap()
440                .category
441                .clone()
442                .unwrap(),
443            "Alcohol".to_string()
444        );
445        assert_eq!(backend.datastore.items.get(&1).unwrap().cost_cents, 75);
446        assert_eq!(backend.datastore.categories.len(), 1);
447        backend.delete_item(1);
448        assert_eq!(backend.datastore.items.len(), 2);
449        assert_eq!(backend.datastore.item_id_counter, 2);
450        assert_eq!(
451            backend.datastore.items.get(&0).unwrap().name,
452            "beer".to_string()
453        );
454        assert_eq!(
455            backend
456                .datastore
457                .items
458                .get(&0)
459                .unwrap()
460                .category
461                .clone()
462                .unwrap(),
463            "Alcohol".to_string()
464        );
465        assert_eq!(backend.datastore.categories.len(), 1);
466    }
467
468
469    #[test]
470    fn simple_delete_user() {
471        let mut backend = build_test_backend();
472        backend.create_user("klaus".to_string());
473        assert_eq!(backend.datastore.users.len(), 1);
474        assert_eq!(backend.datastore.user_id_counter, 1);
475        assert_eq!(
476            backend.datastore.users.get(&0).unwrap().username,
477            "klaus".to_string()
478        );
479        backend.delete_user(0);
480        assert_eq!(backend.datastore.users.len(), 1);
481        assert_eq!(backend.datastore.user_id_counter, 1);
482    }
483
484
485    #[test]
486    fn simple_purchase() {
487        let mut backend = build_test_backend();
488        backend.persistencer.config.users_in_top_users = 1usize;
489
490        //create two users
491        backend.create_user("klaus".to_string());
492        backend.create_user("dieter".to_string());
493
494        //create one item
495        backend.create_item("beer".to_string(), 135u32, Some("Alcoholics".to_string()));
496
497        //make first purchase by A
498
499        println!(
500            "Beginning simple purchase test with datastore={:?}",
501            backend.datastore
502        );
503        assert_eq!(backend.purchase(0, 0, 12345678i64), false);
504        assert_eq!(backend.datastore.purchases.len(), 1);
505        assert_eq!(backend.datastore.top_users.len(), 1);
506        assert_eq!(backend.datastore.top_users.get(&0).unwrap(), &0u32);
507
508        //make second purchase by B
509
510        assert_eq!(backend.purchase(1, 0, 12345888i64), false);
511        assert_eq!(backend.datastore.purchases.len(), 2);
512        assert_eq!(backend.datastore.top_users.len(), 1);
513        assert_eq!(backend.datastore.top_users.get(&0).unwrap(), &0u32);
514
515        //make third purchase by B
516        backend.purchase(1, 0, 12347878i64);
517
518        //should now be A > B and all data should be correct
519        assert_eq!(backend.datastore.purchases.len(), 3);
520        assert_eq!(backend.datastore.top_users.len(), 1);
521
522        println!(
523            "Ending simple purchase test with datastore={:?}",
524            backend.datastore
525        );
526        assert_eq!(backend.datastore.top_users.get(&1).unwrap(), &1u32);
527        assert_eq!(
528            backend
529                .datastore
530                .top_drinks_per_user
531                .get(&0)
532                .unwrap()
533                .get(&0u32)
534                .unwrap(),
535            &0u32
536        );
537        assert_eq!(
538            backend
539                .datastore
540                .top_drinks_per_user
541                .get(&1)
542                .unwrap()
543                .get(&0u32)
544                .unwrap(),
545            &0u32
546        );
547
548
549        println!("Datastore before search: {:?}", backend.datastore);
550
551        //get purchases
552        assert_eq!(backend.datastore.get_purchase(1).unwrap().get_item_id(), &0u32);
553        assert_eq!(backend.datastore.get_purchase(1).unwrap().get_user_id(), &0u32);
554        assert_eq!(backend.datastore.get_purchase(1).unwrap().get_unique_id(), 1u64);
555        assert_eq!(backend.datastore.get_purchase(2).unwrap().get_item_id(), &0u32);
556        assert_eq!(backend.datastore.get_purchase(2).unwrap().get_user_id(), &1u32);
557        assert_eq!(backend.datastore.get_purchase(2).unwrap().get_unique_id(), 2u64);
558        assert_eq!(backend.datastore.get_purchase(3).unwrap().get_item_id(), &0u32);
559        assert_eq!(backend.datastore.get_purchase(3).unwrap().get_user_id(), &1u32);
560        assert_eq!(backend.datastore.get_purchase(3).unwrap().get_unique_id(), 3u64);
561
562        assert_eq!(backend.datastore.get_purchase(0).is_none(), true);
563
564        assert_eq!(backend.datastore.get_purchase(4).is_none(), true);
565
566
567        //test all user query
568        let two_user = backend.datastore.users_searchhit_ids("");
569        let one_user = backend.datastore.users_searchhit_ids("klau");
570        let zero_user = backend.datastore.users_searchhit_ids("lisa");
571
572        assert_eq!(two_user.len(), 2);
573        assert_eq!(one_user.len(), 1);
574        assert_eq!(zero_user.len(), 0);
575
576        //test all item query
577        let all_item = backend.datastore.items_searchhit_ids("");
578        let one_item = backend.datastore.items_searchhit_ids("beer");
579        let zero_item = backend.datastore.items_searchhit_ids("cola");
580
581        assert_eq!(one_item.len(), 1);
582        assert_eq!(all_item.len(), 1);
583        assert_eq!(zero_item.len(), 0);
584
585        //test top user query
586        let top_two_user = backend.datastore.top_user_ids(2);
587        let top_three_user = backend.datastore.top_user_ids(3);
588        let top_one_user = backend.datastore.top_user_ids(1);
589        let top_zero_user = backend.datastore.top_user_ids(0);
590
591        assert_eq!(top_two_user.len(), 2);
592        assert_eq!(top_three_user.len(), 2);
593        assert_eq!(top_one_user.len(), 1);
594        assert_eq!(top_zero_user.len(), 0);
595
596
597        //test top item query
598
599        let top_items = backend.datastore.top_item_ids(0, 2);
600        let no_top_items = backend.datastore.top_item_ids(0, 0);
601
602        assert_eq!(top_items.len(), 1);
603        assert_eq!(no_top_items.len(), 0);
604
605        //test purchase query personal (by user with id = 1)
606        let lowest_time_point = 1000i64;
607        let low_mid_time_point =    12345680i64;
608        let mid_time_point =        12345880i64;
609        let high_mid_time_poin =    12345890i64;
610        let highest_time_point =    12447878i64;
611
612        let all_personal_purchases = backend.datastore.personal_log_filtered(1, lowest_time_point, highest_time_point);
613        let one_personal_purchases = backend.datastore.personal_log_filtered(1, low_mid_time_point, high_mid_time_poin);
614        let zero_personal_purchases = backend.datastore.personal_log_filtered(1, low_mid_time_point, mid_time_point);
615
616        assert_eq!(all_personal_purchases.len(), 2);
617        assert_eq!(one_personal_purchases.len(), 1);
618        assert_eq!(zero_personal_purchases.len(), 0);
619
620
621        //test purchase query global
622        let all_global_purchases = backend.datastore.global_log_filtered(lowest_time_point, highest_time_point);
623        let one_global_purchases = backend.datastore.global_log_filtered(low_mid_time_point, high_mid_time_poin);
624        let zero_global_purchases = backend.datastore.global_log_filtered(low_mid_time_point, mid_time_point);
625
626
627        assert_eq!(all_global_purchases.len(), 3);
628        assert_eq!(one_global_purchases.len(), 1);
629        assert_eq!(zero_global_purchases.len(), 0);
630
631    }
632
633    #[test]
634    fn simple_create_bill() {
635        let mut backend = build_test_backend();
636        //create two users, create three items, make 1 user purchase 2 items but not the third
637        backend.create_user("user a".to_string());
638        backend.create_user("user b".to_string());
639        backend.create_user("donated_to_user".to_string());
640        backend.create_item("item 1".to_string(), 45, None);
641        backend.create_item("item 2".to_string(), 55, Some("category a".to_string()));
642        backend.create_item("item 3".to_string(), 75, Some("category b".to_string()));
643
644
645        {
646            let a = backend.datastore.users_suffix_tree.search("user");
647            let b = backend.datastore.users_suffix_tree.search("user a");
648            let c = backend.datastore.users_suffix_tree.search("");
649
650            assert_eq!(a.len(), 3);
651            assert_eq!(b.len(), 1);
652            assert_eq!(c.len(), 3);
653        }
654
655
656        backend.purchase(0, 0, 10);
657        backend.purchase(0, 1, 20);
658        backend.purchase(0, 0, 30);
659
660        backend.create_free_budget(1000, "some budget message".to_string(), 31, 0, 2);
661        backend.create_free_count(vec!["category a".to_string()], vec![0], 2, "some count message".to_string(), 32, 0, 2);
662
663        backend.purchase(2, 0, 33);
664        backend.purchase(2, 1, 34);
665
666
667
668        backend.create_ffa(Vec::new(), vec![0, 1], 2, "my ffa message".to_string(), 35, 0);
669        let ffa_id : u64 = backend.datastore.open_ffa[0].get_id();
670
671
672        backend.purchase(2, 0, 36);
673        backend.purchase(2, 0, 37);
674        backend.purchase(2, 1, 38);
675        backend.purchase(2, 0, 39);
676
677
678        backend.special_purchase(0, "some special".to_string(), 40);
679
680        assert_eq!(backend.ffa_purchase(ffa_id, 0, 50), true);
681        assert_eq!(backend.ffa_purchase(ffa_id, 0, 60), true);
682
683
684        assert_eq!(backend.ffa_purchase(ffa_id, 1, 70), false);
685
686        let user_key = (0, (&backend).datastore.users.get(&0).unwrap().username.to_string());
687        let user_1_key = (1, (&backend).datastore.users.get(&1).unwrap().username.to_string());
688        let item_0_key = (0, (&backend).datastore.items.get(&0).unwrap().name.to_string());
689        let item_1_key = (1, (&backend).datastore.items.get(&1).unwrap().name.to_string());
690        println!("Testoutput = {:?}\nwith user key = {:?}\nand item key = {:?}", backend.datastore, &user_key, &item_0_key);
691        assert!(backend
692            .datastore
693            .balance_cost_per_user
694            .get(&user_key)
695            .is_some());
696        assert_eq!(
697            backend
698                .datastore
699                .balance_cost_per_user
700                .get(&user_key)
701                .unwrap()
702                .get(&item_0_key)
703                .unwrap(),
704            &180u32
705        );
706
707        assert_eq!(
708            backend
709                .datastore
710                .balance_cost_per_user
711                .get(&user_key)
712                .unwrap()
713                .get(&item_1_key)
714                .unwrap(),
715            &55u32
716        );
717
718
719        assert_eq!(
720            backend.datastore.balance_cost_per_user.get(&user_1_key).is_none(),
721            true
722        );
723
724
725        //create a bill
726        backend.create_bill(0, 100, AllUsers, "remark of bill".to_string());
727
728
729        assert_eq!(
730            backend.datastore.bills[0].bill_state.is_finalized(),
731            false
732        );
733        assert_eq!(
734            backend.datastore.purchases.len(),
735            12
736        );
737
738        backend.update_user(0, "user a".to_string(), true, false, Some("user_id_external_a".to_string()), true);
739        backend.update_user(1, "user b".to_string(), false, false, None, false);
740        backend.update_user(2, "updated_donated_to_user".to_string(), true, false, Some("user_2_external_id".to_string()), true);
741
742
743        assert_eq!(
744            backend.datastore.open_freebies.get(&2).unwrap().len(),
745            2
746        );
747
748        assert_eq!(backend.apply(&BLEvents::FinalizeBill{timestamp_from: 0, timestamp_to: 100}) , false);
749
750        assert_eq!(backend.apply(&SetPriceForSpecial {
751            unique_id: 10,
752            price: 15,
753        }), true);
754
755        assert_eq!(backend.apply(&BLEvents::FinalizeBill{timestamp_from: 0, timestamp_to: 100}) , true);
756
757
758        assert_eq!(
759            backend.datastore.bills[0].bill_state.is_finalized(),
760            true
761        );
762        assert_eq!(
763            backend.datastore.purchases.len(),
764            0
765        );
766        assert_eq!(
767            backend.datastore.bills[0].finalized_data.all_items.len(),
768            2
769        );
770        assert_eq!(
771            backend.datastore.bills[0].finalized_data.all_users.len(),
772            2
773        );
774        assert_eq!(
775            backend.datastore.bills[0].finalized_data.user_consumption.get(&0).unwrap().per_day.get(&0).unwrap().personally_consumed.len(),
776            2
777        );
778        assert_eq!(
779            backend.datastore.bills[0].finalized_data.user_consumption.get(&0).unwrap().per_day.get(&0).unwrap().ffa_giveouts.len(),
780            1
781        );
782        assert_eq!(
783            backend.datastore.bills[0].finalized_data.user_consumption.get(&0).unwrap().per_day.get(&0).unwrap().giveouts_to_user_id.len(),
784            1
785        );
786        assert_eq!(
787            backend.datastore.bills[0].finalized_data.user_consumption.get(&0).unwrap().per_day.get(&0).unwrap().giveouts_to_user_id.get(&2).unwrap().budget_given,
788            190
789        );
790        assert_eq!(
791            backend.datastore.bills[0].finalized_data.user_consumption.get(&2).unwrap().per_day.get(&0).unwrap().giveouts_to_user_id.get(&0).unwrap().budget_gotten,
792            190
793        );
794        assert_eq!(
795            backend.datastore.bills[0].finalized_data.user_consumption.get(&2).unwrap().per_day.get(&0).unwrap().giveouts_to_user_id.get(&0).unwrap().budget_given,
796            0
797        );
798        assert_eq!(
799            backend.datastore.bills[0].finalized_data.user_consumption.get(&0).unwrap().per_day.get(&0).unwrap().giveouts_to_user_id.get(&2).unwrap().budget_gotten,
800            0
801        );
802        assert_eq!(
803            backend.datastore.bills[0].finalized_data.user_consumption.get(&0).unwrap().per_day.get(&0).unwrap().giveouts_to_user_id.get(&2).unwrap().count_giveouts_used.len(),
804            2
805        );
806        assert_eq!(
807            backend.datastore.bills[0].finalized_data.user_consumption.get(&0).unwrap().per_day.get(&0).unwrap().specials_consumed.len(),
808            1
809        );
810
811
812        assert_eq!(
813            backend.datastore.open_freebies.get(&2).unwrap().len(),
814            1
815        );
816
817
818
819        //control that current balance is down to zero for all users
820//
821//        assert_eq!(
822//            backend.datastore.balance_cost_per_user.get(&user_key).is_none(),
823//            true
824//        );
825//
826//
827//        assert_eq!(
828//            backend.datastore.balance_cost_per_user.get(&user_1_key).is_none(),
829//            true
830//        );
831
832
833        //control that bill contains correct data
834//        assert_eq!(
835//            backend
836//                .datastore
837//                .bills
838//                .get(0)
839//                .unwrap()
840//                .sum_of_cost_hash_map
841//                .get(&user_key)
842//                .unwrap()
843//                .get(&item_0_key)
844//                .unwrap(),
845//            &90u32
846//        );
847//        assert_eq!(
848//            backend
849//                .datastore
850//                .bills
851//                .get(0)
852//                .unwrap()
853//                .sum_of_cost_hash_map
854//                .get(&user_1_key)
855//                .unwrap()
856//                .is_empty(),
857//            true
858//        );
859//        assert_eq!(
860//            backend
861//                .datastore
862//                .bills
863//                .get(0)
864//                .unwrap()
865//                .count_hash_map
866//                .get(&user_key)
867//                .unwrap()
868//                .get(&item_1_key)
869//                .unwrap(),
870//            &1u32
871//        );
872//        assert_eq!(
873//            backend
874//                .datastore
875//                .bills
876//                .get(0)
877//                .unwrap()
878//                .count_hash_map
879//                .get(&user_key)
880//                .unwrap()
881//                .get(&item_1_key)
882//                .unwrap(),
883//            &1u32
884//        );
885//        assert_eq!(
886//            backend.datastore.bills.get(0).unwrap().timestamp,
887//            100i64
888//        );
889//        assert_eq!(backend.datastore.bills.get(0).unwrap().users, AllUsers);
890//        assert_eq!(
891//            backend.datastore.bills.get(0).unwrap().comment,
892//            "remark of bill".to_string()
893//        );
894
895
896        //add another purchase and assert that bill didn't change
897        backend.purchase(0, 0, 110);
898        backend.purchase(1, 2, 120);
899        backend.purchase(1, 0, 130);
900
901//        assert_eq!(
902//            backend
903//                .datastore
904//                .bills
905//                .get(0)
906//                .unwrap()
907//                .sum_of_cost_hash_map
908//                .get(&user_key)
909//                .unwrap()
910//                .get(&item_0_key)
911//                .unwrap(),
912//            &90u32
913//        );
914//        assert_eq!(
915//            backend
916//                .datastore
917//                .bills
918//                .get(0)
919//                .unwrap()
920//                .sum_of_cost_hash_map
921//                .get(&user_1_key)
922//                .unwrap()
923//                .is_empty(),
924//            true
925//        );
926//        assert_eq!(
927//            backend
928//                .datastore
929//                .bills
930//                .get(0)
931//                .unwrap()
932//                .count_hash_map
933//                .get(&user_key)
934//                .unwrap()
935//                .get(&item_1_key)
936//                .unwrap(),
937//            &1u32
938//        );
939//        assert_eq!(
940//            backend
941//                .datastore
942//                .bills
943//                .get(0)
944//                .unwrap()
945//                .count_hash_map
946//                .get(&user_key)
947//                .unwrap()
948//                .get(&item_1_key)
949//                .unwrap(),
950//            &1u32
951//        );
952//        assert_eq!(
953//            backend.datastore.bills.get(0).unwrap().timestamp,
954//            100i64
955//        );
956//        assert_eq!(backend.datastore.bills.get(0).unwrap().users, AllUsers);
957//        assert_eq!(
958//            backend.datastore.bills.get(0).unwrap().comment,
959//            "remark of bill".to_string()
960//        );
961    }
962
963
964
965
966
967    #[test]
968    fn simple_ffa_purchase() {
969        let mut backend = build_test_backend();
970        let ts1 = 1i64;
971        let ts2 = 2i64;
972
973        backend.create_user("klaus".to_string());
974        backend.create_item("item 1".to_string(), 45, None);
975        backend.create_ffa(Vec::new(), vec![0], 1, "some textmessage".to_string(), ts1, 0);
976
977        println!("open_ffa = {:?}\nused_up = {:?}", backend.datastore.open_ffa, backend.datastore.used_up_freebies);
978        //freeby should be on new vec
979        assert_eq!(backend.datastore.open_ffa.len(), 1);
980        assert_eq!(backend.datastore.open_freebies.len(), 0);
981        assert_eq!(backend.datastore.used_up_freebies.len(), 0);
982        assert_eq!(backend.datastore.open_ffa[0].get_id(), 1);
983        backend.ffa_purchase(1, 0, ts2);
984
985        assert_eq!(backend.datastore.purchases.len(), 1);
986        assert_eq!(backend.datastore.purchase_count, 1);
987
988        println!("open_ffa = {:?}\nused_up = {:?}", backend.datastore.open_ffa, backend.datastore.used_up_freebies);
989        //freeby should be on used up stack and not the new one
990        assert_eq!(backend.datastore.open_ffa.len(), 0);
991        assert_eq!(backend.datastore.open_freebies.len(), 0);
992        assert_eq!(backend.datastore.used_up_freebies.len(), 1);
993
994
995    }
996
997
998}