कोड योगदान में रोड़ा: `test::nginx`

API7.ai

November 17, 2022

OpenResty (NGINX + Lua)

टेस्टिंग सॉफ्टवेयर डेवलपमेंट का एक आवश्यक हिस्सा है। टेस्ट ड्रिवेन डेवलपमेंट (TDD) की अवधारणा इतनी लोकप्रिय हो गई है कि लगभग हर सॉफ्टवेयर कंपनी में टेस्टिंग कार्य को संभालने के लिए एक QA (गुणवत्ता आश्वासन) टीम होती है।

टेस्टिंग OpenResty की गुणवत्ता और महान प्रतिष्ठा का आधार है, लेकिन यह OpenResty के ओपन-सोर्स प्रोजेक्ट्स का सबसे उपेक्षित हिस्सा भी है। कई डेवलपर्स हर दिन lua-nginx-module का उपयोग करते हैं और कभी-कभी एक फ्लेम ग्राफ चलाते हैं, लेकिन कितने लोग टेस्ट केस चलाएंगे? यहां तक कि कई OpenResty-आधारित ओपन-सोर्स प्रोजेक्ट्स भी टेस्ट केस के बिना हैं। लेकिन टेस्ट केस और निरंतर एकीकरण के बिना एक ओपन-सोर्स प्रोजेक्ट विश्वसनीय नहीं है।

हालांकि, वाणिज्यिक कंपनियों के विपरीत, अधिकांश ओपन-सोर्स प्रोजेक्ट्स में समर्पित सॉफ्टवेयर टेस्टिंग इंजीनियर नहीं होते हैं, तो वे अपने कोड की गुणवत्ता कैसे सुनिश्चित करते हैं? जवाब सरल है: "टेस्ट ऑटोमेशन" और "निरंतर एकीकरण", जिसमें मुख्य बिंदु ऑटोमेटिव और निरंतर हैं, दोनों को OpenResty ने अधिकतम सीमा तक हासिल किया है।

OpenResty के पास 70 ओपन सोर्स प्रोजेक्ट्स हैं, और उनके यूनिट टेस्टिंग, इंटीग्रेशन टेस्टिंग, परफॉर्मेंस टेस्टिंग, मॉक टेस्टिंग, फज़ टेस्टिंग, और अन्य कार्यभार को समुदाय के योगदानकर्ताओं द्वारा पूरी तरह से मैन्युअल रूप से हल करना चुनौतीपूर्ण है। इसलिए, OpenResty ने शुरुआत में ही ऑटोमेशन टेस्टिंग में अधिक निवेश किया। यह अल्पावधि में प्रोजेक्ट को धीमा कर सकता है, लेकिन यह कहा जा सकता है कि इस क्षेत्र में निवेश लंबे समय में बहुत लाभदायक है। इसलिए जब मैं अन्य इंजीनियर्स से OpenResty की टेस्टिंग लॉजिक और टूलसेट के बारे में बात करता हूं, तो वे आश्चर्यचकित हो जाते हैं।

आइए OpenResty की टेस्टिंग फिलॉसफी के बारे में बात करते हैं।

अवधारणा

test::nginx OpenResty टेस्टिंग आर्किटेक्चर का केंद्र है, जिसका उपयोग OpenResty स्वयं और आसपास के lua-resty लाइब्रेरीज़ द्वारा टेस्ट सेट को व्यवस्थित और लिखने के लिए किया जाता है। यह एक उच्च सीमा वाला टेस्टिंग फ्रेमवर्क है। इसका कारण यह है कि, सामान्य टेस्टिंग फ्रेमवर्क्स के विपरीत, test::nginx एसर्शन्स पर आधारित नहीं है और Lua भाषा का उपयोग नहीं करता है, जिसके लिए डेवलपर्स को test::nginx को सीखने और उपयोग करने के लिए शुरू से ही सीखना पड़ता है और टेस्टिंग फ्रेमवर्क्स के अपने ज्ञान को उलटना पड़ता है।

मैं कई OpenResty योगदानकर्ताओं को जानता हूं जो OpenResty में C और Lua कोड सबमिट कर सकते हैं लेकिन test::nginx का उपयोग करके टेस्ट केस लिखना मुश्किल लगता है। उन्हें या तो यह नहीं पता था कि उन्हें कैसे लिखना है या टेस्ट फेल होने पर उन्हें कैसे ठीक करना है। इसलिए, मैं test::nginx को कोड योगदान में एक बाधा कहता हूं।

test::nginx Perl, डेटा-ड्रिवेन, और DSL (डोमेन-स्पेसिफिक लैंग्वेज) को जोड़ता है। एक ही टेस्ट केस सेट के लिए, पैरामीटर्स और पर्यावरण चर को नियंत्रित करके, आप यादृच्छिक निष्पादन, कई पुनरावृत्तियों, मेमोरी लीक डिटेक्शन, स्ट्रेस टेस्टिंग, आदि जैसे विभिन्न प्रभाव प्राप्त कर सकते हैं।

इंस्टालेशन और उदाहरण

test::nginx का उपयोग करने से पहले, आइए इसे कैसे इंस्टॉल करें यह सीखें।

OpenResty सिस्टम में सॉफ्टवेयर इंस्टालेशन के लिए, केवल आधिकारिक CI इंस्टालेशन विधि सबसे समय पर और प्रभावी है; अन्य तरीकों से इंस्टालेशन में हमेशा विभिन्न समस्याएं आती हैं। इसलिए मैं आपको आधिकारिक तरीकों को संदर्भ के रूप में लेने की सलाह देता हूं, जहां आप test::nginx के इंस्टालेशन और उपयोग को भी पा सकते हैं। इसमें चार चरण हैं।

  1. सबसे पहले, Perl के पैकेज मैनेजर cpanminus को इंस्टॉल करें।
  2. फिर, cpanm के माध्यम से test::nginx इंस्टॉल करें।
sudo cpanm --notest Test::Nginx IPC::Run > build.log 2>&1 || (cat build.log && exit 1)
  1. इसके बाद, नवीनतम स्रोत कोड को क्लोन करें।
git clone https://github.com/openresty/test-nginx.git
  1. अंत में, Perl के prove कमांड के माध्यम से test-nginx लाइब्रेरी को लोड करें और /t डायरेक्टरी में टेस्ट केस सेट को चलाएं।
prove -Itest-nginx/lib -r t

इंस्टालेशन के बाद, आइए test::nginx में सबसे सरल टेस्ट केस को देखें। निम्नलिखित कोड आधिकारिक दस्तावेज़ीकरण से अनुकूलित है, और मैंने सभी कस्टमाइज़्ड कंट्रोल पैरामीटर्स को हटा दिया है।

use Test::Nginx::Socket 'no_plan'; run_tests(); __DATA__ === TEST 1: set Server --- config location /foo { echo hi; more_set_headers 'Server: Foo'; } --- request GET /foo --- response_headers Server: Foo --- response_body hi

हालांकि test::nginx Perl में लिखा गया है और मॉड्यूल्स में से एक के रूप में काम करता है, क्या आप उपरोक्त टेस्ट में Perl या किसी अन्य भाषा में कुछ देख सकते हैं? हां। ऐसा इसलिए है क्योंकि test::nginx लेखक का अपना Perl में DSL का कार्यान्वयन है, जो विशेष रूप से NGINX और OpenResty के टेस्टिंग के लिए अमूर्त है।

इसलिए, जब हम पहली बार इस तरह के टेस्ट को देखते हैं, तो हम शायद इसे समझ नहीं पाते हैं। लेकिन चिंता न करें; आइए उपरोक्त टेस्ट केस का विश्लेषण करें।

सबसे पहले, use Test::Nginx::Socket;, यह Perl में लाइब्रेरीज़ को संदर्भित करने का तरीका है, जैसे Lua में require। यह हमें यह भी याद दिलाता है कि test::nginx एक Perl प्रोग्राम है।

दूसरी पंक्ति, run_tests(); test::nginx में एक Perl फ़ंक्शन है, टेस्टिंग फ्रेमवर्क का प्रवेश बिंदु। यदि आप test::nginx में किसी अन्य Perl फ़ंक्शन को कॉल करना चाहते हैं, तो उन्हें run_tests से पहले रखा जाना चाहिए ताकि वे मान्य हों।

तीसरी पंक्ति में __DATA__ एक फ्लैग है जो इंगित करता है कि इसके नीचे सब कुछ टेस्ट डेटा है, और Perl फ़ंक्शन इस फ्लैग से पहले पूरे होने चाहिए।

अगला === TEST 1: set Server, टेस्ट केस का शीर्षक है, जो इस टेस्ट के उद्देश्य को दर्शाता है, और इसमें एक टूल है जो स्वचालित रूप से अंदरूनी नंबरिंग को व्यवस्थित करता है।

--- config NGINX कॉन्फ़िगरेशन फ़ील्ड है। उपरोक्त मामले में, हमने NGINX कमांड्स का उपयोग किया है, Lua नहीं, और यदि आप Lua कोड जोड़ना चाहते हैं, तो आप इसे यहां content_by_lua जैसे डायरेक्टिव के साथ करेंगे।

--- request का उपयोग एक टर्मिनल को अनुरोध भेजने के लिए किया जाता है, जिसके बाद GET /foo है, जो अनुरोध की विधि और URI को निर्दिष्ट करता है।

