• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

juarezr / solrcopy / 18363067970

09 Oct 2025 01:51AM UTC coverage: 81.743% (+15.5%) from 66.205%
18363067970

push

github

web-flow
Merge pull request #39 from juarezr/feat/enhancements

Enhancements and Improvements:

- Added --archive-compression flag to the backup command with support for three compression methods
- Comprehensive Makefile.toml with organized task categories
- Coverage reporting with HTML output generation
- VS Code configuration with recommended extensions

343 of 346 new or added lines in 7 files covered. (99.13%)

4 existing lines in 3 files now uncovered.

1791 of 2191 relevant lines covered (81.74%)

3.53 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

87.06
/src/fetch.rs
1
use super::{args::Backup, connection::SolrClient, fails::*, helpers::*, models::SolrCore};
2
use log::debug;
3
use regex::Regex;
4

5
// region Solr Core
6

7
impl Backup {
8
    pub(crate) fn inspect_core(&self) -> BoxedResult<SolrCore> {
2✔
9
        let diagnostics_query_url = self.get_query_for_diagnostics();
2✔
10
        debug!("Inspecting schema of core {} at: {}", self.options.core, diagnostics_query_url);
2✔
11

12
        // try sometimes for finding the greatest num_found of docs answered by the core
13
        // Used for fixing problems with corrupted replicas of cores with more than 1 shard
14
        let times = (self.workaround_shards * 5) + 1;
2✔
15

16
        let mut res = SolrCore { num_found: 0, fields: vec![] };
2✔
17
        for it in 0..times {
2✔
18
            let json = SolrClient::query_get_as_text(&diagnostics_query_url)?;
2✔
19
            if let Ok(next) = SolrCore::parse_core_schema(self, &json) {
2✔
20
                debug!("#{} Solr query returned num_found: {}", it, next.num_found);
2✔
21
                if next.num_found > res.num_found {
2✔
22
                    res = next;
2✔
23
                }
2✔
UNCOV
24
            }
×
25
        }
26
        if res.num_found <= self.skip && self.skip > 0 {
2✔
27
            throw(format!(
×
28
                "Requested {} in --skip but found {} docs with the query.",
×
29
                self.skip, res.num_found
×
30
            ))?;
×
31
        }
2✔
32
        debug!("Core schema: {:?}", res);
2✔
33
        Ok(res)
2✔
34
    }
2✔
35
}
36

37
impl SolrCore {
38
    fn parse_core_schema(gets: &Backup, json: &str) -> BoxedResult<Self> {
2✔
39
        let core_name = &gets.options.core;
2✔
40

41
        let total_docs = Self::parse_num_found(json)?;
2✔
42
        if total_docs < 1 {
2✔
UNCOV
43
            throw(format!("Solr Core '{}'is empty!", core_name))?
×
44
        };
2✔
45
        let parsed_fields = Self::parse_field_names(json);
2✔
46

47
        let core_fields = if gets.select.is_empty() {
2✔
48
            match parsed_fields {
2✔
49
                None => throw(format!("Missing fields to parse in Solr Core '{}'!", core_name))?,
×
50
                Some(fields) => fields,
2✔
51
            }
52
        } else {
53
            // TODO: check if args.select fields matches parsed_fields when --validate
54
            gets.select.clone()
×
55
        };
56
        let res = SolrCore { num_found: total_docs, fields: core_fields };
2✔
57
        Ok(res)
2✔
58
    }
2✔
59

60
    pub(crate) fn parse_num_found(json: &str) -> BoxedResult<u64> {
3✔
61
        lazy_static! {
62
            static ref REGNF: Regex = Regex::new("\"numFound\":(\\d+),").unwrap();
63
        }
64
        match REGNF.get_group(json, 1) {
3✔
65
            None => throw(format!("Error parsing numFound from solr query: {}", json))?,
×
66
            Some(group1) => {
3✔
67
                let res = group1.parse::<u64>();
3✔
68
                res.or_else(|_| {
3✔
69
                    throw::<u64>(format!("Error converting numFound from solr query: {}", json))
×
70
                })
×
71
            }
72
        }
73
    }
3✔
74

75
    fn parse_field_names(json: &str) -> Option<Vec<String>> {
3✔
76
        lazy_static! {
77
            static ref REGFN: Regex = Regex::new("\"(\\w+)\":").unwrap();
78
        }
79
        let row1 = Self::parse_docs_from_query(json)?;
3✔
80

81
        let matches = REGFN.get_group_values(row1, 1);
3✔
82
        let filtered = matches
3✔
83
            .iter()
3✔
84
            .filter(|s| !s.starts_with('_'))
28✔
85
            .map(|&s| s.to_string())
24✔
86
            .collect::<Vec<String>>();
3✔
87
        Some(filtered)
3✔
88
    }
3✔
89

90
    /// Strips out: `[{  "a": "b", "c": "d" }]` from Solr json response
91
    /// ``` json
92
    /// {"response":{"numFound":46,"start":0,"docs":_____}}
93
    /// ```
94
    pub(crate) fn parse_docs_from_query(json: &str) -> Option<&str> {
6✔
95
        json.find_text_between("docs\":", "}}") // -> [{  ... }]
6✔
96
    }
6✔
97
}
98

