diff options
Diffstat (limited to 'tests/models/legacy')
| -rw-r--r-- | tests/models/legacy/__init__.py | 0 | ||||
| -rw-r--r-- | tests/models/legacy/data.py | 265 | ||||
| -rw-r--r-- | tests/models/legacy/test_offerwall_parse_response.py | 186 | ||||
| -rw-r--r-- | tests/models/legacy/test_profiling_questions.py | 81 | ||||
| -rw-r--r-- | tests/models/legacy/test_user_question_answer_in.py | 304 |
5 files changed, 836 insertions, 0 deletions
diff --git a/tests/models/legacy/__init__.py b/tests/models/legacy/__init__.py new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/tests/models/legacy/__init__.py diff --git a/tests/models/legacy/data.py b/tests/models/legacy/data.py new file mode 100644 index 0000000..20f3231 --- /dev/null +++ b/tests/models/legacy/data.py @@ -0,0 +1,265 @@ +# https://fsb.generalresearch.com/00ff1d9b71b94bf4b20d22cd56774120/offerwall/45b7228a7/?bpuid=379fb74f-05b2-42dc-b283 +# -47e1c8678b04&duration=1200&format=json&country_iso=us +RESPONSE_45b7228a7 = ( + '{"info": {"success": true}, "offerwall": {"availability_count": 9, "buckets": [{"category": [{"adwords_id": ' + 'null, "adwords_label": null, "id": "c82cf98c578a43218334544ab376b00e", "label": "Social Research", "p": 1.0}], ' + '"description": "", "duration": {"max": 719, "min": 72, "q1": 144, "q2": 621, "q3": 650}, ' + '"id": "5503c471d95645dd947080704d3760b3", "name": "", "payout": {"max": 132, "min": 68, "q1": 113, "q2": 124, ' + '"q3": 128}, "quality_score": 1.0, "uri": ' + '"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=5503c471d95645dd947080704d3760b3&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=16fa868", "x": 0, "y": 0}, ' + '{"category": [{"adwords_id": null, "adwords_label": null, "id": "c82cf98c578a43218334544ab376b00e", ' + '"label": "Social Research", "p": 0.6666666666666666}, {"adwords_id": "5000", "adwords_label": "World ' + 'Localities", "id": "cd3f9374ba5d4e5692ee5691320ecc8b", "label": "World Localities", "p": 0.16666666666666666}, ' + '{"adwords_id": "14", "adwords_label": "People & Society", "id": "c8642a1b86d9460cbe8f7e8ae6e56ee4", ' + '"label": "People & Society", "p": 0.16666666666666666}], "description": "", "duration": {"max": 1180, ' + '"min": 144, "q1": 457, "q2": 621, "q3": 1103}, "id": "56f437aa5da443748872390a5cbf6103", "name": "", "payout": {' + '"max": 113, "min": 24, "q1": 40, "q2": 68, "q3": 68}, "quality_score": 0.17667012, ' + '"uri": "https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=56f437aa5da443748872390a5cbf6103&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=16fa868", "x": 1, "y": 0}, ' + '{"category": [{"adwords_id": null, "adwords_label": null, "id": "c82cf98c578a43218334544ab376b00e", ' + '"label": "Social Research", "p": 0.6666666666666666}, {"adwords_id": "5000", "adwords_label": "World ' + 'Localities", "id": "cd3f9374ba5d4e5692ee5691320ecc8b", "label": "World Localities", "p": 0.16666666666666666}, ' + '{"adwords_id": "14", "adwords_label": "People & Society", "id": "c8642a1b86d9460cbe8f7e8ae6e56ee4", ' + '"label": "People & Society", "p": 0.16666666666666666}], "description": "", "duration": {"max": 1180, ' + '"min": 144, "q1": 457, "q2": 1103, "q3": 1128}, "id": "a5b8403e4a4a4ed1a21ef9b3a721ab02", "name": "", ' + '"payout": {"max": 68, "min": 14, "q1": 24, "q2": 40, "q3": 68}, "quality_score": 0.01, ' + '"uri": "https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=a5b8403e4a4a4ed1a21ef9b3a721ab02&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=16fa868", "x": 2, "y": 0}], ' + '"id": "2fba2999baf0423cad0c49eceea4eb33", "payout_format": "${payout/100:.2f}"}}' +) + +RESPONSE_b145b803 = ( + '{"info":{"success":true},"offerwall":{"availability_count":10,"buckets":[{"category":[{"adwords_id":null,' + '"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research","p":1.0}],"contents":[{' + '"id":"b9d6fdb95ae2402dbb8e8673be382f04","id_code":"m:b9d6fdb95ae2402dbb8e8673be382f04","loi":954,"payout":166,' + '"source":"m"},{"id":"x94r9bg","id_code":"o:x94r9bg","loi":71,"payout":132,"source":"o"},{"id":"ejqjbv4",' + '"id_code":"o:ejqjbv4","loi":650,"payout":128,"source":"o"},{"id":"yxqdnb9","id_code":"o:yxqdnb9","loi":624,' + '"payout":113,"source":"o"},{"id":"vyjrv0v","id_code":"o:vyjrv0v","loi":719,"payout":124,"source":"o"}],' + '"currency":"USD","description":"","duration":{"max":954,"min":72,"q1":625,"q2":650,"q3":719},' + '"id":"c190231a7d494012a2f641a89a85e6a6","name":"","payout":{"max":166,"min":113,"q1":124,"q2":128,"q3":132},' + '"quality_score":1.0,"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120' + '/?i=c190231a7d494012a2f641a89a85e6a6&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=9dbbf8c","x":0,"y":0},' + '{"category":[{"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social ' + 'Research","p":0.5},{"adwords_id":"5000","adwords_label":"World Localities",' + '"id":"cd3f9374ba5d4e5692ee5691320ecc8b","label":"World Localities","p":0.25},{"adwords_id":"14",' + '"adwords_label":"People & Society","id":"c8642a1b86d9460cbe8f7e8ae6e56ee4","label":"People & Society",' + '"p":0.25}],"contents":[{"id":"ejqa3kw","id_code":"o:ejqa3kw","loi":143,"payout":68,"source":"o"},' + '{"id":"g6xkrbm","id_code":"o:g6xkrbm","loi":536,"payout":68,"source":"o"},{"id":"yr5od0g","id_code":"o:yr5od0g",' + '"loi":457,"payout":68,"source":"o"}],"currency":"USD","description":"","duration":{"max":537,"min":144,"q1":301,' + '"q2":457,"q3":497},"id":"ee12be565f744ef2b194703f3d32f8cd","name":"","payout":{"max":68,"min":68,"q1":68,' + '"q2":68,"q3":68},"quality_score":0.01,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=ee12be565f744ef2b194703f3d32f8cd&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=9dbbf8c","x":1,"y":0},' + '{"category":[{"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social ' + 'Research","p":1.0}],"contents":[{"id":"a019660a8bc0411dba19a3e5c5df5b6c",' + '"id_code":"m:a019660a8bc0411dba19a3e5c5df5b6c","loi":1180,"payout":24,"source":"m"},{"id":"ejqa3kw",' + '"id_code":"o:ejqa3kw","loi":143,"payout":68,"source":"o"},{"id":"8c54725047cc4e0590665a034d37e7f5",' + '"id_code":"m:8c54725047cc4e0590665a034d37e7f5","loi":1128,"payout":14,"source":"m"}],"currency":"USD",' + '"description":"","duration":{"max":1180,"min":144,"q1":636,"q2":1128,"q3":1154},' + '"id":"dc2551eb48d84b329fdcb5b2bd60ed71","name":"","payout":{"max":68,"min":14,"q1":19,"q2":24,"q3":46},' + '"quality_score":0.06662835156312356,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=dc2551eb48d84b329fdcb5b2bd60ed71&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=9dbbf8c","x":2,"y":0}],' + '"id":"7cb9eb4c1a5b41a38cfebd13c9c338cb"}}' +) + +# This is a blocked user. Otherwise, the format is identical to RESPONSE_b145b803 +# https://fsb.generalresearch.com/00ff1d9b71b94bf4b20d22cd56774120/offerwall/1e5f0af8/?bpuid=00051c62-a872-4832-a008 +# -c37ec51d33d3&duration=1200&format=json&country_iso=us +RESPONSE_d48cce47 = ( + '{"info":{"success":true},"offerwall":{"availability_count":0,"buckets":[],' + '"id":"168680387a7f4c8c9cc8e7ab63f502ff","payout_format":"${payout/100:.2f}"}}' +) + +# https://fsb.generalresearch.com/00ff1d9b71b94bf4b20d22cd56774120/offerwall/1e5f0af8/?bpuid=379fb74f-05b2-42dc-b283 +# -47e1c8678b04&duration=1200&format=json&country_iso=us +RESPONSE_1e5f0af8 = ( + '{"info":{"success":true},"offerwall":{"availability_count":9,"buckets":[{"category":[{"adwords_id":null,' + '"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research","p":1.0}],"contents":[{' + '"id":"x94r9bg","id_code":"o:x94r9bg","loi":71,"payout":132,"source":"o"},{"id":"yxqdnb9","id_code":"o:yxqdnb9",' + '"loi":604,"payout":113,"source":"o"},{"id":"ejqjbv4","id_code":"o:ejqjbv4","loi":473,"payout":128,"source":"o"},' + '{"id":"vyjrv0v","id_code":"o:vyjrv0v","loi":719,"payout":124,"source":"o"}],"currency":"USD","description":"",' + '"duration":{"max":719,"min":72,"q1":373,"q2":539,"q3":633},"id":"2a4a897a76464af2b85703b72a125da0",' + '"is_recontact":false,"name":"","payout":{"max":132,"min":113,"q1":121,"q2":126,"q3":129},"quality_score":1.0,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=2a4a897a76464af2b85703b72a125da0&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=82fe142","x":0,"y":0},' + '{"category":[{"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social ' + 'Research","p":0.5},{"adwords_id":"5000","adwords_label":"World Localities",' + '"id":"cd3f9374ba5d4e5692ee5691320ecc8b","label":"World Localities","p":0.25},{"adwords_id":"14",' + '"adwords_label":"People & Society","id":"c8642a1b86d9460cbe8f7e8ae6e56ee4","label":"People & Society",' + '"p":0.25}],"contents":[{"id":"775ed98f65604dac91b3a60814438829","id_code":"m:775ed98f65604dac91b3a60814438829",' + '"loi":1121,"payout":32,"source":"m"},{"id":"ejqa3kw","id_code":"o:ejqa3kw","loi":143,"payout":68,"source":"o"},' + '{"id":"yr5od0g","id_code":"o:yr5od0g","loi":457,"payout":68,"source":"o"}],"currency":"USD","description":"",' + '"duration":{"max":1121,"min":144,"q1":301,"q2":457,"q3":789},"id":"0aa83eb711c042e28bb9284e604398ac",' + '"is_recontact":false,"name":"","payout":{"max":68,"min":32,"q1":50,"q2":68,"q3":68},"quality_score":0.01,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=0aa83eb711c042e28bb9284e604398ac&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=82fe142","x":1,"y":0},' + '{"category":[{"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social ' + 'Research","p":1.0}],"contents":[{"id":"775ed98f65604dac91b3a60814438829",' + '"id_code":"m:775ed98f65604dac91b3a60814438829","loi":1121,"payout":32,"source":"m"},' + '{"id":"8c54725047cc4e0590665a034d37e7f5","id_code":"m:8c54725047cc4e0590665a034d37e7f5","loi":1128,"payout":14,' + '"source":"m"},{"id":"a019660a8bc0411dba19a3e5c5df5b6c","id_code":"m:a019660a8bc0411dba19a3e5c5df5b6c",' + '"loi":1180,"payout":24,"source":"m"}],"currency":"USD","description":"","duration":{"max":1180,"min":1121,' + '"q1":1125,"q2":1128,"q3":1154},"id":"d3a87b2bb6cf4428a55916bdf65e775e","is_recontact":false,"name":"",' + '"payout":{"max":32,"min":14,"q1":19,"q2":24,"q3":28},"quality_score":0.0825688889614345,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=d3a87b2bb6cf4428a55916bdf65e775e&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=82fe142","x":2,"y":0}],' + '"id":"391a54bbe84c4dbfa50b40841201a606"}}' +) + +# https://fsb.generalresearch.com/00ff1d9b71b94bf4b20d22cd56774120/offerwall/5fl8bpv5/?bpuid=379fb74f-05b2-42dc-b283 +# -47e1c8678b04&duration=1200&format=json&country_iso=us +RESPONSE_5fl8bpv5 = ( + '{"info":{"success":true},"offerwall":{"availability_count":9,"buckets":[{' + '"id":"a1097b20f2ae472a9a9ad2987ba3bf95",' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=a1097b20f2ae472a9a9ad2987ba3bf95&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e7baf5e"}],' + '"id":"fddaa544d7ff428a8ccccd0667fdc249","payout_format":"${payout/100:.2f}"}}' +) + +# https://fsb.generalresearch.com/00ff1d9b71b94bf4b20d22cd56774120/offerwall/37d1da64/?bpuid=379fb74f-05b2-42dc-b283 +# -47e1c8678b04&duration=1200&format=json&country_iso=us +RESPONSE_37d1da64 = ( + '{"info":{"success":true},"offerwall":{"availability_count":18,"buckets":[{"category":[{"adwords_id":null,' + '"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research","p":1.0}],"contents":[{' + '"id":"0qvwx4z","id_code":"o:0qvwx4z","loi":700,"payout":106,"source":"o"},{"id":"x94r9bg","id_code":"o:x94r9bg",' + '"loi":72,"payout":132,"source":"o"},{"id":"yxqdnb9","id_code":"o:yxqdnb9","loi":605,"payout":113,"source":"o"},' + '{"id":"ejqjbv4","id_code":"o:ejqjbv4","loi":474,"payout":128,"source":"o"}],"eligibility":"conditional",' + '"id":"2cfc47e8d8c4417cb1f499dbf7e9afb8","loi":700,"missing_questions":["7ca8b59f4c864f80a1a7c7287adfc637"],' + '"payout":106,"uri":null},{"category":[{"adwords_id":null,"adwords_label":null,' + '"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research","p":1.0}],"contents":[{"id":"yxqdnb9",' + '"id_code":"o:yxqdnb9","loi":605,"payout":113,"source":"o"},{"id":"x94r9bg","id_code":"o:x94r9bg","loi":72,' + '"payout":132,"source":"o"},{"id":"ejqjbv4","id_code":"o:ejqjbv4","loi":474,"payout":128,"source":"o"}],' + '"eligibility":"unconditional","id":"8964a87ebbe9433cae0ddce1b34a637a","loi":605,"payout":113,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=8964a87ebbe9433cae0ddce1b34a637a&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=ec8aa9a"},{"category":[{' + '"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research",' + '"p":1.0}],"contents":[{"id":"a019660a8bc0411dba19a3e5c5df5b6c","id_code":"m:a019660a8bc0411dba19a3e5c5df5b6c",' + '"loi":1180,"payout":24,"source":"m"},{"id":"x94r9bg","id_code":"o:x94r9bg","loi":72,"payout":132,"source":"o"},' + '{"id":"yxqdnb9","id_code":"o:yxqdnb9","loi":605,"payout":113,"source":"o"},' + '{"id":"775ed98f65604dac91b3a60814438829","id_code":"m:775ed98f65604dac91b3a60814438829","loi":1121,"payout":32,' + '"source":"m"},{"id":"ejqa3kw","id_code":"o:ejqa3kw","loi":144,"payout":68,"source":"o"},{"id":"ejqjbv4",' + '"id_code":"o:ejqjbv4","loi":474,"payout":128,"source":"o"},{"id":"yr5od0g","id_code":"o:yr5od0g","loi":457,' + '"payout":68,"source":"o"},{"id":"vyjrv0v","id_code":"o:vyjrv0v","loi":719,"payout":124,"source":"o"}],' + '"eligibility":"unconditional","id":"ba98df6041344e818f02873534ae09a3","loi":1180,"payout":24,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=ba98df6041344e818f02873534ae09a3&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=ec8aa9a"},{"category":[{' + '"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research",' + '"p":1.0}],"contents":[{"id":"775ed98f65604dac91b3a60814438829","id_code":"m:775ed98f65604dac91b3a60814438829",' + '"loi":1121,"payout":32,"source":"m"},{"id":"x94r9bg","id_code":"o:x94r9bg","loi":72,"payout":132,"source":"o"},' + '{"id":"yxqdnb9","id_code":"o:yxqdnb9","loi":605,"payout":113,"source":"o"},{"id":"ejqa3kw",' + '"id_code":"o:ejqa3kw","loi":144,"payout":68,"source":"o"},{"id":"ejqjbv4","id_code":"o:ejqjbv4","loi":474,' + '"payout":128,"source":"o"},{"id":"yr5od0g","id_code":"o:yr5od0g","loi":457,"payout":68,"source":"o"},' + '{"id":"vyjrv0v","id_code":"o:vyjrv0v","loi":719,"payout":124,"source":"o"}],"eligibility":"unconditional",' + '"id":"6456abe0f2584be8a30d9e0e93bef496","loi":1121,"payout":32,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=6456abe0f2584be8a30d9e0e93bef496&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=ec8aa9a"},{"category":[{' + '"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research",' + '"p":1.0}],"contents":[{"id":"ejqa3kw","id_code":"o:ejqa3kw","loi":144,"payout":68,"source":"o"},{"id":"x94r9bg",' + '"id_code":"o:x94r9bg","loi":72,"payout":132,"source":"o"},{"id":"x94r9bg","id_code":"o:x94r9bg","loi":72,' + '"payout":132,"source":"o"}],"eligibility":"unconditional","id":"e0a0fb27bf174040be7971795a967ce5","loi":144,' + '"payout":68,"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=e0a0fb27bf174040be7971795a967ce5&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=ec8aa9a"},{"category":[{' + '"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research",' + '"p":1.0}],"contents":[{"id":"ejqjbv4","id_code":"o:ejqjbv4","loi":474,"payout":128,"source":"o"},' + '{"id":"x94r9bg","id_code":"o:x94r9bg","loi":72,"payout":132,"source":"o"},{"id":"x94r9bg","id_code":"o:x94r9bg",' + '"loi":72,"payout":132,"source":"o"}],"eligibility":"unconditional","id":"99e3f8cfd367411b822cf11c3b54b558",' + '"loi":474,"payout":128,"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709' + "/00ff1d9b71b94bf4b20d22cd56774120/?i=99e3f8cfd367411b822cf11c3b54b558&b=379fb74f-05b2-42dc-b283-47e1c8678b04" + '&66482fb=ec8aa9a"},{"category":[{"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e",' + '"label":"Social Research","p":1.0}],"contents":[{"id":"8c54725047cc4e0590665a034d37e7f5",' + '"id_code":"m:8c54725047cc4e0590665a034d37e7f5","loi":1128,"payout":14,"source":"m"},{"id":"x94r9bg",' + '"id_code":"o:x94r9bg","loi":72,"payout":132,"source":"o"},{"id":"yxqdnb9","id_code":"o:yxqdnb9","loi":605,' + '"payout":113,"source":"o"},{"id":"775ed98f65604dac91b3a60814438829",' + '"id_code":"m:775ed98f65604dac91b3a60814438829","loi":1121,"payout":32,"source":"m"},{"id":"ejqa3kw",' + '"id_code":"o:ejqa3kw","loi":144,"payout":68,"source":"o"},{"id":"ejqjbv4","id_code":"o:ejqjbv4","loi":474,' + '"payout":128,"source":"o"},{"id":"yr5od0g","id_code":"o:yr5od0g","loi":457,"payout":68,"source":"o"},' + '{"id":"vyjrv0v","id_code":"o:vyjrv0v","loi":719,"payout":124,"source":"o"}],"eligibility":"unconditional",' + '"id":"db7bc77afbb6443e8f35e9f06764fd06","loi":1128,"payout":14,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=db7bc77afbb6443e8f35e9f06764fd06&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=ec8aa9a"},{"category":[{' + '"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research",' + '"p":0.5},{"adwords_id":"5000","adwords_label":"World Localities","id":"cd3f9374ba5d4e5692ee5691320ecc8b",' + '"label":"World Localities","p":0.25},{"adwords_id":"14","adwords_label":"People & Society",' + '"id":"c8642a1b86d9460cbe8f7e8ae6e56ee4","label":"People & Society","p":0.25}],"contents":[{"id":"yr5od0g",' + '"id_code":"o:yr5od0g","loi":457,"payout":68,"source":"o"},{"id":"x94r9bg","id_code":"o:x94r9bg","loi":72,' + '"payout":132,"source":"o"},{"id":"ejqa3kw","id_code":"o:ejqa3kw","loi":144,"payout":68,"source":"o"}],' + '"eligibility":"unconditional","id":"d5af3c782a354d6a8616e47531eb15e7","loi":457,"payout":68,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=d5af3c782a354d6a8616e47531eb15e7&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=ec8aa9a"},{"category":[{' + '"adwords_id":null,"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research",' + '"p":1.0}],"contents":[{"id":"vyjrv0v","id_code":"o:vyjrv0v","loi":719,"payout":124,"source":"o"},' + '{"id":"x94r9bg","id_code":"o:x94r9bg","loi":72,"payout":132,"source":"o"},{"id":"ejqjbv4","id_code":"o:ejqjbv4",' + '"loi":474,"payout":128,"source":"o"}],"eligibility":"unconditional","id":"ceafb146bb7042889b85630a44338a75",' + '"loi":719,"payout":124,"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709' + "/00ff1d9b71b94bf4b20d22cd56774120/?i=ceafb146bb7042889b85630a44338a75&b=379fb74f-05b2-42dc-b283-47e1c8678b04" + '&66482fb=ec8aa9a"}],"id":"37ed0858e0f64329812e2070fb658eb3","question_info":{' + '"7ca8b59f4c864f80a1a7c7287adfc637":{"choices":[{"choice_id":"0","choice_text":"Single, never married",' + '"order":0},{"choice_id":"1","choice_text":"Living with a Partner","order":1},{"choice_id":"2",' + '"choice_text":"Civil Union / Domestic Partnership","order":2},{"choice_id":"3","choice_text":"Married",' + '"order":3},{"choice_id":"4","choice_text":"Separated","order":4},{"choice_id":"5","choice_text":"Divorced",' + '"order":5},{"choice_id":"6","choice_text":"Widowed","order":6}],"country_iso":"us","language_iso":"eng",' + '"question_id":"7ca8b59f4c864f80a1a7c7287adfc637","question_text":"What is your relationship status?",' + '"question_type":"MC","selector":"SA"}}}}' +) + +# https://fsb.generalresearch.com/00ff1d9b71b94bf4b20d22cd56774120/offerwall/5fa23085/?bpuid=379fb74f-05b2-42dc-b283 +# -47e1c8678b04&duration=1200&format=json&country_iso=us +RESPONSE_5fa23085 = ( + '{"info":{"success":true},"offerwall":{"availability_count":7,"buckets":[{"category":[{"adwords_id":null,' + '"adwords_label":null,"id":"c82cf98c578a43218334544ab376b00e","label":"Social Research","p":0.6666666666666666},' + '{"adwords_id":"5000","adwords_label":"World Localities","id":"cd3f9374ba5d4e5692ee5691320ecc8b","label":"World ' + 'Localities","p":0.16666666666666666},{"adwords_id":"14","adwords_label":"People & Society",' + '"id":"c8642a1b86d9460cbe8f7e8ae6e56ee4","label":"People & Society","p":0.16666666666666666}],"contents":[{' + '"id":"x94r9bg","id_code":"o:x94r9bg","loi":72,"payout":132,"source":"o"},{"id":"yxqdnb9","id_code":"o:yxqdnb9",' + '"loi":605,"payout":113,"source":"o"},{"id":"ejqjbv4","id_code":"o:ejqjbv4","loi":640,"payout":128,"source":"o"},' + '{"id":"yr5od0g","id_code":"o:yr5od0g","loi":457,"payout":68,"source":"o"},{"id":"vyjrv0v","id_code":"o:vyjrv0v",' + '"loi":719,"payout":124,"source":"o"}],"duration":{"max":719,"min":72,"q1":457,"q2":605,"q3":640},' + '"id":"30049c28363b4f689c84fbacf1cc57e2","payout":{"max":132,"min":68,"q1":113,"q2":124,"q3":128},' + '"source":"pollfish","uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120' + '/?i=30049c28363b4f689c84fbacf1cc57e2&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e3c1af1"}],' + '"id":"1c33756fd7ca49fa84ee48e42145e68c"}}' +) + +# https://fsb.generalresearch.com/00ff1d9b71b94bf4b20d22cd56774120/offerwall/1705e4f8/?bpuid=379fb74f-05b2-42dc-b283 +# -47e1c8678b04&duration=1200&format=json&country_iso=us +RESPONSE_1705e4f8 = ( + '{"info":{"success":true},"offerwall":{"availability_count":7,"buckets":[{"currency":"USD","duration":719,' + '"id":"d06abd6ac75b453a93d0e85e4e391c00","min_payout":124,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=d06abd6ac75b453a93d0e85e4e391c00&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"},{"currency":"USD",' + '"duration":705,"id":"bcf5ca85a4044e9abed163f72039c7d1","min_payout":123,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=bcf5ca85a4044e9abed163f72039c7d1&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"},{"currency":"USD",' + '"duration":679,"id":"b85034bd59e04a64ac1be7686a4c906d","min_payout":121,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=b85034bd59e04a64ac1be7686a4c906d&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"},{"currency":"USD",' + '"duration":1180,"id":"324cf03b9ba24ef19284683bf9b62afb","min_payout":24,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=324cf03b9ba24ef19284683bf9b62afb&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"},{"currency":"USD",' + '"duration":1062,"id":"6bbbef3157c346009e677e556ecea7e7","min_payout":17,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=6bbbef3157c346009e677e556ecea7e7&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"},{"currency":"USD",' + '"duration":1128,"id":"bc12ba86b5024cf5b8ade997415190f7","min_payout":14,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=bc12ba86b5024cf5b8ade997415190f7&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"},{"currency":"USD",' + '"duration":1126,"id":"e574e715dcc744dbacf84a8426a0cd37","min_payout":10,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=e574e715dcc744dbacf84a8426a0cd37&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"},{"currency":"USD",' + '"duration":1302,"id":"a6f562e3371347d19d281d40b3ca317d","min_payout":10,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=a6f562e3371347d19d281d40b3ca317d&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"},{"currency":"USD",' + '"duration":953,"id":"462c8e1fbdad475792a360097c8e740f","min_payout":4,' + '"uri":"https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i' + '=462c8e1fbdad475792a360097c8e740f&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=e09baa2"}],' + '"id":"7f5158dc25174ada89f54e2b26a61b20"}}' +) + +# Blocked user +# https://fsb.generalresearch.com/00ff1d9b71b94bf4b20d22cd56774120/offerwall/0af0f7ec/?bpuid=00051c62-a872-4832-a008 +# -c37ec51d33d3&duration=1200&format=json&country_iso=us +RESPONSE_0af0f7ec = ( + '{"info":{"success":true},"offerwall":{"availability_count":0,"buckets":[],' + '"id":"34e71f4ccdec47b3b0991f5cfda60238","payout_format":"${payout/100:.2f}"}}' +) diff --git a/tests/models/legacy/test_offerwall_parse_response.py b/tests/models/legacy/test_offerwall_parse_response.py new file mode 100644 index 0000000..7fb5315 --- /dev/null +++ b/tests/models/legacy/test_offerwall_parse_response.py @@ -0,0 +1,186 @@ +import json + +from generalresearch.models import Source +from generalresearch.models.legacy.bucket import ( + TopNPlusBucket, + SurveyEligibilityCriterion, + DurationSummary, + PayoutSummary, + BucketTask, +) + + +class TestOfferwallTopNAndStarwall: + def test_45b7228a7(self): + from generalresearch.models.legacy.offerwall import ( + TopNOfferWall, + TopNOfferWallResponse, + StarwallOfferWallResponse, + ) + from tests.models.legacy.data import ( + RESPONSE_45b7228a7, + ) + + res = json.loads(RESPONSE_45b7228a7) + assert TopNOfferWallResponse.model_validate(res) + offerwall = TopNOfferWall.model_validate(res["offerwall"]) + assert offerwall + offerwall.censor() + # Format is identical to starwall + assert StarwallOfferWallResponse.model_validate(res) + + def test_b145b803(self): + from generalresearch.models.legacy.offerwall import ( + TopNPlusOfferWallResponse, + StarwallPlusOfferWallResponse, + ) + from tests.models.legacy.data import ( + RESPONSE_b145b803, + ) + + res = json.loads(RESPONSE_b145b803) + assert TopNPlusOfferWallResponse.model_validate(res) + assert StarwallPlusOfferWallResponse.model_validate(res) + + def test_d48cce47(self): + from generalresearch.models.legacy.offerwall import ( + TopNPlusBlockOfferWallResponse, + StarwallPlusBlockOfferWallResponse, + ) + from tests.models.legacy.data import ( + RESPONSE_b145b803, + RESPONSE_d48cce47, + ) + + res = json.loads(RESPONSE_d48cce47) # this is a blocked user's response + assert TopNPlusBlockOfferWallResponse.model_validate(res) + assert StarwallPlusBlockOfferWallResponse.model_validate(res) + # otherwise it is identical to the plus's response + res = json.loads(RESPONSE_b145b803) + assert TopNPlusBlockOfferWallResponse.model_validate(res) + assert StarwallPlusBlockOfferWallResponse.model_validate(res) + + def test_1e5f0af8(self): + from generalresearch.models.legacy.offerwall import ( + TopNPlusBlockRecontactOfferWallResponse, + StarwallPlusBlockRecontactOfferWallResponse, + ) + from tests.models.legacy.data import ( + RESPONSE_d48cce47, + RESPONSE_1e5f0af8, + ) + + res = json.loads(RESPONSE_1e5f0af8) + assert TopNPlusBlockRecontactOfferWallResponse.model_validate(res) + assert StarwallPlusBlockRecontactOfferWallResponse.model_validate(res) + + res = json.loads(RESPONSE_d48cce47) # this is a blocked user's response + assert TopNPlusBlockRecontactOfferWallResponse.model_validate(res) + assert StarwallPlusBlockRecontactOfferWallResponse.model_validate(res) + + def test_eligibility_criteria(self): + b = TopNPlusBucket( + id="c82cf98c578a43218334544ab376b00e", + contents=[ + BucketTask( + id="12345", + payout=10, + source=Source.TESTING, + id_code="t:12345", + loi=120, + ) + ], + duration=DurationSummary(max=1, min=1, q1=1, q2=1, q3=1), + quality_score=1, + payout=PayoutSummary(max=1, min=1, q1=1, q2=1, q3=1), + uri="https://task.generalresearch.com/api/v1/52d3f63b2709/00ff1d9b71b94bf4b20d22cd56774120/?i=2a4a897a76464af2b85703b72a125da0&b=379fb74f-05b2-42dc-b283-47e1c8678b04&66482fb=82fe142", + eligibility_criteria=( + SurveyEligibilityCriterion( + question_id="71a367fb71b243dc89f0012e0ec91749", + question_text="what is something", + qualifying_answer=("1",), + qualifying_answer_label=("abc",), + property_code="t:123", + ), + SurveyEligibilityCriterion( + question_id="81a367fb71b243dc89f0012e0ec91749", + question_text="what is something 2", + qualifying_answer=("2",), + qualifying_answer_label=("ddd",), + property_code="t:124", + ), + ), + ) + assert b.eligibility_criteria[0].rank == 0 + assert b.eligibility_criteria[1].rank == 1 + print(b.model_dump_json()) + b.censor() + print(b.model_dump_json()) + + +class TestOfferwallSingle: + def test_5fl8bpv5(self): + from generalresearch.models.legacy.offerwall import ( + SingleEntryOfferWallResponse, + ) + from tests.models.legacy.data import ( + RESPONSE_5fl8bpv5, + ) + + res = json.loads(RESPONSE_5fl8bpv5) + assert SingleEntryOfferWallResponse.model_validate(res) + + +class TestOfferwallSoftPair: + def test_37d1da64(self): + from generalresearch.models.legacy.offerwall import ( + SoftPairOfferwallResponse, + ) + from tests.models.legacy.data import ( + RESPONSE_37d1da64, + ) + + res = json.loads(RESPONSE_37d1da64) + assert SoftPairOfferwallResponse.model_validate(res) + + +class TestMarketplace: + def test_5fa23085(self): + from generalresearch.models.legacy.offerwall import ( + MarketplaceOfferwallResponse, + ) + + from tests.models.legacy.data import ( + RESPONSE_5fa23085, + ) + + res = json.loads(RESPONSE_5fa23085) + assert MarketplaceOfferwallResponse.model_validate(res) + + +class TestTimebucks: + def test_1705e4f8(self): + from generalresearch.models.legacy.offerwall import ( + TimeBucksOfferwallResponse, + ) + from tests.models.legacy.data import ( + RESPONSE_1705e4f8, + ) + + res = json.loads(RESPONSE_1705e4f8) + assert TimeBucksOfferwallResponse.model_validate(res) + + def test_0af0f7ec(self): + from generalresearch.models.legacy.offerwall import ( + TimeBucksBlockOfferwallResponse, + ) + from tests.models.legacy.data import ( + RESPONSE_1705e4f8, + RESPONSE_0af0f7ec, + ) + + res = json.loads(RESPONSE_0af0f7ec) + assert TimeBucksBlockOfferwallResponse.model_validate(res) + + res = json.loads(RESPONSE_1705e4f8) + assert TimeBucksBlockOfferwallResponse.model_validate(res) diff --git a/tests/models/legacy/test_profiling_questions.py b/tests/models/legacy/test_profiling_questions.py new file mode 100644 index 0000000..1afaa6b --- /dev/null +++ b/tests/models/legacy/test_profiling_questions.py @@ -0,0 +1,81 @@ +class TestUpkQuestionResponse: + + def test_init(self): + from generalresearch.models.legacy.questions import UpkQuestionResponse + + s = ( + '{"status": "success", "count": 7, "questions": [{"selector": "SL", "validation": {"patterns": [{' + '"message": "Must input a value between 13 and 120", "pattern": "^(1[01][0-9]|120|1[3-9]|[2-9][' + '0-9])$"}]}, "country_iso": "us", "question_id": "c5a4ef644c374f8994ecb3226b84263e", "language_iso": ' + '"eng", "configuration": {"max_length": 3, "type": "TE"}, "question_text": "What is your age (in ' + 'years)?", "question_type": "TE", "task_score": 20.28987136651298, "task_count": 21131, "p": 1.0}, ' + '{"choices": [{"order": 0, "choice_id": "0", "choice_text": "Male"}, {"order": 1, "choice_id": "1", ' + '"choice_text": "Female"}, {"order": 2, "choice_id": "2", "choice_text": "Other"}], "selector": "SA", ' + '"country_iso": "us", "question_id": "5d6d9f3c03bb40bf9d0a24f306387d7c", "language_iso": "eng", ' + '"question_text": "What is your gender?", "question_type": "MC", "task_score": 16.598347505339095, ' + '"task_count": 4842, "p": 0.8180607558081178}, {"choices": [{"order": 0, "choice_id": "ara", ' + '"choice_text": "Arabic"}, {"order": 1, "choice_id": "zho", "choice_text": "Chinese - Mandarin"}, ' + '{"order": 2, "choice_id": "dut", "choice_text": "Dutch"}, {"order": 3, "choice_id": "eng", ' + '"choice_text": "English"}, {"order": 4, "choice_id": "fre", "choice_text": "French"}, {"order": 5, ' + '"choice_id": "ger", "choice_text": "German"}, {"order": 6, "choice_id": "hat", "choice_text": "Haitian ' + 'Creole"}, {"order": 7, "choice_id": "hin", "choice_text": "Hindi"}, {"order": 8, "choice_id": "ind", ' + '"choice_text": "Indonesian"}, {"order": 9, "choice_id": "ita", "choice_text": "Italian"}, {"order": 10, ' + '"choice_id": "jpn", "choice_text": "Japanese"}, {"order": 11, "choice_id": "kor", "choice_text": ' + '"Korean"}, {"order": 12, "choice_id": "may", "choice_text": "Malay"}, {"order": 13, "choice_id": "pol", ' + '"choice_text": "Polish"}, {"order": 14, "choice_id": "por", "choice_text": "Portuguese"}, {"order": 15, ' + '"choice_id": "pan", "choice_text": "Punjabi"}, {"order": 16, "choice_id": "rus", "choice_text": ' + '"Russian"}, {"order": 17, "choice_id": "spa", "choice_text": "Spanish"}, {"order": 18, "choice_id": ' + '"tgl", "choice_text": "Tagalog/Filipino"}, {"order": 19, "choice_id": "tur", "choice_text": "Turkish"}, ' + '{"order": 20, "choice_id": "vie", "choice_text": "Vietnamese"}, {"order": 21, "choice_id": "zul", ' + '"choice_text": "Zulu"}, {"order": 22, "choice_id": "xxx", "choice_text": "Other"}], "selector": "MA", ' + '"country_iso": "us", "question_id": "f15663d012244d5fa43f5784f7bd1898", "language_iso": "eng", ' + '"question_text": "Which language(s) do you speak fluently at home? (Select all that apply)", ' + '"question_type": "MC", "task_score": 15.835933296975051, "task_count": 147, "p": 0.780484657143325}, ' + '{"selector": "SL", "validation": {"patterns": [{"message": "Must enter a valid zip code: XXXXX", ' + '"pattern": "^[0-9]{5}$"}]}, "country_iso": "us", "question_id": "543de254e9ca4d9faded4377edab82a9", ' + '"language_iso": "eng", "configuration": {"max_length": 5, "min_length": 5, "type": "TE"}, ' + '"question_text": "What is your zip code?", "question_type": "TE", "task_score": 3.9114103408096685, ' + '"task_count": 4116, "p": 0.19277649769949645}, {"selector": "SL", "validation": {"patterns": [{' + '"message": "Must input digits only (range between 1 and 999999)", "pattern": "^[0-9]{1,6}$"}]}, ' + '"country_iso": "us", "question_id": "9ffacedc92584215912062a9d75338fa", "language_iso": "eng", ' + '"configuration": {"max_length": 6, "type": "TE"}, "question_text": "What is your current annual ' + 'household income before taxes (in USD)?", "question_type": "TE", "task_score": 2.4630414657197686, ' + '"task_count": 3267, "p": 0.12139266046727369}, {"choices": [{"order": 0, "choice_id": "0", ' + '"choice_text": "Employed full-time"}, {"order": 1, "choice_id": "1", "choice_text": "Employed ' + 'part-time"}, {"order": 2, "choice_id": "2", "choice_text": "Self-employed full-time"}, {"order": 3, ' + '"choice_id": "3", "choice_text": "Self-employed part-time"}, {"order": 4, "choice_id": "4", ' + '"choice_text": "Active military"}, {"order": 5, "choice_id": "5", "choice_text": "Inactive ' + 'military/Veteran"}, {"order": 6, "choice_id": "6", "choice_text": "Temporarily unemployed"}, ' + '{"order": 7, "choice_id": "7", "choice_text": "Full-time homemaker"}, {"order": 8, "choice_id": "8", ' + '"choice_text": "Retired"}, {"order": 9, "choice_id": "9", "choice_text": "Student"}, {"order": 10, ' + '"choice_id": "10", "choice_text": "Disabled"}], "selector": "SA", "country_iso": "us", "question_id": ' + '"b546d26651f040c9a6900ffb126e7d69", "language_iso": "eng", "question_text": "What is your current ' + 'employment status?", "question_type": "MC", "task_score": 1.6940674222375414, "task_count": 1134, ' + '"p": 0.0834932559027201}, {"choices": [{"order": 0, "choice_id": "0", "choice_text": "No"}, ' + '{"order": 1, "choice_id": "1", "choice_text": "Yes, Mexican"}, {"order": 2, "choice_id": "2", ' + '"choice_text": "Yes, Puerto Rican"}, {"order": 3, "choice_id": "3", "choice_text": "Yes, Cuban"}, ' + '{"order": 4, "choice_id": "4", "choice_text": "Yes, Salvadoran"}, {"order": 5, "choice_id": "5", ' + '"choice_text": "Yes, Dominican"}, {"order": 6, "choice_id": "6", "choice_text": "Yes, Guatemalan"}, ' + '{"order": 7, "choice_id": "7", "choice_text": "Yes, Colombian"}, {"order": 8, "choice_id": "8", ' + '"choice_text": "Yes, Honduran"}, {"order": 9, "choice_id": "9", "choice_text": "Yes, Ecuadorian"}, ' + '{"order": 10, "choice_id": "10", "choice_text": "Yes, Argentinian"}, {"order": 11, "choice_id": "11", ' + '"choice_text": "Yes, Peruvian"}, {"order": 12, "choice_id": "12", "choice_text": "Yes, Nicaraguan"}, ' + '{"order": 13, "choice_id": "13", "choice_text": "Yes, Spaniard"}, {"order": 14, "choice_id": "14", ' + '"choice_text": "Yes, Venezuelan"}, {"order": 15, "choice_id": "15", "choice_text": "Yes, Panamanian"}, ' + '{"order": 16, "choice_id": "16", "choice_text": "Yes, Other"}], "selector": "SA", "country_iso": "us", ' + '"question_id": "7d452b8069c24a1aacbccbf767910345", "language_iso": "eng", "question_text": "Are you of ' + 'Hispanic, Latino, or Spanish origin?", "question_type": "MC", "task_score": 1.6342156553005878, ' + '"task_count": 2516, "p": 0.08054342118687588}], "special_questions": [{"selector": "HIDDEN", ' + '"country_iso": "xx", "question_id": "1d1e2e8380ac474b87fb4e4c569b48df", "language_iso": "xxx", ' + '"question_type": "HIDDEN"}, {"selector": "HIDDEN", "country_iso": "xx", "question_id": ' + '"2fbedb2b9f7647b09ff5e52fa119cc5e", "language_iso": "xxx", "question_type": "HIDDEN"}, {"selector": ' + '"HIDDEN", "country_iso": "xx", "question_id": "4030c52371b04e80b64e058d9c5b82e9", "language_iso": ' + '"xxx", "question_type": "HIDDEN"}, {"selector": "HIDDEN", "country_iso": "xx", "question_id": ' + '"a91cb1dea814480dba12d9b7b48696dd", "language_iso": "xxx", "question_type": "HIDDEN"}, {"selector": ' + '"HIDDEN", "task_count": 40.0, "task_score": 0.45961204566189584, "country_iso": "us", "question_id": ' + '"59f39a785f154752b6435c260cbce3c6", "language_iso": "eng", "question_text": "Core-Based Statistical ' + 'Area (2020)", "question_type": "HIDDEN"}], "consent_questions": []}' + ) + instance = UpkQuestionResponse.model_validate_json(s) + + assert isinstance(instance, UpkQuestionResponse) diff --git a/tests/models/legacy/test_user_question_answer_in.py b/tests/models/legacy/test_user_question_answer_in.py new file mode 100644 index 0000000..253c46e --- /dev/null +++ b/tests/models/legacy/test_user_question_answer_in.py @@ -0,0 +1,304 @@ +import json +from decimal import Decimal +from uuid import uuid4 + +import pytest + + +class TestUserQuestionAnswers: + """This is for the GRS POST submission that may contain multiple + Question+Answer(s) combinations for a single GRS Survey. It is + responsible for making sure the same question isn't submitted + more than once per submission, and other "list validation" + checks that aren't possible on an individual level. + """ + + def test_json_init( + self, + product_manager, + user_manager, + session_manager, + wall_manager, + user_factory, + product, + session_factory, + utc_hour_ago, + ): + from generalresearch.models.thl.session import Session, Wall + from generalresearch.models.thl.user import User + from generalresearch.models import Source + from generalresearch.models.legacy.questions import ( + UserQuestionAnswers, + ) + + u: User = user_factory(product=product) + + s1: Session = session_factory( + user=u, + wall_count=1, + started=utc_hour_ago, + wall_req_cpi=Decimal("0.00"), + wall_source=Source.GRS, + ) + assert isinstance(s1, Session) + w1 = s1.wall_events[0] + assert isinstance(w1, Wall) + + instance = UserQuestionAnswers.model_validate_json( + json.dumps( + { + "product_id": product.uuid, + "product_user_id": u.product_user_id, + "session_id": w1.uuid, + "answers": [ + {"question_id": uuid4().hex, "answer": ["a", "b"]}, + {"question_id": uuid4().hex, "answer": ["a", "b"]}, + ], + } + ) + ) + assert isinstance(instance, UserQuestionAnswers) + + def test_simple_validation_errors( + self, product_manager, user_manager, session_manager, wall_manager + ): + from generalresearch.models.legacy.questions import ( + UserQuestionAnswers, + ) + + with pytest.raises(ValueError): + UserQuestionAnswers.model_validate( + { + "product_user_id": f"test-user-{uuid4().hex[:6]}", + "session_id": uuid4().hex, + "answers": [{"question_id": uuid4().hex, "answer": ["a", "b"]}], + } + ) + + with pytest.raises(ValueError): + UserQuestionAnswers.model_validate( + { + "product_id": uuid4().hex, + "session_id": uuid4().hex, + "answers": [{"question_id": uuid4().hex, "answer": ["a", "b"]}], + } + ) + + # user is validated only if a session_id is passed + UserQuestionAnswers.model_validate( + { + "product_id": uuid4().hex, + "product_user_id": f"test-user-{uuid4().hex[:6]}", + "answers": [{"question_id": uuid4().hex, "answer": ["a", "b"]}], + } + ) + + with pytest.raises(ValueError): + UserQuestionAnswers.model_validate( + { + "product_id": uuid4().hex, + "product_user_id": f"test-user-{uuid4().hex[:6]}", + "session_id": uuid4().hex, + } + ) + + with pytest.raises(ValueError): + UserQuestionAnswers.model_validate( + { + "product_id": uuid4().hex, + "product_user_id": f"test-user-{uuid4().hex[:6]}", + "session_id": uuid4().hex, + "answers": [], + } + ) + + with pytest.raises(ValueError): + answers = [ + {"question_id": uuid4().hex, "answer": ["a"]} for i in range(101) + ] + UserQuestionAnswers.model_validate( + { + "product_id": uuid4().hex, + "product_user_id": f"test-user-{uuid4().hex[:6]}", + "session_id": uuid4().hex, + "answers": answers, + } + ) + + with pytest.raises(ValueError): + UserQuestionAnswers.model_validate( + { + "product_id": uuid4().hex, + "product_user_id": f"test-user-{uuid4().hex[:6]}", + "session_id": uuid4().hex, + "answers": "aaa", + } + ) + + def test_no_duplicate_questions(self): + # TODO: depending on if or how many of these types of errors actually + # occur, we could get fancy and just drop one of them. I don't + # think this is worth exploring yet unless we see if it's a problem. + from generalresearch.models.legacy.questions import ( + UserQuestionAnswers, + ) + + consistent_qid = uuid4().hex + with pytest.raises(ValueError) as cm: + UserQuestionAnswers.model_validate( + { + "product_id": uuid4().hex, + "product_user_id": f"test-user-{uuid4().hex[:6]}", + "session_id": uuid4().hex, + "answers": [ + {"question_id": consistent_qid, "answer": ["aaa"]}, + {"question_id": consistent_qid, "answer": ["bbb"]}, + ], + } + ) + + assert "Don't provide answers to duplicate questions" in str(cm.value) + + def test_allow_answer_failures_silent( + self, + product_manager, + user_manager, + session_manager, + wall_manager, + product, + user_factory, + utc_hour_ago, + session_factory, + ): + """ + There are many instances where suppliers may be submitting answers + manually, and they're just totally broken. We want to silently remove + that one QuestionAnswerIn without "loosing" any of the other + QuestionAnswerIn items that they provided. + """ + from generalresearch.models.thl.session import Session, Wall + from generalresearch.models.thl.user import User + from generalresearch.models.legacy.questions import ( + UserQuestionAnswers, + ) + + u: User = user_factory(product=product) + + s1: Session = session_factory(user=u, wall_count=1, started=utc_hour_ago) + assert isinstance(s1, Session) + w1 = s1.wall_events[0] + assert isinstance(w1, Wall) + + data = { + "product_id": product.uuid, + "product_user_id": u.product_user_id, + "session_id": w1.uuid, + "answers": [ + {"question_id": uuid4().hex, "answer": ["aaa"]}, + {"question_id": f"broken-{uuid4().hex[:6]}", "answer": ["bbb"]}, + ], + } + # load via .model_validate() + instance = UserQuestionAnswers.model_validate(data) + assert isinstance(instance, UserQuestionAnswers) + + # One of the QuestionAnswerIn items was invalid, so it was dropped + assert 1 == len(instance.answers) + + # Confirm that this also works via model_validate_json + json_data = json.dumps(data) + instance = UserQuestionAnswers.model_validate_json(json_data) + assert isinstance(instance, UserQuestionAnswers) + + # One of the QuestionAnswerIn items was invalid, so it was dropped + assert 1 == len(instance.answers) + + assert instance.user is None + instance.prefetch_user(um=user_manager) + assert isinstance(instance.user, User) + + +class TestUserQuestionAnswerIn: + """This is for the individual Question+Answer(s) that may come back from + a GRS POST. + """ + + def test_simple_validation_errors(self): + from generalresearch.models.legacy.questions import ( + UserQuestionAnswerIn, + ) + + with pytest.raises(ValueError): + UserQuestionAnswerIn.model_validate( + {"question_id": f"test-{uuid4().hex[:6]}", "answer": ["123"]} + ) + + with pytest.raises(ValueError): + UserQuestionAnswerIn.model_validate({"answer": ["123"]}) + + with pytest.raises(ValueError): + UserQuestionAnswerIn.model_validate( + {"question_id": uuid4().hex, "answer": [123]} + ) + + with pytest.raises(ValueError): + UserQuestionAnswerIn.model_validate( + {"question_id": uuid4().hex, "answer": [""]} + ) + + with pytest.raises(ValueError): + UserQuestionAnswerIn.model_validate( + {"question_id": uuid4().hex, "answer": [" "]} + ) + + with pytest.raises(ValueError): + UserQuestionAnswerIn.model_validate( + {"question_id": uuid4().hex, "answer": ["a" * 5_001]} + ) + + with pytest.raises(ValueError): + UserQuestionAnswerIn.model_validate( + {"question_id": uuid4().hex, "answer": []} + ) + + def test_only_single_answers(self): + from generalresearch.models.legacy.questions import ( + UserQuestionAnswerIn, + ) + + for qid in { + "2fbedb2b9f7647b09ff5e52fa119cc5e", + "4030c52371b04e80b64e058d9c5b82e9", + "a91cb1dea814480dba12d9b7b48696dd", + "1d1e2e8380ac474b87fb4e4c569b48df", + }: + # This is the UserAgent question which only allows a single answer + with pytest.raises(ValueError) as cm: + UserQuestionAnswerIn.model_validate( + {"question_id": qid, "answer": ["a", "b"]} + ) + + assert "Too many answer values provided" in str(cm.value) + + def test_answer_item_limit(self): + from generalresearch.models.legacy.questions import ( + UserQuestionAnswerIn, + ) + + answer = [uuid4().hex[:6] for i in range(11)] + with pytest.raises(ValueError) as cm: + UserQuestionAnswerIn.model_validate( + {"question_id": uuid4().hex, "answer": answer} + ) + assert "List should have at most 10 items after validation" in str(cm.value) + + def test_disallow_duplicate_answer_values(self): + from generalresearch.models.legacy.questions import ( + UserQuestionAnswerIn, + ) + + answer = ["aaa" for i in range(5)] + with pytest.raises(ValueError) as cm: + UserQuestionAnswerIn.model_validate( + {"question_id": uuid4().hex, "answer": answer} + ) |