--- response_headers, जिसका उपयोग प्रतिक्रिया हेडर्स का पता लगाने के लिए किया जाता है। निम्नलिखित Server: Foo इंगित करता है कि प्रतिक्रिया हेडर्स में header और value अवश्य प्रकट होने चाहिए। यदि नहीं, तो टेस्ट फेल हो जाएगा।

अंतिम --- response_body, जिसका उपयोग संबंधित बॉडी का पता लगाने के लिए किया जाता है। निम्नलिखित hi वह स्ट्रिंग है जो प्रतिक्रिया बॉडी में अवश्य प्रकट होनी चाहिए; यदि नहीं, तो टेस्ट फेल हो जाएगा।

ठीक है, यहां, सबसे सरल टेस्ट केस का विश्लेषण समाप्त हो गया है। इसलिए, टेस्ट केस को समझना OpenResty-संबंधित डेवलपमेंट कार्य को पूरा करने के लिए एक पूर्वापेक्षा है।

अपने टेस्ट केस लिखें

अगला, हाथों-हाथ टेस्टिंग में आने का समय है। याद है कि हमने पिछले लेख में Memcached सर्वर का परीक्षण कैसे किया था? हां; हमने resty का उपयोग करके मैन्युअल रूप से अनुरोध भेजा था, जो निम्नलिखित कोड द्वारा दर्शाया गया है।

resty -e 'local memcached = require "resty.memcached" local memc, err = memcached:new() memc:set_timeout(1000) -- 1 sec local ok, err = memc:connect("127.0.0.1", 11212) local ok, err = memc:set("dog", 32) if not ok then ngx.say("failed to set dog: ", err) return end local res, flags, err = memc:get("dog") ngx.say("dog: ", res)'

लेकिन क्या मैन्युअल रूप से भेजना पर्याप्त स्मार्ट नहीं है? कोई चिंता नहीं। test::nginx सीखने के बाद हम मैन्युअल टेस्ट को ऑटोमेटेड में बदलने का प्रयास कर सकते हैं। उदाहरण के लिए:

use Test::Nginx::Socket::Lua::Stream; run_tests(); __DATA__ === TEST 1: basic get and set --- config location /test { content_by_lua_block { local memcached = require "resty.memcached" local memc, err = memcached:new() if not memc then ngx.say("failed to instantiate memc: ", err) return end memc:set_timeout(1000) -- 1 sec local ok, err = memc:connect("127.0.0.1", 11212) local ok, err = memc:set("dog", 32) if not ok then ngx.say("failed to set dog: ", err) return end local res, flags, err = memc:get("dog") ngx.say("dog: ", res) } } --- stream_config lua_shared_dict memcached 100m; --- stream_server_config listen 11212; content_by_lua_block { local m = require("memcached-server") m.go() } --- request GET /test --- response_body dog: 32 --- no_error_log [error]

इस टेस्ट केस में, मैंने --- stream_config, --- stream_server_config, --- no_error_log को कॉन्फ़िगरेशन आइटम्स के रूप में जोड़ा है, लेकिन वे मूल रूप से समान हैं, अर्थात

टेस्ट्स के डेटा और टेस्टिंग को सरल बनाया गया है ताकि कॉन्फ़िगरेशन को अमूर्त करके पठनीयता और विस्तारणीयता को बेहतर बनाया जा सके।

यही वह जगह है जहां test::nginx अन्य टेस्टिंग फ्रेमवर्क्स से मूलभूत रूप से अलग है। यह DSL एक दोधारी तलवार है क्योंकि यह टेस्ट लॉजिक को स्पष्ट और आसानी से विस्तारणीय बनाता है। हालांकि, यह सीखने की लागत को बढ़ाता है, जिससे आपको टेस्ट केस लिखने से पहले नए सिंटैक्स और कॉन्फ़िगरेशन को फिर से सीखना पड़ता है।

सारांश

test::nginx शक्तिशाली है, लेकिन कई बार यह आपके परिदृश्य के लिए हमेशा उपयुक्त नहीं हो सकता है। तितली को पहिये पर क्यों तोड़ें? OpenResty में, आपके पास एसर्शन-स्टाइल टेस्टिंग फ्रेमवर्क busted का उपयोग करने का विकल्प भी है। busted resty के साथ मिलकर एक कमांड लाइन टूल बन जाता है, और कई टेस्टिंग आवश्यकताओं को पूरा कर सकता है।

अंत में, मैं आपके लिए एक प्रश्न छोड़ता हूं। क्या आप इस टेस्ट को Memcached के लिए स्थानीय रूप से चला सकते हैं? यदि आप एक नया टेस्ट केस जोड़ सकते हैं, तो यह बहुत अच्छा होगा।