<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    Selenium Grid 安裝

      Selenium Grid
      Selenium Grid允許同時并行地、在不同的環境上運行多個測試任務。這里主要演示一下怎么使用Selenium Grid。
      準備
      1、需要兩臺機子
      2、兩臺機子分別安裝好JDK環境
      3、兩臺機子需要從 http://code.google.com/p/selenium/downloads/list下載selenium-server-standalone-*.jar包
      開始:
      Grid需要一臺機子做為主節點,然后其它機子做為子節點連接到這個主節點上來。所以首先要啟動主節點。
      啟動主節點
      選一臺機子做為主節點。打開命令行,cd至selenium-server-standalone-*.jar包的目錄下,然后用下面的命令啟動主節點服務:
      java -jar selenium-server-standalone-2.24.1.jar -role hub
      默認啟動默認端口為4444。如果要改這個端口,可以再上面的命令后面加上 -port XXXX。啟動完后,你可以用瀏覽 器    打開 http://localhost:4444/grid/console 這個網址查看主節點的狀態。
      啟動完主節點之后,要做的就是啟動子節點。
      啟動子節點:
      先另一臺機子做為子節點。同樣打開命令行,cd至selenium-server-standalone-*.jar包的目錄下,然后用下面的命令啟動次節點服務:
      java -jar selenium-server-standalone-2.24.1.jar  -role  node  -hubhttp://192.168.4.124:4444/grid/register
      其中192.168.4.124為主節點機子的ip地址,可以使用ipconfig命令在命令行查看得到。上面命令默認啟動5555端口,可使用-port 更改。
      啟動完成連接到主節點后,可以在主節點機子上 ,http://localhost:4444/grid/console網址查看到這個子節點狀態。使用同樣的方法,可以鏈接其它的子節點。
      運行一個簡單的例子:
      上面已經把grid弄成功了,現在我們用Grid來運行一個很簡單的例子。代碼如下:
    import java.net.MalformedURLException;
    import java.net.URL;
    import org.openqa.selenium.WebDriver;
    import org.openqa.selenium.remote.DesiredCapabilities;
    import org.openqa.selenium.remote.RemoteWebDriver;
    public class GridTest {
    /**
    * @throws MalformedURLException
    */
    public static void main(String[] args) throws MalformedURLException {
    DesiredCapabilities test = DesiredCapabilities.firefox();
    WebDriver dr = new RemoteWebDriver(new URL("http://192.168.4.137:5555/wd/hub"),test);
    dr.get("http://www.baidu.com");
    }
    }
      在主節點機子上運行上面的代碼,你可以在次節點機子上看到firefox瀏覽器被啟動,然后打開了www.baidu.com這個網址。
      值得注意的是:
      WebDriver dr = new RemoteWebDriver(newURL("http://192.168.4.137:5555/wd/hub"),test);
      這一句中的192.168.4.137為次節點的ip地址。

    posted @ 2014-03-28 11:14 順其自然EVO 閱讀(264) | 評論 (0)編輯 收藏

    Android軟件測試的日志文件抓取簡介

    1、log文件分類簡介
      實時打印 的主要有: logcat main , logcat radio , logcat events , tcpdump ,還有高通平臺的還會有QXDM 日志
      狀態信息 的有: adb shell cat /proc/kmsg , adb shell dmesg , adb shell dumpstate , adb shell dumpsys , adb bugreport ,工程模式等
      2、LOG抓取詳解
      l  實時打印
      adb logcat -b main -v time>app.log  打印應用程序的 log
      adb logcat -b radio -v time> radio.log 打印射頻相關的 log , SIM STK 也會在里面, modem 相關的ATcommand 等,當然跟 QXDM 差的很遠了。
      adb logcat -b events -v time  打印系統事件的日志,比如觸屏事件。。。
      tcpdump 是很有用的,對于 TCP/IP 協議相關的都可以使用這個來抓, adb shell tcpdump -s 10000 -w /sdcard/capture.pcap ,比如抓 mms 下載的時候的 UA profile , browser 上網的時候,使用 proxy 的 APN 下載, streaming 的相關內容包括 UA profile 等。
      最后是高通平臺的 QXDM ,不管是不是 Android ,只要使用高通芯片,都會對它很熟悉,當然了,不是高通的芯片就不用提它了。這個不多講,內容豐富,射頻,電話,上網, ... 凡是高通提供的解決方案,這個都可以抓。(QXDM 的 LOG抓取方法請參考 QPST、 QXDM的基本使用說明及作用 )
      l  狀態信息
      o   bugreport (命令 adb bugreport>bugreport.log) 。里面包含有 dmesg , dumpstate 和 dumpsys 。
      o   dumpstate 是系統狀態信息,里面比較全,包括手機當前的內存信息、 cpu 信息、 logcat 緩存, kernel 緩存等等。
      o     adb shell dumpsys 這個是關于系統 service 的內容都在這個里面,這個命令還有更詳盡的用法,比如 adb shell dumpsys meminfo system 是查看 system 這個 process 的內存信息。
      o   kmsg 抓取
      adb shell cat /proc/kmsg > kmsg.txt ,打開后查 msm_kgsl 字段
      說明:用于檢索用 printk 生成的內核消息。任何時刻只能有一個具有超級用戶權限的進程可以讀取這個文件。也可以用系統調用 syslog 檢索這些消息。通常使用工具 dmesg 或守護進程 klogd 檢索這些消息。 proc 是一個內存文件系統 , 每次讀文件 kmsg 實際是內核內部的循環緩沖區 , 每讀過后 , 循環緩沖區的東西就被認為已經處理過了 ( 也就是變成無效內容 ), 所以你再次讀為空是很正常的 為什么會這樣處理呢 , 循環緩沖區大小有限 , 內核又隨時可能往里面寫東西 , 所以這樣處理很正常 . 你去查一下 /proc/kmsg 的信息有沒有跟系統日志關聯 , 如果有的話 ,你就可以讀日志文件
      o   dmsg 抓取
      adb shell dmesg > dmesg.txt
      說明: dmesg 用來顯示開機信息, kernel 會將開機信息存儲在 ring buffer 中。您若是開機時來不及查看信息,可利用 dmesg 來查看。 dmesg 是 kernel 的 log ,凡是跟 kernel 相關的,比如 driver 出了問題(相機,藍牙, usb ,啟動,等等)開機信息亦保存在 /var/log 目錄中,名稱為 dmesg 的文件里。 more /var/log/dmesg
      o   工程模式下 log 的抓取
      對于 Apollo 手機請撥打 *#*#8888#*#* , 然后勾選相應的 LOG 。待測試結束后,通過 SD 卡導出 LOG 到PC.
      3、Log分析:
      Get Log from Android System
      adb bugreport > bugreport.txt
      copy bugreport to the current directory.
      bugreport 里面包含了各種 log 信息 , 大部分 log 也可以通過直接運行相關的程序來直接獲得 .
      步驟如下 :
      1.adb shell 2. 進入相關工具程式的目錄 3. 執行相關程式 4. 得到相關信息
      下面以輸出進程信息為例 1.adb shell 2. 輸入 ps -P 3. 可以看到相關進程信息
      Log Archive Analysis
      1.bugreport
      bugreport 記錄 android 啟動過程的 log, 以及啟動后的系統狀態 , 包括進程列表,內存信息, VM 信息等等到.

     2.bugreport 結構分析
      (1)dumpstate
      MEMORY INFO
      獲取該 log: 讀取文件 /proc/meminfo
      系統內存使用狀態
      CPU INFO
      獲取該 log: 執行 /system/bin/top -n 1 -d 1 -m 30 -t
      系統 CPU 使用狀態
      PROCRANK
      獲取該 log: 執行 /system/bin/procrank
      執行 /system/xbin/procrank 后輸出的結果 , 查看一些內存使用狀態
      VIRTUAL MEMORY STATS
      獲取該 log: 讀取文件 /proc/vmstat
      虛擬內存分配情況
      vmalloc 申請的內存則位于 vmalloc_start ~ vmalloc_end 之間,與物理地址沒有簡單的轉換關系,雖然在邏輯上它們也是連續的,但是在物理上它們不要求連續。
      VMALLOC INFO
      獲取該 log: 讀取文件 /proc/vmallocinfo
      虛擬內存分配情況
      SLAB INFO
      獲取該 log: 讀取文件 /proc/slabinfo
      SLAB 是一種內存分配器 . 這里輸出該分配器的一些信息
      ZONEINFO
      獲取該 log: 讀取文件 /proc/zoneinfo
      zone info
      SYSTEM LOG( 需要著重分析 )
      獲取該 log: 執行 /system/bin/logcat -v time -d *:v
      會輸出在程序中輸出的 Log, 用于分析系統的當前狀態
      VM TRACES
      獲取該 log: 讀取文件 /data/anr/traces.txt
      因為每個程序都是在各自的 VM 中運行的 , 這個 Log 是現實各自 VM 的一些 traces
      EVENT LOG TAGS
      獲取該 log: 讀取文件 /etc/event-log-tags
      EVENT LOG
      獲取該 log: 執行 /system/bin/logcat -b events -v time -d *:v
      輸出一些 Event 的 log
      RADIO LOG
      獲取該 log: 執行 /system/bin/logcat -b radio -v time -d *:v
      顯示一些無線設備的鏈接狀態 , 如 GSM , PHONE,STK(Satellite Tool Kit)…
      NETWORK STATE
      獲取該 log: 執行 /system/bin/netcfg ( 得到網絡鏈接狀態 )
      獲取該 log: 讀取文件 /proc/net/route ( 得到路由狀態 )
      顯示網絡鏈接和路由
      SYSTEM PROPERTIES
      獲取該 log: 參考代碼實現
      顯示一些系統屬性 , 如 Version,Services,network…
      KERNEL LOG
      獲取該 log: 執行 /system/bin/dmesg
      顯示 Android 內核輸出的 Log
      KERNEL WAKELOCKS
      獲取該 log: 讀取文件 /proc/wakelocks
      內核對一些程式和服務喚醒和休眠的一些記錄
      KERNEL CPUFREQ
      (Linux kernel CPUfreq subsystem) Clock scaling allows you to change the clock speed of the CPUs on the fly.
      This is a nice method to save battery power, because the lower the clock speed is, the less power the CPU consumes.
      PROCESSES
      獲取該 log: 執行 ps -P
      顯示當前進程
      PROCESSES AND THREADS
      獲取該 log: 執行 ps -t -p -P
      顯示當前進程和線程
      LIBRANK
      獲取該 log: 執行 /system/xbin/librank
      剔除不必要的 library
      BINDER FAILED TRANSACTION LOG
      獲取該 log: 讀取文件 /proc/binder/failed_transaction_log
      BINDER TRANSACTION LOG
      獲取該 log: 讀取文件 /proc/binder/transaction_log
      BINDER TRANSACTIONS
      獲取該 log: 讀取文件 /proc/binder/transactions
      BINDER STATS
      獲取該 log: 讀取文件 /proc/binder/stats
      BINDER PROCESS STATE
      獲取該 log: 讀取文件 /proc/binder/proc/*
      bind 相關的一些狀態
      FILESYSTEMS
      獲取該 log: 執行 /system/bin/df
      主要文件的一些容量使用狀態 (cache,sqlite,dev…)
      PACKAGE SETTINGS
      獲取該 log: 讀取文件 /data/system/packages.xml
      系統中 package 的一些狀態 ( 訪問權限 , 路徑 …) ,類似 Windows 里面的一些 lnk 文件吧 .
      PACKAGE UID ERRORS
      獲取該 log: 讀取文件 /data/system/uiderrors.txt
      錯誤信息
      KERNEL LAST KMSG LOG
      最新 kernel message log
      LAST RADIO LOG
      最新 radio log
      KERNEL PANIC CONSOLE LOG
      KERNEL PANIC THREADS LOG
      控制臺 / 線程的一些錯誤信息 log
      BACKLIGHTS
      獲取該 log: 獲取 LCD brightness 讀 /sys/class/leds/lcd-backlight/brightness
      獲取該 log: 獲取 Button brightness 讀 /sys/class/leds/button-backlight/brightness
      獲取該 log: 獲取 Keyboard brightness 讀 /sys/class/leds/keyboard-backlight/brightness
      獲取該 log: 獲取 ALS mode 讀 /sys/class/leds/lcd-backlight/als
      獲取該 log: 獲取 LCD driver registers 讀 /sys/class/leds/lcd-backlight/registers
      獲取相關亮度的一些信息
      (2)build.prop
      VERSION INFO 輸出下列信息
      當前時間
      當前內核版本 : 可以讀取文件 (/proc/version) 獲得
      顯示當前命令 : 可以讀取文件夾 (/proc/cmdline) 獲得
      顯示系統 build 的一些屬性 : 可以讀取文件 (/system/build.prop) 獲得
      輸出系統一些屬性
      gsm.version.ril-impl
      gsm.version.baseband
      gsm.imei
      gsm.sim.operator.numeric
      gsm.operator.alpha

     (3)dumpsys
      執行 /system/bin/dumpsys 后可以獲得這個 log.
      經常會發現該 log 輸出不完整 , 因為代碼里面要求該工具最多只執行 60ms, 可能會導致 log 無法完全輸出來 .
      可以通過修改時間參數來保證 log 完全輸出 .
      信息 :
      Currently running services
      DUMP OF SERVICE services-name(running)
      Log Code Analysis
      Site: .\frameworks\base\cmds\dumpstate\
      相關 Log 程序的代碼可以從上面目錄獲取
      Log Analysis Experience
      分析步驟
      1. 查看一些版本信息
      確認問題的系統環境
      2. 查看 CPU/MEMORY 的使用狀況
      看是否有內存耗盡 ,CPU 繁忙這樣的背景情況出現 .
      3. 分析 traces
      因為 traces 是系統出錯以后輸出的一些線程堆棧信息 , 可以很快定位到問題出在哪里 .
      4. 分析 SYSTEM LOG
      系統 Log 詳細輸出各種 log, 可以找出相關 log 進行逐一分析
      實例分析
      下面分析我寫的一個測試例子 , 在 OnCreate 做一個死循環 , 這樣主線程會被鎖住,在按下硬件的 Back 之后會出現 ANR 的錯誤 .
      在 traces 中發現該程序的堆棧信息如下 :
    —– pid 20597 at 2010-03-15 01:29:53 —–
    Cmd line: com.android.test
    DALVIK THREADS:
    "main" prio=5 tid=3 TIMED_WAIT
    | group="main" sCount=1 dsCount=0 s=N obj=0x2aac6240 self=0xbda8
    | sysTid=20597 nice=0 sched=0/0 cgrp=default handle=1877232296
    at java.lang.VMThread.sleep(Native Method)
    at java.lang.Thread.sleep(Thread.java:1306)
    at java.lang.Thread.sleep(Thread.java:1286)
    at android.os.SystemClock.sleep(SystemClock.java:114)
    at com.android.test.main.onCreate(main.java:20)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2512)
    at android.app.ActivityThread.access$2200(ActivityThread.java:119)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1863)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4363)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    at dalvik.system.NativeStart.main(Native Method)
    "Binder Thread #2" prio=5 tid=11 NATIVE
    | group="main" sCount=1 dsCount=0 s=N obj=0x2fb7c260 self=0×143860
    | sysTid=20601 nice=0 sched=0/0 cgrp=default handle=1211376
    at dalvik.system.NativeStart.run(Native Method)
    "Binder Thread #1" prio=5 tid=9 NATIVE
    | group="main" sCount=1 dsCount=0 s=N obj=0x2fb7c1a0 self=0x14c980
    | sysTid=20600 nice=0 sched=0/0 cgrp=default handle=1207920
    at dalvik.system.NativeStart.run(Native Method)
    "Signal Catcher" daemon prio=5 tid=7 RUNNABLE
    | group="system" sCount=0 dsCount=0 s=N obj=0x2fb7a1e8 self=0x126cc0
    | sysTid=20599 nice=0 sched=0/0 cgrp=default handle=1269048
    at dalvik.system.NativeStart.run(Native Method)
    "HeapWorker" daemon prio=5 tid=5 VMWAIT
    | group="system" sCount=1 dsCount=0 s=N obj=0x2e31daf0 self=0x135c08
    | sysTid=20598 nice=0 sched=0/0 cgrp=default handle=1268528
    at dalvik.system.NativeStart.run(Native Method)
    —– end 20597 —–
      該文件的堆棧結構從下往上進行分析
      (1) 棧底 at dalvik.system.NativeStart.run(Native Method)
      系統為當前的 task( 應用程式 ) 啟動一個專用的虛擬機
      (2) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2459)
      Activity Services 是在后臺負責管理 Activity, 它此時將測試例子的 Activity 啟動起來了
      (3)at com.android.test.main.onCreate(main.java:20)
      啟動測試程序
      (4) 棧頂 at java.lang.VMThread.sleep(Native Method)
      線程被 sleep 掉了 , 所以無法響應用戶 , 出現 ANR 錯誤 .
      上面是對一個非常簡單的問題的分析 .
      如果遇到比較復雜的問題還需要詳細分析 SYSTEM LOG.
      1. 比如網絡異常 , 要通過 SYSTEM LOG 里面輸出的網絡鏈接信息來判斷網絡狀態
      2. 數據傳輸 , 網絡鏈接等耗時的操作需要分析 SYSTEM LOG 里面 ActivityManager 的響應時間
      3…

    posted @ 2014-03-28 11:12 順其自然EVO 閱讀(207) | 評論 (0)編輯 收藏

    如何一步一步從 QA 到 EP

      兩三年以前,和友人談到 QA(軟件質量保證) 這個行業,還有 QA 這個團隊的未來,就有了一絲憂慮。而現在,終于有機會實踐一下自己之前的想法,在這里分享給大家。
      從我有限的從業經驗到現在,經歷了很多次軟件開發模式的變化,這些變化,或因為跟風,或因為有切實的問題要解決,總之始終處于各種不同的嘗試的路上。QA 團隊從最早的強調流程,到后來強調開發技術,搞自動化測試,再后來又開始做敏捷和持續集成,這條發展的路上,對自己的要求不斷變高的同時,也伴隨著一個組織和團隊發展的魔咒。
      組織發展魔咒
      這個發展的魔咒更像是一個循環,可能開始于任何一個環節。
      例如,公司負責技術的高層,沒來由的認為,測試和質量保證并不重要。這個判斷會慢慢滲透到技術團隊的各個角落,導致測試工程師,乃至測試團隊的其他角色,例如SQA,未來發展的空間會被壓縮,而壓縮發展空間的結果就是留不住人、招不到人。一方面相關工作的經驗技能要求越來越高,一方面可見的天花板又擺在那里。于是整個 QA 團隊都成了別人眼中的 「低技術」團隊,不論真的低技術還是別人以為的低技術,這種印象都很要命,為了擺脫這種印象,大家需要做點東西來證明自己,于是各種自動化測試框架、平臺、系統,紛紛出現,殊不知此時,QA 團隊和整個公司的價值已經慢慢的不一致了,自己關起門跟自己玩,成了普遍現象之后,在公司高層看來,他會覺得自己的 「QA 團隊并不重要」的判斷被證明了,因為沒有任何明確的證據表明,QA 團隊與公司愿景和計劃之間的直接聯系。
      可怕么?在很多軟件研發組織中,這是現實存在的循環。
      說起來我們的實踐,確實打破了這個循環,說起來好笑,我們解救 QA 團隊的方式,就是徹底取消這個團隊。但是反過來講,只有殺死「QA 團隊」,才能真正的解放「QA 工程師們」,真正解放整個軟件研發過程。
      一些基本的價值觀
      這個事情,就要從一些最基本的價值觀說起。
      比如,人總要對自己做的事負責。當然做了漂亮的事情,誰都希望頭上有光環,但是做了丑事,也要能忍受得了羞辱。之為 「吃自己的狗食」,而老式的軟件開發分段流程,等于鼓勵上游做的錯事,下游來擦屁股,于是上游頤指氣使,下游低三下四,這種頤指氣使和低三下四還能傳導,于是的于是,最下游的一個環節,就是公認的受氣包了。暫不說效率和質量,從最基本的做事方法的角度,似乎也有些欠妥。我們這一條怎么落地呢,就是改組研發團隊,建立 Owner 制度。一個項目的 Owner,就像一個項目的 CEO,大事小情都要關注,從產品到開發,從測試到運維,總之一個項目的成敗,都需要 Owner 來操心,項目外的人,都是他的資源。相應的,項目也變得和平臺無關,而與特性有關,每個項目組都會涉及到幾個平臺的設計、開發工作。
      還比如,給質量一個明確的標準。做質量工作或者測試的人,都會有強迫癥,總覺得哪里不對勁,還得狠狠的回歸一遍,又一遍。可其實大家都知道質量是沒有個確定的標準說好還是壞的,那怎么確定質量呢?我們稱作 「質量體現在造成實際的影響上」,也就是說,一個嚴重的問題,如果沒造成影響,或很輕微,那就不嚴重。而一個輕微問題,如果影響面很廣,例如有 1000 萬用戶都看見了,那就不輕微。
      又比如,交付一個完美產品還是建立一個快速召回的機制?我們確實真的想每時每刻都能交付一個完美無暇的產品,但那不可能。特別是在互聯網行業,跟傳統的電信、醫療、航空航天的產品迭代有天壤之別,一個完美產品用一年做出來,市場可能早就變了天了。但不完美就有質量風險和代價,為了平衡這一點,我們必須建立一個快速召回缺陷產品的機制,甚至能讓用戶在發現缺陷之前,就用上了新版本。
      有了這幾條價值觀,我們就大概知道開發過程改進的方向,以及做事情的原則了。那我們做了什么呢?我們組建了 EP 團隊。
      EP 是什么
      說到這里,EP 這個詞才第一次出現,這個詞的內涵之豐富,可能需要仔細說說。
      我最早看到 EP 這個詞,是在當時還是 Google EP 團隊成員的 James Wittaker 寫的那一個有名的 「How Google Test」的系列博客中,內容我就不轉述了,很多人都讀過。
      EP 是 Engineering Productivity 的縮寫,工程生產力的意思,這個團隊,就是給整個大技術團隊,甚至整個公司提高工作效率的。通俗直白的說,就是一個工具團隊。因為工欲善其事、必先利其器,不要小看工具團隊,某些程度上來講,一個產品隨著市場的變化可能很快凋亡,而一個好的工程工具,生命力要強得多,比如,開發語言其實就是最基本的工程工具了。那么,對一個公司,或者說交付團隊來講,怎么衡量工程生產力的高低呢?這個衡量方式其實就決定了「EP團隊」的工作方向。我們自己定義的工程生產力從低到高的定義是這樣的:1)質量,這是最基礎的指標,什么都不行,也要保證質量過關,否則一個產品連生存的可能都沒有。2)同等質量水平下,追求速度。質量過關了,就要看迭代速度了,你比競爭對手快,你就能活下來。3)同等質量和速度下,工程師的幸福感。如果質量也過關了,速度也快,但是大家過得很苦,天天加班,重復勞動,看不到未來,這也不行。幸福是什么?對我們來說,就是不被反復的簡單問題所困擾,該自動的都自動,自動不是說一定快,但是一定省心,這里的幸福就是省心,有精力去關注更多的有意義的事情,而不是每天處理簡單重復的問題。4)同等質量和速度,也有幸福感,再看成長。工程師們有沒有感受到成長?不斷的解決問題或開發產品,感受到的是重復勞動還是成長?其實前三點都做到了,第四點一定是有的。

     EP 做什么
      我們回頭說 EP 團隊,EP 團隊也有自己的人生理想,那就是一個三部曲:替、教、獨立。
      第一個是替的階段,其實就是比較老式的開發過程,我替你測試、替你上線、替你運維。
      這個階段,完全不符合我們「吃狗食」那一條價值觀,按照狗食法則,一個人自己設計開發編碼,當然要自己測試,自己寫的代碼 bug 多要一遍遍回歸,這個苦果自己不吃誰來吃?但沒辦法,大多數程序員在如何測試自己的程序方面沒有受過什么訓練,為了盡快發布產品,只能替,但這個替的時間要越短越好,盡快進入下一個階段,教。
      第二個是教,就是教技術團隊的其他成員,如何測試自己的程序,如何構造環境、構造數據,如何部署和運維自己的產品。這里的自己做,并不是回到蠻荒時期,例如創業初期只有一個程序員的時候,他當然是自己開發自己測試自己部署,但我們到了第二階段的自己做,是自己規范的做,通過我們提供的相對完善和規范的工具做。我們就處于這個階段的初期。
      第三個階段是獨立,獨立是說 EP 團隊從一個替人做事的下游團隊,到一個教人做事的教練團隊,真正進化為一個提供技術服務的產品團隊。這個產品團隊的產品,大多數應該是以一個標準化的、健壯的服務的形式,而不是人力資源的形式,提供給其他團隊的。當然這是我們的理想,能否達到或者是否切合實際,還需要時間來觀察。
      EP 團隊和整個技術團隊的關系
      從這三個階段的描述中,多多少少都提到一些 EP 團隊和整個技術團隊或整個公司的關系,那這個關系是什么呢?
      前面提過,我們不希望是個下游替人收尾的團隊,我們也有「吃狗食」這樣的原則,所以我想到一個比喻,來說明 EP 團隊和其他技術團隊的關系。
      我們都知道有一個行業叫做汽車制造業,他們遵循一定的規范和標準,還能巧妙的將創意和標準結合在一起,制造出一些工業奇跡,這些汽車被賣給各式各樣的人,汽車企業并不關心他們的產品用在什么地方,不過他們又發明了一種叫做 4S 店的東西,用來給那些工業奇跡定期維護、修理、還可以收集市場反饋以便改進產品。
      還有另一個行業叫做物流業,他們的目的就是將貨物從一個地方運到另一個地方,這種空間的轉移,就是他們為客戶創造的價值。在這過程中,他們會利用到汽車制造業產出的汽車,但他們不太關心汽車本身的標準、設計細節,他們只是使用,他們關心的是使用成本、維修方便。出問題,他們會找 4S 店。
      這兩個行業之間的交集是汽車,汽車制造業的價值是制造出好的汽車,物流業的價值是貨物的到達,汽車制造業不關心你的貨物的目的地,物流業不關心他的汽車的制造工藝。但汽車制造業會很關心你怎么用這個汽車,以及積極的幫助你保養,而物流業也會很關心這個車費不費油,好不好開。
      說到這里,你可能已經看明白 EP 團隊和其他技術團隊的關系了:EP 團隊就像汽車制造業,提供高效、低耗的工具;產品技術團隊就像物流業,使用工具,快速前進,創造用戶價值。他們之間互相依賴,卻又彼此獨立。
      EP 都有誰
      了解了 EP 和周圍團隊的關系之后,來看看我們的 EP 團隊的角色和成員。
      我們的 EP 團隊,大致分成如下幾個角色(而實際上的工作是混合的,之所以要分開成角色,主要是從招聘的角度出發):
      SED,Software Engineer in DevOps。顧名思義,這個角色首先是個軟件開發工程師,其次,面向的領域是 DevOps,DevOps 的概念我們就不必多講了,在實際工作中,SED 工程師是個真正的多面手,他們可能今天在開發一個 Linux server 的自動化上線和回滾的工具,明天就要設計或優化 CDN 的部署,后天又要解決一個 Windows 平臺編譯加速問題,還有還有一個自動性能 benchmark 工具等著他來開發。這個角色目前我們只有兩位,而且這個角色的工程師是最難招聘的,因為新人,或者很小的公司出來的人,很少有受過系統的訓練或有比較先進的軟件工程思想,而從大公司出來的人,已經被大公司條塊分割的工作方式同化,一般只擅長一個領域,而對跨界的或者不懂,或者沒興趣。所以這個崗位的工程師,都是有成熟公司工作經驗的 Geek 型的人。
      SA,System Admin。系統工程師,和很多公司的運維工程師很想像,實際上我們現在的狀態,做的事情也和大多數公司的運維工程師一樣,處理監控,優化服務部署等等,但不一樣的是我們的目標是將絕大多數應用層面的運維工作交還給開發團隊,所以我們在不斷的將監控系統改造為友好的,自助的,也不斷的將各位上線部署類的工作做成自動的,現在已經有了很多成果,我們的 SA 主要精力可以放在系統以及更底層的部分了。
      TE,Testing Engineer。測試工程師,其實這個稱呼有點名不符實,我們的唯一一位測試工程師,主要的工作其實是發布和迭代控制,要保證整個交付團隊的迭代節奏,例如在代碼上拉發布分支、觸發發布事件、監控數據等等工作,這個工作要求非常精確,又很繁瑣,因此和 SED 工程師有非常多的交互,他們負責將這個過程自動化。這里插入介紹一下我們的發布過程,可能大家會更理解為什么還有個「發布工程師」:
      我們有三個發布 Channel:Beta、RC、Release,作用各有不同。例如 Beta Channel,主要用于一些新特性的提前發布,這里面可能會多少有點缺陷,所以一定要控制人數,并且是那些喜歡嘗鮮的用戶,他們會用的比較徹底。而 Beta Channel,可能每天都有版本更新,會有一些用戶喜歡跟著 Beta 版。而這些新的特性如果用戶反饋不錯,并且沒有什么嚴重的問題,就會進入最近一次 RC(Release Candidate),這個量就很大了,大概能占到我們每日活躍用戶的十分之一到五分之一,這里面的功能在沒有意外的話,就是正式發布的功能了,需要注意的是,不是每個 Beta 都會變成 RC。而 RC 在發布幾天之后,如果一切正常,就會切換為 Release,Release Channel 一般會在一天之內,讓絕大多數活躍用戶升級完畢,這個時候,如果程序有 bug,影響就非常大了。
      Venders,外包測試團隊。我們有大約六七個人的外包測試團隊(on-site),主要負責我們主要產品的人工驗收測試。我們對外包測試團隊的工作方式也有一個設想,就是一個項目剛開始的時候,外包測試團隊應當是先上很多人,然后隨著 SED 的介入,讓自動化程度加強,慢慢人少下來,直到下一個新項目開始。但這個設想在國內想實現,卻沒那么容易,主要有幾個原因:1)國內的外包測試的工程師,通常是技術和經驗都比較初級的人來做,外包測試成了一個門檻低天花板也低的行業,技術和經驗缺乏,導致進入新項目以后沒辦法非??斓纳鲜?,而有經驗有能力的人,很快就會脫離外包行業;2)外包測試的公司,人才儲備不足,很少有人力資源池,都是有需求,現從市場上招,或從競爭對手那里挖,有的人都沒見過,就派到客戶那邊來面試,這也導致了沒辦法幾個月就撤下來,因為他沒辦法跟候選人簽合同。這兩個客觀原因,我們也比較無奈,所以我們的外包測試團隊基本上還是長期 on-site。
      UOE,user operation engineer。用戶運營工程師,這個崗位很多人不太容易理解,一般用戶運營人員都是跟內容啊、用戶打交道的,就像貼吧管理員就是典型的用戶運營人員,那為什么要有個運營工程師呢?這個我們是跟硅谷的 Dropbox 學習的。因為在日常工作中,我們發現有想當一部分用戶的反饋,不論是新功能的需求還是缺陷,都是技術性很強的,如果你能做到第一時間和用戶做深入的,技術含量較高的溝通,從解決問題的成功率上會高很多,而如果你反饋一個技術問題,總是過了幾天才有技術人員跟你聯系的話,你可能配合排查問題的愿望會小很多。基于這個思路,我們增加了這個角色,同時他們還負責一些運營過程中使用的工具和平臺類的研發??赡軙腥藛栠@個角色為什么會在 EP 團隊?其實仔細分析一下用戶運營的工作,會發現他們處理的對象是一個個用戶提交的 ticket,這非常像 test case,不同之處是一個是用戶事后提交,一個是事先設計,分別保證了優先級和完備性,因此結合起來,對提高質量是非常有益的事情。
      EP 團隊的工作方式與面臨的挑戰
      上面這幾個角色,就組成了我們的 EP 團隊,這樣的一個團隊,這樣的一個能力構成,就有了一些鮮明的特點,例如:
      1)沒人管的事情我們管,支持所有團隊。公司內部雖然分成了很多個團隊,但是很多技術問題是找不到人負責的,例如,一個簡單的內部數據統計腳本,或者一個發布內容到 CDN 的 CMS,等等。這些事情基本都會由 EP 團隊接過來。
      2)做事情沒有計劃。這個特點可能很多人會覺得匪夷所思,甚至不能接受,但實際上這跟 EP 團隊的工作有關系,比如汽車 4S 店,有多少車禍的汽車要修理,多少人為損壞的車要修理,怎么做計劃?實際上是遇山開道、遇水搭橋。外部的市場的變化、內部的技術人員的變化,都會有不斷的瓶頸出現,而 EP 就要快速發現并解決這些瓶頸,直到發現下一個瓶頸,這個過程沒辦法有詳盡的長期的計劃。而替代的是使用目標管理的方式,我們公司內部所有團隊都會用一種叫做 OKR(Objective and Key Result)的方式來做管理,簡單的說,就是設定目標,然后評估完成度。EP 團隊的目標大致有兩個方向,一個我們叫做 「Smoothly & Fast」,就是讓一切跑通做順的能力,還有一個就是「實現自助」,能讓其他團隊的成員,不管是技術還是非技術背景,都能自己通過我們的工具完成任務。
      這些特點看起來很不錯,但是實際上帶來的問題也非常多,例如:
      沒有成就感。因為所有人都是你的需求方,這個感覺實在是不太好,另一個角度講,很多研發工程師會覺得開發一個對外的產品比較有成就感,對內的總覺得沒意思。這個問題要解決,其實就要靠所謂的「工程師文化」來解決,國內長期以來在職業化上有一些不好的習慣,其實能發明工具的人都是大師,開發語言就是工具,操作系統也是工具,真正的牛人,都在做各式各樣的工具。能幫助別人成功的人,是最成功的。
      還有,就是脫離實際。很多人做工具,怎么炫怎么做,流行什么做什么,要么就大而全,這還是好的,更多的時候是想的大而全,半年做不出來。整個公司的價值取向是一致的,特別是小公司,容不得這種炫技一般的工作方式。所以我有一句話,叫做「自 high 無價值」,什么叫「自 high」?就是自己跟自己玩,玩的很高興。
      還有一個問題,就是招聘困難。這個在 SED 的工作職責部分提過,就不展開了。因為招聘困難,我們就要考慮怎么培養這樣的人才,所以我們有一個方法論,叫做「要改進,先體驗」,因為很多 EP 的成員是要改進工作過程的,但是怎么改,不是所有人都能搞定,這依賴于大量的經驗積累,對經驗不足的人,很簡單,就是讓他去做。要提高研發效率,找到痛點,那就先去做一個月研發;要去改進測試過程,提高效率,就去做一個月測試。一個技術和思維方式都很不錯,只是經驗少的人,經過一個月的體驗,能提出非常多的、而其他人已經麻木了的改進點,并推動實施。
      再有,依賴整個團隊的成熟度。不是說有了 EP 這樣一個團隊,整個公司的效率和工作模式就會有大幅度提升,因為一個汽車再好,你開的方向不對,也到不了目的地?,F實中存在著非常多缺乏責任感的 Owner,很多人覺得,我寫完代碼編譯通過了,丟給測試組就行了,沒我的事了,這樣的想法大有人在,所以從成立 EP 團隊,到整個公司的生產力真正被提高,中間不只是提供工具這么簡單,還有一系列的指導和訓練的工作。
      Why we can & why you can
      最后,關于我們為什么能做這個事情,我們也有一些總結:
      1)創業團隊。創業團隊就是短小精悍,精力集中,沒有太多無謂的紛擾,快速交付產品快速迭代是主要的工作方式。
      2)從第一天開始堅持自由和責任的工程文化。從創始人開始,很堅持這種工程文化,有什么樣的 leader 就有什么樣的團隊,所以大家接收和擁抱 EP 的工作模式,也非常快。
      雖然上述這兩條很多公司沒有,但不代表做不成這個事情,在我看來,只要具備下面幾條,想做成 EP 的工作,就并不難。
      1)互聯網行業?;ヂ摼W行業有一個非常好的,區別于以往其他行業的特點,就是你的產品在物理上是自己控制的,提供的只是服務,這非常有利于快速迭代,因為傳統行業不可能做到。
      2)快速變化的業務模式。這不是說我們自己要快速變化,而是業務模式和市場不斷變化,來推著我們前進。只有業務模式的快速發展,才對生產力有不斷更高的要求。
      3)有改變的決心。這個說起來有點虛了,但也很重要,因為 EP 這樣的工作模式會有陣痛,例如團隊的重組、轉型,都會影響到一部分人的利益,特別是團隊的管理者,而這些中高層管理者,也確實有能力阻止變革。但坦白的說,很多時候你不主動改變,到了客觀環境推動你不得不變的時候,到最后就成了被淘汰的人了。我還有一句話,叫做「組織結構決定工作模式」,意思是說,很多工作模式的出現,是因為組織結構的需要。反過來說,在你的組織里很多很好的工作模式推動不下去,或者效果很差,你就要看看你的組織結構是不是有問題。比如兩個本來應該緊密合作的團隊,一直合作不好,互相鄙視,你想簡化流程,最后流程越做越多,大家都在壘墻,那你就要看看兩個團隊共同的老板,是不是級別太高了。
      4)對團隊成員的高標準。前面我提過,我們 EP 團隊的大部分是 Geek 型的人,Geek 這個詞在英語里是一種很高的評價。只有一個技術和經驗都非常豐富的人,才能勝任 EP 這樣的工作,所以要堅持不懈的雇傭一流的人才,人不夠,可以抓大放小,但絕不能有二流、三流的人在團隊里。


    posted @ 2014-03-28 11:06 順其自然EVO 閱讀(940) | 評論 (0)編輯 收藏

    Flask-Testing 單元測試

    準備
      1. 安裝pip
      2. 安裝Flask
      3. 安裝Flask-Testing (ver:>=0.4.1)
      測試程序
    #coding=utf8
    from flask import Flask,jsonify
    from flask.ext.testing import TestCase
    import unittest
    app = Flask(__name__)
    @app.route("/ajax/")
    def some_json():
    return jsonify(success=False)
    class TestViews(TestCase):
    def create_app(self):
    app.config['TESTING'] = True
    return app
    def test_some_json(self):
    response = self.client.get("/ajax/")
    '''''
    判斷還回的JSON對像是不是{'success':True}
    '''
    self.assertEquals(response.json, dict(success=True))
    if  __name__ =='__main__':
    unittest.main()
      執行測試結果:
    python tests.py

    posted @ 2014-03-28 11:02 順其自然EVO 閱讀(253) | 評論 (0)編輯 收藏

    Linux學習—fork用法

     linux當中可以使用fork函數創建一個新進程
      #include <unistd.h>
      pid_t fork(void);
      返回值:子進程中返回0,父進程中返回子進程ID,出錯返回-1
      在fork調用之后,子進程獲得父進程數據空間、堆和棧的副本,但是并不共享這些存儲空間部分。
      fork的一個特性是父進程的所有打開文件描述符都被復制到子進程中。父、子進程的每個相同的打開描述符共享一個文件表項。
      這種共享文件的方式使父、子進程對同一文件使用了一個文件偏移量。
      fork有兩種用法:
      (1)一個父進程希望復制自己,使父、子進程同時執行不同的代碼段。例如,父進程等待客戶端的服務請求,然后fork一個子進程處理這個請求,自己則繼續等待下一個服務請求。
     ?。?)一個進程要執行一個不同的操作。fork一個子進程之后立馬調用exec
      fork的特殊應用:fork兩次可以避免僵死進程,(僵死進程是指一個已經終止,但是其父進程尚未對其進行善后處理的進程),父進程先fork一個子進程,子進程繼續fork一個孫子進程,然后就直接退出。這樣,父進程就可以很快的wait到子進程,釋放其資源,不需要阻塞,繼續自己的操作;而孫子進程交由了init進程托管,執行自己的操作而不用擔心了。
      ps:write函數不帶緩沖,標準I/O庫是帶緩沖的,如果標準輸出練到終端設備,則它是行緩沖的,否則它是全緩沖的

    posted @ 2014-03-27 17:07 順其自然EVO 閱讀(277) | 評論 (0)編輯 收藏

    數據庫中的事務、存儲過程和觸發器的簡單使用

     什么是事務(Transaction)
      指訪問并可能更新數據庫中各種數據項的一個程序執行單元(unit)--也就是由多個sql語句組成,必須作為一個整體執行
      這些sql語句作為一個整體一起向系統提交,要么都執行、要么都不執行
      語法步驟:
      開始事務:BEGIN TRANSACTION
      事務提交:COMMIT TRANSACTION
      事務回滾:ROLLBACK TRANSACTION
      判斷某條語句執行是否出錯:
      全局變量@@ERROR;
      @@ERROR只能判斷當前一條T-SQL語句執行是否有錯,為了判斷事務中所有T-SQL語句是否有錯,我們需要對錯誤進行累計;
      例:SET @errorSum=@errorSum+@@error
      存儲過程---就像數據庫中運行方法(函數)
      和C#里的方法一樣,由存儲過程名/存儲過程參數組成/可以有返回結果。
      前面學的if else/while/變量 等,都可以在存儲過程中使用
      優點:
      執行速度更快
      允許模塊化程序設計
      提高系統安全性
      減少網絡流通量
      系統存儲過程
      由系統定義,存放在master數據庫中
      名稱以“sp_”開頭或”xp_”開頭
      自定義存儲過程
      由用戶在自己的數據庫中創建的存儲過程
      系統存儲過程
      說明
      sp_databases
      列出服務器上的所有數據庫。
      sp_helpdb
      報告有關指定數據庫或所有數據庫的信息
      sp_renamedb
      更改數據庫的名稱
      sp_tables
      返回當前環境下可查詢的對象的列表
      sp_columns
      回某個表列的信息
      sp_help
      查看某個表的所有信息
      sp_helpconstraint
      查看某個表的約束
      sp_helpindex
      查看某個表的索引
      sp_stored_procedures
      列出當前環境中的所有存儲過程。  sp_password
      添加或修改登錄帳戶的密碼。
      sp_helptext
      顯示默認值、未加密的存儲過程、用戶定義的存儲過程、觸發器或視圖的實際文本。
      定義存儲過程的語法
      CREATE  PROC[EDURE]  存儲過程名
      @參數   數據類型 = 默認值 OUTPUT,
      @參數n  數據類型 = 默認值 OUTPUT
      AS
      SQL語句
      參數說明:
      參數可選
      參數分為輸入參數、輸出參數
      輸入參數允許有默認值
      EXEC  過程名  [參數]
      觸發器是一種特殊類型的存儲過程,它不同于前面介紹過的一般的存儲過程。
      一般的存儲過程通過存儲過程名稱被直接調用,而觸發器主要是通過事件進行觸發而被執行。
      觸發器是一個功能強大的工具,在表中數據發生變化時自動強制執行。觸發器可以用于SQL Server約束、默認值和規則的完整性檢查,還可以完成難以用普通約束實現的復雜功能。
      那究竟何為觸發器?在SQL Server里面也就是對某一個表的一定的操作,觸發某種條件,從而執行的一段程序。觸發器是一個特殊的存儲過程。
      常見的觸發器有三種:分別應用于Insert , Update , Delete 事件
      常用語法
    CREATE TRIGGER triggerName ON Table
    for UPDATE|INSERT|DELETE
    AS
    begin
    end
      觸發器-更新
    CREATE TRIGGER testForFun ON dbo.Category
    for UPDATE
    AS
    begin
    select * from book
    end
    update Category set c_name = 'Android2' where c_id=3
      觸發器-刪除
    CREATE TRIGGER testForDel ON dbo.Category
    for delete
    AS
    begin
    select * from book
    end
    delete Category set c_name = 'Android2' where c_id=3

    posted @ 2014-03-27 17:06 順其自然EVO 閱讀(471) | 評論 (0)編輯 收藏

    Selenium實例:Python登錄WebQQ

     selenium范例:python登錄webqq
    from selenium import webdriver
    from selenium.common.exceptions import NoSuchElementException
    from selenium.webdriver.common.keys import Keys
    import time
    from pprint import pprint
    username="username"
    passwd="password"
    class WebQQ:
    def __init__(self):
    self.browser = webdriver.Firefox() # Get local session of firefox
    self.browser.set_window_position(800,0)
    self.browser.get("http://web.qq.com") # Load page
    while True:
    try:
    elem = self.browser.find_element_by_id("alloy_icon_app_50_3") # Find the qq button
    elem.click()
    print "click qq button"
    break
    except NoSuchElementException:
    print "element not loaded yet"
    time.sleep(0.1) # Let the page load, will be added to the API
    def login(self):
    self.browser.switch_to_frame("ifram_login")
    # Find the loginState option
    elem = self.browser.find_element_by_id("loginState")
    elem.click()
    print "click loginState"
    # choose hidden state
    elem = self.browser.find_element_by_id("loginStatePanel")
    elems = elem.find_elements_by_class_name("statePanel_li")
    elems[0].click()
    print "choose online state"
    # login
    elem = self.browser.find_element_by_id("u") # user name
    elem.send_keys(username)
    elem = self.browser.find_element_by_id("p") # passwd
    elem.send_keys(passwd)
    elem = self.browser.find_element_by_id("login_button") # login button
    elem.click()
    def main():
    webqq = WebQQ()
    webqq.login()
    if __name__ == "__main__":
    main()

    posted @ 2014-03-27 17:04 順其自然EVO 閱讀(721) | 評論 (0)編輯 收藏

    Windows 7上QTP11破解方法

     QTP11破解方法:
      1.準備文件
      注冊機mgn-mqt82.exe
      2.安裝QTP11
      3.運行注冊機mgn-mqt82.exe
      如果運行mgn-mqt82.exe 沒有反應-,請注意關掉暫時關掉殺毒軟件
      根據路徑“C:\Program Files\Common Files\Mercury Interactive\License Manager\lservrc”
      以上方法是網上9.2 的破解方法, 以下是11的破解方法,同時適用QTP10.0,只不過以下方法破解10.0可以無時間限制,而11只能適用15天或者30天 。如果11的License到期了,可以使用此方法再次重新破解,不需要重裝,即可再次使用15-30天。
      1.找到lservrc文件,將它剪切至桌面,或者是別的文件夾,注意一定是剪切。
      2.運行QTP 11
      或者
      4.點擊Install License,選擇Seat license,因為QTP10和QTP11都采用了兩種license ,單機版的和服務器并發的,
      我們破解的是單機許可。
      5.點擊下一步
      用記事本打開前面注冊機生產的lservrc文件,會看到有4個許可密鑰,復制任意一條密鑰,從開頭至#號結束,
      粘貼至窗口的文本框中,點擊下一步,如果提示該密鑰已經安裝,何以選擇另外一條安裝,如果仍然提示,
      請注意檢查第三步lservrc文件是否移走了,
      點擊下一步
      6.安裝完成,啟動QTP
      插件破解方法:
      1.net插件安裝
      將下載下來的插件進行解壓縮到目錄qtp92-net-addin中,進入該目錄,點擊setup.exe,直接默認安裝,到最后,把“立即注冊”取消,安裝完畢。重新啟動qtp,會發現插件已經存在,但是顯示灰色,不可選,狀態為no license。
      2.破解.net插件
     ?。?)進入注冊表,將HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive備份
      (2)找到HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\WPF,將名稱為“默認”的鍵值修改為“QTCoreAddin”,再將“ProgID”的鍵值修改為 “Mercury.AddinBaseObj”
     ?。?)找到HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\WinForms,將將名稱為“默認”的鍵值修改為“QTCoreAddin”,再將“ProgID”的鍵值修改為 “Mercury.AddinBaseObj”
     ?。?)關閉注冊表,重啟軟件,發現.net和wpf插件的狀態變為built in狀態,經過驗證,可以正常使用
      3.破解java插件
     ?。?)進入注冊表,將HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive備份
     ?。?)找到HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\java,將名稱為“默認”的鍵值修改為“QTCoreAddin”,再將“ProgID”的鍵值修改為 “Mercury.AddinBaseObj”
     ?。?)關閉注冊表,重啟軟件,發現java插件的狀態變為built in狀態,經過驗證,可以正常使用
      4.破解webservice插件
      (1)進入注冊表,將HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive備份
     ?。?)找到HKEY_LOCAL_MACHINE\SOFTWARE\Mercury Interactive\QuickTest Professional\Add-In Manager\webservice,將名稱為“默認”的鍵值修改為“QTCoreAddin”,再將“ProgID”的鍵值修改為 “Mercury.AddinBaseObj”
     ?。?)關閉注冊表,重啟軟件,發現webservice插件的狀態變為built in狀態,經過驗證,可以正常使用
      QTP11 30天試用期到后的破解新方法
      1. 找到 C:\ProgramData\SafeNet Sentinel 目錄,更名或者刪除.2. 找到 QTP11 安裝目錄下bin子目錄,如 C:\Program Files (x86)\HP\QuickTest Professional\bin,執行.(win7以管理員權限執行.) 此方法win7 64bit 可行. 以上兩點無法破解,個人用的是win 7 家庭普通版,64bit的,但運行instdemo.exe 后,C:\ProgramData\SafeNet Sentinel重新生成Sentinel RMS Development Kit,重啟qtp 11還是提示還有30天后過期~!

    posted @ 2014-03-27 16:56 順其自然EVO 閱讀(343) | 評論 (0)編輯 收藏

    Android游戲開發cocos-2d中精靈的動作測試

      安裝好cocos-2d之后,創建一個好一個Android項目,在項目中復制下載好的Cocos-2d包中的cocos2d-master\cocos2d-android\libs中的所有文件,全部粘貼到Android項目中的libs目錄下,右擊libs中的cocos2d-android.jar,然后builder path操作。這樣就創建好了游戲項目。
      以下是一個入門的小程序:
      MainActivity.java代碼:
    import org.cocos2d.layers.CCScene;
    import org.cocos2d.nodes.CCDirector;
    import org.cocos2d.opengl.CCGLSurfaceView;
    import android.os.Bundle;
    import android.app.Activity;
    public class MainActivity extends Activity {
    //Cocos2d引擎將會把圖形繪制到View對象上
    private CCGLSurfaceView view = null;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    view = new CCGLSurfaceView(this);
    setContentView(view);
    //得到CCDirector對象
    CCDirector director = CCDirector.sharedDirector();
    //設置游戲的相關屬性
    //設置當前游戲程序中所使用的view對象
    director.attachInView(view);
    //設置是否顯示FPS值
    director.setDisplayFPS(true);
    //設置游戲渲染一幀所需要的時間
    director.setAnimationInterval(1/30);
    //生成一個游戲場景對象
    CCScene scene = CCScene.node();
    //生成布景對象
    GameLayer gameLayer = new GameLayer();
    //將布景層對象添加到游戲場景中去
    scene.addChild(gameLayer);
    //運行游戲場景
    director.runWithScene(scene);
    }
    }
      GameLayer.java代碼:
    import org.cocos2d.actions.interval.CCBlink;
    import org.cocos2d.layers.CCLayer;
    import org.cocos2d.nodes.CCSprite;
    public class GameLayer extends CCLayer{
    //聲明一個精靈對象
    CCSprite player;
    public GameLayer(){
    //創建一個精靈對象
    player = CCSprite.sprite("player.png");
    //將精靈對象添加到布景層當中
    this.addChild(player);
    //精靈對象位置
    player.setPosition(300,300);
    //測試閃爍
    CCBlink blink = CCBlink.action(3, 60);//第一個參數是時間,第二個參數閃爍的次數
    player.runAction(blink);
    // //測試縮放指定倍數
    // CCScaleTo caleTo = CCScaleTo.action(3, 5, 5);//第一個參數是時間,第二、三個參數分別表示在x軸和Y軸上的縮放倍數
    //
    // player.runAction(caleTo);
    // //測試旋轉
    // CCRotateTo rotateTo = CCRotateTo.action(3, 180);//第一個參數是旋轉所需的時間,
    // //第二個是旋轉的度數,當度數<=180時,順時針旋轉;>180時,逆時針旋轉
    // player.runAction(rotateTo);
    //
    // //測試移動精靈
    // CGPoint  point = CGPoint.ccp(500,500);//最后的位置
    // CCMoveTo moveTo = CCMoveTo.action(3, point);//第一個參數是精靈移動的時間
    // player.runAction(moveTo);
    //
    // 測試進項旋轉
    //1.生成動作對象
    // CCFlipX flipx = CCFlipX.action(true);
    // //2.使用精靈對象去執行動作對象
    // player.runAction(flipx);
    //
    // 測試精靈隱藏
    //1.生成動作對象
    // CCHide hide = CCHide.action();
    // //2.執行
    // player.runAction(hide);
    }
    }

    posted @ 2014-03-27 16:55 順其自然EVO 閱讀(436) | 評論 (0)編輯 收藏

    面向系統測試的一種ganglia指標擴展的方法

     ganlia 和 nagios 等工具,是業界優秀的監控告警工具;這種工具主要是面向運維的,也可以用來進行性能穩定性的測試。
      面對分布式系統測試,耗時都比較長,往往一臺機器安裝多套系統,影響監控指標的準確性。
      下面是一種進行進程級別監控的方n法,可以通過擴展,集群的監控力度;同時將監控腳本加入告警,防止腳本異常退出(Nagios擴展另文描述)
      GEngin.py:總體的引擎,根據conf下配置文件的配置項,輪詢監控指標,調用gmetric廣播出去
      conf:目錄中保存metrix配置文件,配置參數指標
      flag:目錄中僅保存一個flag文件,文件名就是任務名,監控指標將根據任務名分離,便于匯總統計對比
      log: 目錄中記錄GEngin的log及每個指標收取腳本的log
      pid: GEngin的pid 為告警腳本使用
      script: 指標收集的具體的腳本
      cat conf/metrix.cfg:
    YARN|ResourceManager|cpu|ResourceManager_cpu.py|ResourceManager_cpu.txt|int16|Percent|
    YARN|ResourceManager|mem|ResourceManager_mem.py|ResourceManager_mem.txt|int16|Percent|
    YARN|ResourceManager|lsof|ResourceManager_lsof.py|ResourceManager_lsof.txt|int16|Number|
      ls flag/:
      yarntestD001.flag
      ll log/:
    -rw-r--r-- 1 yarn users     168 Mar 19 20:02 yarntestD001_YARNResourceManagercputdw-10-16-19-91.txt
    -rw-r--r-- 1 yarn users     168 Mar 19 20:02 yarntestD001_YARNResourceManagerlsoftdw-10-16-19-91.txt
    -rw-r--r-- 1 yarn users     168 Mar 19 20:02 yarntestD001_YARNResourceManagermemtdw-10-16-19-91.txt
      ll script/:
    -rw-r--r-- 1 yarn users  882 Feb 28 17:20 ResourceManager_cpu.py
    -rw-r--r-- 1 yarn users 1093 Feb 28 17:45 ResourceManager_lsof.py
    -rw-r--r-- 1 yarn users  882 Feb 28 17:18 ResourceManager_mem.py
      cat script/SAMPLE.py:
    #!/usr/bin/env python
    # coding=gbk
    import sys
    import os
    import datetime
    import time
    def CheckInput():
    "Check Input parameters , they should be a pysql file."
    if len(sys.argv) < 2 :
    print "Usage: " + sys.argv[0] + " FileNamePrefix "
    sys.exit()
    if __name__== '__main__':
    CheckInput() # check parameter and asign PyFileName
    ## result file log to directory of LOG
    LogFile = open("log/"+sys.argv[1],'a')
    res = "29"
    ## Interface to Gmetrix ,must be value:Value
    print "value:"+res
    ntime = str(time.strftime("%Y-%m-%d %X",time.localtime()))
    LogFile.write(ntime+" "+res+"\n")
    LogFile.close()

      cat GEngin.py :
    #!/usr/bin/env python
    # coding=gbk
    import sys
    import os
    import random
    import datetime
    import time
    from time import sleep
    def CheckInput():
    "Check Input parameters , they should be a pysql file."
    print "Usage : python ./" + sys.argv[0]
    if not os.path.exists("conf/metrix.cfg"):
    print "Error : config file conf/metrix.cfg does not exsits ! "
    sys.exit()
    ## kill previous proc For restart
    if os.path.exists("pid/pid.txt"):
    pfile = open("pid/pid.txt",'r')
    for p in pfile:
    pid = p.strip()
    os.system("kill -9 "+pid)
    pfile.close()
    os.system("rm pid/pid.txt")
    pfile = open("pid/pid.txt",'a')
    pid = os.getpid()
    pfile.write(str(pid))
    pfile.close()
    if __name__== '__main__':
    CheckInput() # check parameter and asign PyFileName
    LogFile = open("log/"+sys.argv[0]+".log",'a')
    # File Prefix of logs
    filePre="noTask"
    for fi in os.listdir("flag"):
    if fi.endswith(".flag"):
    filePre=fi.split('.')[0].strip()
    # host name for gmetrix
    host=""
    f = os.popen("hostname")
    for res in f:
    if res.startswith("tdw"):
    host=res.strip()
    LogFile.write("******** Start task "+filePre+" monitoring *******\n")
    # Main Loop untile flag is null
    while True:
    if len(os.listdir("flag")) < 1 or len(os.listdir("flag")) > 1:
    sleep(10)
    LogFile.write("Finish previous take "+filePre+"  .... No task ,Main loop .....\n")
    LogFile.flush()
    continue
    if len(os.listdir("flag")) == 1 and not os.path.exists("flag/"+filePre+".flag"):
    LogFile.write("Finish previous take "+filePre+".....\n")
    for fi in os.listdir("flag"):
    if fi.endswith(".flag"):
    filePre=fi.split('.')[0].strip()
    LogFile.write("***** Start New Task "+filePre+" monitoring *******\n")
    # Deal with config metrix one by one
    insFile = open("conf/metrix.cfg",'r')
    for line in insFile:
    mGroup,mName,mItem,mShell,mFile,mUnit,mWeiht,nouse = line.split('|');
    outPutFile = filePre+"_"+mGroup+mName+mItem+host+".txt"
    value = ""
    if mShell.endswith(".py"):
    f = os.popen("python script/"+mShell+" "+outPutFile)
    for res in f:
    if res.startswith("value:"):
    value=res.split(':')[1].strip()
    else:
    value="0"
    f.close()
    if mShell.endswith(".sh"):
    f = os.popen("script/"+mShell+" "+outPutFile)
    for res in f:
    if res.startswith("value:"):
    value=res.split(':')[1].strip()
    else:
    value="0"
    f.close()
    cmd = "gmetric -n "+mGroup+"_"+mName+"_"+mItem+" -v "+value+" -t "+mUnit+" -u "+mWeiht+" -S "+host+":"+host
    print cmd
    f = os.popen(cmd)
    ntime = str(time.strftime("%Y-%m-%d %X",time.localtime()))
    LogFile.write(ntime+" "+cmd+"\n")
    insFile.close()
    LogFile.flush()
    if len(os.listdir("flag")) == 1 and os.path.exists("flag/"+filePre+".flag"):
    sleep(8)
    LogFile.close()
      Ganglia 中顯示的監控指標:
      將運行的GEngin.py腳本加入監控,防止進程異常退出

    posted @ 2014-03-27 16:53 順其自然EVO 閱讀(295) | 評論 (0)編輯 收藏

    僅列出標題
    共394頁: First 上一頁 133 134 135 136 137 138 139 140 141 下一頁 Last 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲国产精品13p| 色九月亚洲综合网| 永久亚洲成a人片777777| 成年性生交大片免费看| 99爱在线精品视频免费观看9| www成人免费观看网站| 亚洲成a∧人片在线观看无码| 色拍自拍亚洲综合图区| 亚洲中文字幕在线第六区| 国产免费私拍一区二区三区| 黄色成人网站免费无码av| 2019中文字幕在线电影免费| a级日本高清免费看| 国产99久久久国产精免费| 色噜噜狠狠色综合免费视频| 亚洲色一区二区三区四区| 亚洲国产精品成人久久久| 日本久久久久亚洲中字幕| 亚洲国产另类久久久精品黑人| 亚洲精品网站在线观看不卡无广告| 国产精品99久久免费| 香蕉视频在线观看免费国产婷婷| 老司机在线免费视频| 亚洲成综合人影院在院播放| 亚洲av无码成h人动漫无遮挡| 亚洲一区二区视频在线观看| 亚洲乱码日产精品a级毛片久久| 又黄又爽无遮挡免费视频| 免费欧洲毛片A级视频无风险| 日日操夜夜操免费视频| 国产网站免费观看| 免费v片在线观看| 亚洲成a人片在线观看日本麻豆| 国产免费啪嗒啪嗒视频看看| 日韩在线a视频免费播放| 国产免费观看a大片的网站| 免费v片在线观看品善网| 亚洲中文字幕视频国产| 国产精品V亚洲精品V日韩精品 | 亚洲精品美女久久777777| 亚洲日韩激情无码一区|