apify_client/
lib.rs

1#[macro_use]
2extern crate query_params;
3#[macro_use]
4extern crate serde_json;
5
6pub mod client;
7pub mod key_value_stores;
8pub mod datasets;
9pub mod request;
10pub mod utils;
11pub mod generic_types;
12
13// These are integration tests that call Apify APIs
14// They require an API token in test/test_token.txt file as plain string
15// TODO: Cleanup if tests crash in the middle
16#[cfg(test)]
17mod test {
18    use super::client::{ApifyClient, IdOrName, ApifyApiError, ApifyClientError};
19    use super::datasets::{Dataset};
20    use super::generic_types::{NoContent, PaginationList};
21    use serde::{Serialize, Deserialize};
22
23    // Simple await macro for tests
24    macro_rules! await_test {
25        ($e:expr) => {
26            tokio_test::block_on($e)
27        };
28    }
29    #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
30    struct Item {
31        field1: f64,
32        field2: f64,
33    }
34    fn get_test_items() -> Vec<Item> {
35        vec![Item { field1: 1., field2: 2. }, Item { field1: 3., field2: 4. }]
36    }
37
38    // You must have token in test/test_token.txt file as plain string
39    fn create_client () -> ApifyClient {
40        let path = std::env::current_dir().unwrap();
41        println!("The current directory is {}", path.display());
42        let token = std::fs::read_to_string("test/test_token.txt");
43        println!("{:?}", token);
44        let my_client = ApifyClient::new(token.ok());
45        my_client
46    }    
47
48    // Helper functions for sending the actual requests
49    // Needed because we need to clean up after each test
50    fn create_dataset (client: &ApifyClient, name: &str) -> Dataset {
51        let dataset = await_test!(client.create_dataset(name).send()).unwrap();
52        dataset
53    }
54
55    fn update_dataset (client: &ApifyClient, id_or_name: &IdOrName, name: &str) -> Dataset {
56        let dataset = await_test!(client.update_dataset(id_or_name, name).send()).unwrap();
57        dataset
58    }
59
60    fn delete_dataset (client: &ApifyClient, id_or_name: &IdOrName) -> NoContent {
61        let no_content = await_test!(client.delete_dataset(id_or_name).send()).unwrap();
62        no_content
63    }
64
65    fn get_dataset (client: &ApifyClient, id_or_name: &IdOrName) -> Result<Dataset, ApifyClientError> {
66        let maybe_dataset = await_test!(client.get_dataset(id_or_name).send());
67        maybe_dataset
68    }
69
70    fn put_items (client: &ApifyClient, id_or_name: &IdOrName, items: Vec<Item>) -> Result<NoContent, ApifyClientError> {
71        let put_result = await_test!(client.put_items(id_or_name, &items).send());
72        put_result
73    }
74
75
76    fn get_items (client: &ApifyClient, id_or_name: IdOrName) -> Result<PaginationList<Item>, ApifyClientError> {
77        let maybe_pagination_list = await_test!(client.get_items(id_or_name).send());
78        maybe_pagination_list
79    }
80
81    fn get_items_raw_csv (client: &ApifyClient, id_or_name: IdOrName) -> Result<String, ApifyClientError> {
82        let maybe_string = await_test!(client.get_items_raw(id_or_name).format(crate::datasets::Format::Csv).send());
83        maybe_string
84    }
85
86    // This is done as one mega test to limit number of API calls when cleaning
87    // but perhaps there is a better way
88    #[test]
89    fn create_update_get_and_delete_dataset () {
90        let client = create_client();
91        let name = "RUST-TEST-CREATE";
92
93        let dataset = create_dataset(&client, name);
94        assert_eq!(dataset.name.unwrap(), name);
95
96        let dataset_id = dataset.id.clone();
97
98        let maybe_dataset = get_dataset(&client, &IdOrName::Id(dataset_id.clone()));
99        assert_eq!(maybe_dataset.unwrap().name.unwrap(), name);
100
101        let new_name = "RUST-TEST-UPDATE";
102        let dataset = update_dataset(&client, &IdOrName::Id(dataset_id.clone()), new_name);
103        assert_eq!(dataset.name.unwrap(), new_name);
104
105        let maybe_dataset = get_dataset(&client, &IdOrName::Id(dataset_id.clone()));
106        assert_eq!(maybe_dataset.unwrap().name.unwrap(), new_name);
107
108        let no_content = delete_dataset(&client, &IdOrName::Id(dataset.id));
109        assert_eq!(no_content, NoContent::new());
110
111        let maybe_dataset = get_dataset(&client, &IdOrName::Id(dataset_id));
112        assert!(maybe_dataset.is_err());
113        let is_correct_error = match maybe_dataset.unwrap_err() {
114            ApifyClientError::ApifyApi(ApifyApiError::NotFound(text)) => text == "Dataset was not found".to_string(),
115            _ => false,
116        };
117        assert!(is_correct_error);
118    }
119    
120    #[test]
121    fn list_datasets_test () {
122        let client = create_client();
123        let name = "RUST-TEST-LIST";
124
125        let dataset = create_dataset(&client, name);
126        let dataset_id = dataset.id;
127        
128        let maybe_pagination_list = await_test!(client.list_datasets().limit(10).send());
129        assert!(maybe_pagination_list.is_ok());
130        assert!(maybe_pagination_list.unwrap().items.iter().find(|dataset| dataset.id == dataset_id.clone()).is_some());
131
132        delete_dataset(&client, &IdOrName::Id(dataset_id.clone()));
133
134        let maybe_pagination_list = await_test!(client.list_datasets().limit(10).send());
135        assert!(maybe_pagination_list.is_ok());
136        assert!(maybe_pagination_list.unwrap().items.iter().find(|dataset| dataset.id == dataset_id).is_none());
137    }
138
139    // TODO: Test all formats and most params
140    #[test] 
141    fn put_get_items_test () {
142        let client = create_client();
143        let name = "RUST-TEST-PUT-ITEMS";
144
145        let dataset = create_dataset(&client, name);
146        let dataset_id = dataset.id;
147
148        let items = get_test_items();
149        let put_result = put_items(&client, &IdOrName::Id(dataset_id.clone()), items.clone());
150        assert!(put_result.is_ok());
151        assert_eq!(put_result.unwrap(), NoContent::new());
152
153        // We have to sleep so that numbers on Apify's side update propagate properly
154        std::thread::sleep(std::time::Duration::from_secs(10));
155
156        let maybe_pagination_list = get_items(&client, IdOrName::Id(dataset_id.clone()));
157        assert!(maybe_pagination_list.is_ok());
158        let pagination_list = maybe_pagination_list.unwrap();
159        println!("{:?}", pagination_list);
160        let pagination_list_test = PaginationList{
161            total: 2,
162            offset: 0,
163            limit: Some(999999999999),
164            count: 2,
165            desc: false,
166            items: get_test_items(),
167        };
168        assert_eq!(pagination_list, pagination_list_test);
169
170        let maybe_string = get_items_raw_csv(&client, IdOrName::Id(dataset_id.clone()));
171        assert!(maybe_string.is_ok());
172        println!("{}", maybe_string.unwrap());
173
174        let no_content = delete_dataset(&client, &IdOrName::Id(dataset_id.clone()));
175        assert_eq!(no_content, NoContent::new());
176    }
177}