99
// endregion
100

101
#[cfg(test)]
102
mod tests {
103
    use super::{SolrCore, StringHelpers};
104
    use pretty_assertions::assert_eq;
105

106
    const CORE_1ROW: &str = r#"{
107
        "response":{"numFound":46,"start":0,
108
            "docs":[
109
                {
110
                "id":"3007WFP",
111
                "name":["Dell Widescreen UltraSharp 3007WFP"],
112
                "cat":["electronics and computer1"],
113
                "price":[2199.0]}
114
            ]}}"#;
115
    const CORE_3ROW: &str = r#"{"response":{"numFound":46,"start":0,
116
            "docs":[
117
                {"id":"3007WFP","name":["Dell Widescreen UltraSharp 3007WFP"],"cat":["electronics and computer1"],"price":[2199.0]},
118
                {"id":"100-435805","name":["ATI Radeon X1900 XTX 512 MB PCIE Video Card"],"cat":["electronics","graphics card"],"price":[649.99]},
119
                {"id":"EN7800GTX/2DHTV/256M","name":["ASUS Extreme N7800GTX/2DHTV (256 MB)"],"cat":["electronics","graphics card"],"price":[479.95]}
120
            ]}}"#;
121

122
    #[test]
123
    fn check_schema_num_found() {
1✔
124
        let num_found = SolrCore::parse_num_found(CORE_1ROW);
1✔
125
        assert_eq!(num_found.ok(), Some(46));
1✔
126
    }
1✔
127

128
    #[test]
129
    fn check_schema_fields() {
1✔
130
        let fields = SolrCore::parse_field_names(CORE_1ROW);
1✔
131
        assert_eq!(fields.is_some(), true);
1✔
132

133
        let fields2 = fields.unwrap();
1✔
134

135
        assert_eq!(fields2.len(), 4);
1✔
136
        assert_eq!(fields2.get(0).unwrap(), "id");
1✔
137
        assert_eq!(fields2.get(1).unwrap(), "name");
1✔
138
        assert_eq!(fields2.get(2).unwrap(), "cat");
1✔
139
        assert_eq!(fields2.get(3).unwrap(), "price");
1✔
140
    }
1✔
141

142
    #[test]
143
    fn check_query_docs() {
1✔
144
        let docs = SolrCore::parse_docs_from_query(CORE_3ROW);
1✔
145
        assert_eq!(docs.is_some(), true);
1✔
146

147
        let json = docs.unwrap().remove_whitespace();
1✔
148

149
        let starting = &json[..2];
1✔
150
        assert_eq!(starting, "[{");
1✔
151

152
        let two = json.len() - 2;
1✔
153
        let ending = &json[two..];
1✔
154
        assert_eq!(ending, "}]");
1✔
155

156
        let rows = json.split("},{").collect::<Vec<&str>>();
1✔
157
        assert_eq!(rows.len(), 3);
1✔
158
    }
1✔
159
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc