karmasphere-client 0.6.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README +41 -0
- data/bin/rubykarmaclient +135 -0
- data/lib/karmasphere.rb +5 -0
- data/lib/karmasphere/client.rb +116 -0
- data/lib/karmasphere/constants.rb +18 -0
- data/lib/karmasphere/debug.rb +22 -0
- data/lib/karmasphere/query.rb +92 -0
- data/lib/karmasphere/response.rb +116 -0
- data/lib/rubytorrent/bencoding.rb +182 -0
- data/test/test_all.rb +8 -0
- data/test/test_client.rb +264 -0
- data/test/test_query.rb +120 -0
- data/test/test_response.rb +65 -0
- metadata +57 -0
    
        data/README
    ADDED
    
    | @@ -0,0 +1,41 @@ | |
| 1 | 
            +
            = Karmasphere Ruby Client Library
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            produced by Meng Weng Wong 200606
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            == Usage
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            After installation, run
         | 
| 8 | 
            +
             | 
| 9 | 
            +
              rubykarmaclient --ip4=127.0.0.2
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            You should get back a response from the Karmasphere system
         | 
| 12 | 
            +
            showing the reputation of that IP address.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            == Installation
         | 
| 15 | 
            +
             | 
| 16 | 
            +
            The Karmasphere Client has been packaged as a rubygem.  As
         | 
| 17 | 
            +
            it is still in active development, and as the rest of the
         | 
| 18 | 
            +
            Karmasphere system is still in alpha, this gem has not yet
         | 
| 19 | 
            +
            been uploaded to RubyForge (20060701).
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            == User Documentation
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            To learn about the Karmasphere system, see http://www.karmasphere.com/userguide/
         | 
| 24 | 
            +
             | 
| 25 | 
            +
            == Developer Documentation
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            If you are an MTA or Anti-Spam Vendor, see http://www.karmasphere.com/devzone/
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            == Bugs
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            See http://rt.karmasphere.com/
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            == History
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            [20060701] Packaged for rake/rubygems by Meng Weng Wong <mengwong@karmasphere.com>.
         | 
| 36 | 
            +
            [200606] Originally written by Dave Brown <dagbrown>.
         | 
| 37 | 
            +
             | 
| 38 | 
            +
            == License
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            This client software is distributed under the same terms as Ruby.
         | 
| 41 | 
            +
             | 
    
        data/bin/rubykarmaclient
    ADDED
    
    | @@ -0,0 +1,135 @@ | |
| 1 | 
            +
            #!/usr/bin/ruby
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # mengwong@pobox.com 20060629
         | 
| 4 | 
            +
            # Karmasphere client for Ruby
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            # usage:
         | 
| 7 | 
            +
            #  rubykarmaclient --host=slave.karmasphere.com --ip4=127.0.0.2
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            # ----------------------------------------------------------
         | 
| 10 | 
            +
            #			 libraries
         | 
| 11 | 
            +
            # ----------------------------------------------------------
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            require "socket"
         | 
| 14 | 
            +
            require "rubygems" # if run from trunk/lib, with ../bin/rubykarmaclient, the dev libs will load instead of the system libs
         | 
| 15 | 
            +
            require "rubytorrent/bencoding"
         | 
| 16 | 
            +
            require "karmasphere/client"
         | 
| 17 | 
            +
            require "karmasphere/query"
         | 
| 18 | 
            +
            require "karmasphere/response"
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            # ----------------------------------------------------------
         | 
| 21 | 
            +
            #		     options processing
         | 
| 22 | 
            +
            # ----------------------------------------------------------
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            require "getoptlong"
         | 
| 25 | 
            +
            opts = GetoptLong.new(
         | 
| 26 | 
            +
                    [ "--host"              , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 27 | 
            +
                    [ "--port"              , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 28 | 
            +
            		[ "--composite"         , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 29 | 
            +
                    [ "--combiner"          , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 30 | 
            +
                    [ "--ip4"               , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 31 | 
            +
                    [ "--ip6"               , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 32 | 
            +
                    [ "--domain"            , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 33 | 
            +
                    [ "--url"               , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 34 | 
            +
                    [ "--email"             , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 35 | 
            +
                    [ "--flags"             , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 36 | 
            +
                    [ "--username"          , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 37 | 
            +
                    [ "--password"          , GetoptLong::REQUIRED_ARGUMENT ],
         | 
| 38 | 
            +
                    [ "--tcp"               , GetoptLong::NO_ARGUMENT ],
         | 
| 39 | 
            +
                    [ "--help"              , GetoptLong::NO_ARGUMENT ],
         | 
| 40 | 
            +
                    [ "--single"            , GetoptLong::NO_ARGUMENT ],
         | 
| 41 | 
            +
                    [ "--debug", "-d"       , GetoptLong::NO_ARGUMENT ]
         | 
| 42 | 
            +
            	);
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            myopts = {};
         | 
| 45 | 
            +
            opts.each { |opt, arg| myopts[opt] = arg }
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            # ----------------------------------------------------------
         | 
| 48 | 
            +
            # symbolic constants
         | 
| 49 | 
            +
            # ----------------------------------------------------------
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            FL_WANTFACTS = 1
         | 
| 52 | 
            +
            DEFAULT_IP = "127.0.0.2"
         | 
| 53 | 
            +
            DEFAULT_COMPOSITE = "karmasphere.email-sender"
         | 
| 54 | 
            +
             | 
| 55 | 
            +
            if myopts.has_key? '--help' then
         | 
| 56 | 
            +
               print "usage: rubykarmaclient
         | 
| 57 | 
            +
                             [     --username=xxx --password=yyy          ]
         | 
| 58 | 
            +
                             [     --ip4=127.0.0.2                        ]
         | 
| 59 | 
            +
                             [     --domain=example.com                   ]
         | 
| 60 | 
            +
                             [     --url=http://www.example.com/phishing/ ]
         | 
| 61 | 
            +
                             [     --tcp                                  ]
         | 
| 62 | 
            +
                             [     --composite=karmasphere.email-sender   ]
         | 
| 63 | 
            +
            "
         | 
| 64 | 
            +
            		exit;
         | 
| 65 | 
            +
            end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
             | 
| 68 | 
            +
            # ----------------------------------------------------------
         | 
| 69 | 
            +
            #		      data preparation
         | 
| 70 | 
            +
            # ----------------------------------------------------------
         | 
| 71 | 
            +
             | 
| 72 | 
            +
            identities = []
         | 
| 73 | 
            +
            [ "--ip4", "--ip6", "--domain", "--url", "--email" ].each do |identifier|
         | 
| 74 | 
            +
            	identities << myopts[identifier] if myopts[identifier];
         | 
| 75 | 
            +
            end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
            identities << DEFAULT_IP if identities.length == 0;
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            print "identifiers = #{identities}\n" if myopts['--debug'];
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            # ----------------------------------------------------------
         | 
| 82 | 
            +
            #			    main
         | 
| 83 | 
            +
            # ----------------------------------------------------------
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            # 
         | 
| 86 | 
            +
            # set up client
         | 
| 87 | 
            +
            # 
         | 
| 88 | 
            +
             | 
| 89 | 
            +
            clientargs = { }
         | 
| 90 | 
            +
             | 
| 91 | 
            +
            if myopts.has_key? '--tcp' then clientargs[:type] = :CONNECTION_TCP else clientargs[:type] = :CONNECTION_UDP end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
            if myopts.has_key? '--host' then clientargs[:host] = myopts['--host'] end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
            if myopts.has_key? '--username' then clientargs[:principal]   = myopts['--username'] end
         | 
| 96 | 
            +
            if myopts.has_key? '--password' then clientargs[:credentials] = myopts['--password'] end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            client=Karmasphere::Client.new(clientargs)
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            # 
         | 
| 101 | 
            +
            # set up query
         | 
| 102 | 
            +
            # 
         | 
| 103 | 
            +
             | 
| 104 | 
            +
            query_id = myopts['--id'] || "000";
         | 
| 105 | 
            +
             | 
| 106 | 
            +
            queryargs = { :Id => query_id,
         | 
| 107 | 
            +
              :Identities => identities }
         | 
| 108 | 
            +
             | 
| 109 | 
            +
            if myopts.has_key? '--flags' then
         | 
| 110 | 
            +
              queryargs[:Flags] = myopts['--flags']
         | 
| 111 | 
            +
            else
         | 
| 112 | 
            +
              queryargs[:Flags] = FL_WANTFACTS
         | 
| 113 | 
            +
            end
         | 
| 114 | 
            +
             | 
| 115 | 
            +
            if myopts.has_key? '--composite' then
         | 
| 116 | 
            +
              queryargs[:Composites] = myopts['--composite'].split(',')
         | 
| 117 | 
            +
            else
         | 
| 118 | 
            +
              queryargs[:Composites] = [ DEFAULT_COMPOSITE ]
         | 
| 119 | 
            +
            end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
            print "query args: " , queryargs.inspect, "\n" if myopts['--debug'];
         | 
| 122 | 
            +
            query = Karmasphere::Query.new( queryargs )
         | 
| 123 | 
            +
            print query.inspect, "\n" if myopts['--debug'];
         | 
| 124 | 
            +
             | 
| 125 | 
            +
            # 
         | 
| 126 | 
            +
            # display response
         | 
| 127 | 
            +
            # 
         | 
| 128 | 
            +
             | 
| 129 | 
            +
            response = client.ask(query)
         | 
| 130 | 
            +
             | 
| 131 | 
            +
            if myopts['--debug']
         | 
| 132 | 
            +
              puts response.instance_variable_get('@hash').inspect
         | 
| 133 | 
            +
            end
         | 
| 134 | 
            +
             | 
| 135 | 
            +
            puts response
         | 
    
        data/lib/karmasphere.rb
    ADDED
    
    
| @@ -0,0 +1,116 @@ | |
| 1 | 
            +
            #------------------------------------------------------------------------
         | 
| 2 | 
            +
            # The (mostly-complete) Karmasphere Client
         | 
| 3 | 
            +
            #------------------------------------------------------------------------
         | 
| 4 | 
            +
            require "socket"
         | 
| 5 | 
            +
            require "rubytorrent/bencoding"
         | 
| 6 | 
            +
            require "stringio"
         | 
| 7 | 
            +
            require "fcntl"
         | 
| 8 | 
            +
            require "karmasphere/debug"
         | 
| 9 | 
            +
             | 
| 10 | 
            +
            module Karmasphere
         | 
| 11 | 
            +
              CONNECTION_UDP = :CONNECTION_UDP
         | 
| 12 | 
            +
              CONNECTION_TCP = :CONNECTION_TCP
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                class CredentialsError < Exception
         | 
| 15 | 
            +
                end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                class Client
         | 
| 18 | 
            +
                    private 
         | 
| 19 | 
            +
                    def send_query(query)
         | 
| 20 | 
            +
                        if @auth 
         | 
| 21 | 
            +
                            querystr=query.to_hash.merge(@auth).to_bencoding
         | 
| 22 | 
            +
                        else
         | 
| 23 | 
            +
                            querystr=query.to_hash.to_bencoding
         | 
| 24 | 
            +
                        end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                        if TCPSocket === @socket then
         | 
| 27 | 
            +
                            @socket.send [querystr.length].pack("N"),0
         | 
| 28 | 
            +
                        end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                      Karmasphere.dprint("sending query string #{querystr}\n");
         | 
| 31 | 
            +
                        @socket.send querystr,0
         | 
| 32 | 
            +
                      Karmasphere.dprint("sent.\n");
         | 
| 33 | 
            +
                    end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                    def find_response(query)
         | 
| 36 | 
            +
                        # (hack, not guaranteed to work) handle out-of-order responses
         | 
| 37 | 
            +
                        loop do
         | 
| 38 | 
            +
                            if @response_pool.has_key? query.id then
         | 
| 39 | 
            +
                                return @response_pool.delete(query.id)
         | 
| 40 | 
            +
                            else
         | 
| 41 | 
            +
                                response=Response.new( decode(receive_response), query )
         | 
| 42 | 
            +
                                @response_pool[response.id] = response;
         | 
| 43 | 
            +
                            end
         | 
| 44 | 
            +
                        end
         | 
| 45 | 
            +
                    end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
                    def receive_response
         | 
| 48 | 
            +
                        if TCPSocket === @socket then
         | 
| 49 | 
            +
                            length_s = @socket.recvfrom(4)[0]
         | 
| 50 | 
            +
                            length_n = length_s.unpack("N")[0]
         | 
| 51 | 
            +
                            Karmasphere.dprint("client decoding TCP response of #{length_n} bytes\n");
         | 
| 52 | 
            +
                            @socket.recvfrom(length_n)[0]
         | 
| 53 | 
            +
                        else
         | 
| 54 | 
            +
                          Karmasphere.dprint("client awaiting response from #@socket\n");
         | 
| 55 | 
            +
                          reply, from = @socket.recvfrom(8192)
         | 
| 56 | 
            +
                          Karmasphere.dprint("client response received from #@socket\n");
         | 
| 57 | 
            +
                          reply
         | 
| 58 | 
            +
                        end
         | 
| 59 | 
            +
                    end
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                    def decode(querystr)
         | 
| 62 | 
            +
                        RubyTorrent::BStream.new(
         | 
| 63 | 
            +
                            StringIO.new( querystr )
         | 
| 64 | 
            +
                        ).to_a[0]
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                    def make_query(query)
         | 
| 68 | 
            +
                        send_query query
         | 
| 69 | 
            +
                        find_response query
         | 
| 70 | 
            +
                    end
         | 
| 71 | 
            +
             | 
| 72 | 
            +
                    public
         | 
| 73 | 
            +
                    def initialize(*args)
         | 
| 74 | 
            +
                        host="query.karmasphere.com"
         | 
| 75 | 
            +
                        port=8666
         | 
| 76 | 
            +
                        type=CONNECTION_UDP
         | 
| 77 | 
            +
                        if Hash === args[0] then
         | 
| 78 | 
            +
                            opts = args[0]
         | 
| 79 | 
            +
                            host = opts[:host] if opts.has_key? :host 
         | 
| 80 | 
            +
                            port = opts[:port] if opts.has_key? :port
         | 
| 81 | 
            +
                            type = opts[:type] if opts.has_key? :type and
         | 
| 82 | 
            +
                                                  opts[:type] == CONNECTION_TCP ||
         | 
| 83 | 
            +
                                                  opts[:type] == CONNECTION_UDP
         | 
| 84 | 
            +
                            @auth = nil
         | 
| 85 | 
            +
                            if opts.has_key? :principal then
         | 
| 86 | 
            +
                                unless opts.has_key? :credentials
         | 
| 87 | 
            +
                                    raise CredentialsError, "principal missing credentials"
         | 
| 88 | 
            +
                                end
         | 
| 89 | 
            +
                            end
         | 
| 90 | 
            +
                            if opts.has_key? :credentials then
         | 
| 91 | 
            +
                                unless opts.has_key? :principal
         | 
| 92 | 
            +
                                    raise CredentialsError, "credentials missing principal"
         | 
| 93 | 
            +
                                end
         | 
| 94 | 
            +
                                @auth = { "a" => [ opts[:principal], opts[:credentials] ] }
         | 
| 95 | 
            +
                            end
         | 
| 96 | 
            +
                        end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                        if type == CONNECTION_UDP
         | 
| 99 | 
            +
                            @socket = UDPSocket.new
         | 
| 100 | 
            +
                          Karmasphere.dprint "UDP client: attempting to connect to #{host}:#{port}\n"
         | 
| 101 | 
            +
                            @socket.connect host, port
         | 
| 102 | 
            +
                            @socket.fcntl(Fcntl::F_SETFD,1) if defined? Fcntl::F_SETFD
         | 
| 103 | 
            +
                          Karmasphere.dprint "UDP client: created socket #@socket\n"
         | 
| 104 | 
            +
                        else
         | 
| 105 | 
            +
                          Karmasphere.dprint "TCP client: attempting to connect to #{host}:#{port}\n"
         | 
| 106 | 
            +
                            @socket = TCPSocket.new host, port
         | 
| 107 | 
            +
                        end
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                        @response_pool={}
         | 
| 110 | 
            +
                    end
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                    def ask(query)
         | 
| 113 | 
            +
                        make_query(query)
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
            end
         | 
| @@ -0,0 +1,18 @@ | |
| 1 | 
            +
            #------------------------------------------------------------------------
         | 
| 2 | 
            +
            # Constants used in the Karmasphere Query class
         | 
| 3 | 
            +
            #------------------------------------------------------------------------
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            module Karmasphere
         | 
| 6 | 
            +
                IDT_IP4_ADDRESS          = 0
         | 
| 7 | 
            +
                IDT_IP6_ADDRESS          = 1
         | 
| 8 | 
            +
                IDT_DOMAIN_NAME          = 2
         | 
| 9 | 
            +
                IDT_EMAIL_ADDRESS        = 3
         | 
| 10 | 
            +
                IDT_URL                  = 4
         | 
| 11 | 
            +
                IDT_OPAQUE               = 5
         | 
| 12 | 
            +
                AUTHENTIC                = "a"
         | 
| 13 | 
            +
                SMTP_CLIENT_IP           = "smtp.client-ip"
         | 
| 14 | 
            +
                SMTP_ENV_HELO            = "smtp.env.helo"
         | 
| 15 | 
            +
                SMTP_ENV_MAIL_FROM       = "smtp.env.mail-from"
         | 
| 16 | 
            +
                SMTP_ENV_RCPT_TO         = "smtp.env.rcpt-to"
         | 
| 17 | 
            +
                SMTP_HEADER_FROM_ADDRESS = "smtp.header.from.address"
         | 
| 18 | 
            +
            end
         | 
| @@ -0,0 +1,22 @@ | |
| 1 | 
            +
             | 
| 2 | 
            +
            module Karmasphere
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              # if you want debugging turned on,
         | 
| 5 | 
            +
              # set any one of these environment variables:
         | 
| 6 | 
            +
              # * KARMADEBUG
         | 
| 7 | 
            +
              # * RUBYDEBUG
         | 
| 8 | 
            +
              # or change the following line to read .find(lambda { true })
         | 
| 9 | 
            +
              
         | 
| 10 | 
            +
              KARMADEBUG = %w{KARMADEBUG RUBYDEBUG}.find(nil) do |debugenv|
         | 
| 11 | 
            +
                ENV[debugenv] and ENV[debugenv].size and ENV[debugenv] != "0"
         | 
| 12 | 
            +
              end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              # use +dprint+ instead of print.  it will print to STDERR,
         | 
| 15 | 
            +
              # but only when debugging is turned on.
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              def dprint(*args)
         | 
| 18 | 
            +
                STDERR.print("KarmaDebug: ", "%0.6f: " % Time.now, *args) if KARMADEBUG
         | 
| 19 | 
            +
              end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
              module_function :dprint  
         | 
| 22 | 
            +
            end
         | 
| @@ -0,0 +1,92 @@ | |
| 1 | 
            +
            #------------------------------------------------------------------------
         | 
| 2 | 
            +
            # Karmasphere Query class (translation of the Perl code)
         | 
| 3 | 
            +
            #------------------------------------------------------------------------
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require "karmasphere/constants"
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            module Karmasphere
         | 
| 8 | 
            +
                class Query
         | 
| 9 | 
            +
                    @@ID=0
         | 
| 10 | 
            +
                    Realflag = { 
         | 
| 11 | 
            +
                        :Id => "_",
         | 
| 12 | 
            +
                        :Identities => "i",
         | 
| 13 | 
            +
                        :Composites => "s",
         | 
| 14 | 
            +
                        :Combiners => "c",
         | 
| 15 | 
            +
                        :Flags => "fl"
         | 
| 16 | 
            +
                    }
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                    private
         | 
| 19 | 
            +
                    def guess_identity_type(addr)
         | 
| 20 | 
            +
                        case addr
         | 
| 21 | 
            +
                            when /^[0-9\.]{7,15}$/:        IDT_IP4_ADDRESS
         | 
| 22 | 
            +
                            when /^[0-9a-f:\/]{2,64}$/i:   IDT_IP6_ADDRESS
         | 
| 23 | 
            +
                            when /^https?:\/\//:           IDT_URL
         | 
| 24 | 
            +
                            when /@/:                      IDT_EMAIL_ADDRESS
         | 
| 25 | 
            +
                            when /\./:                     IDT_DOMAIN_NAME
         | 
| 26 | 
            +
                            else                           IDT_OPAQUE
         | 
| 27 | 
            +
                        end
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                    public
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                    def initialize(*args)
         | 
| 33 | 
            +
                        self.id = "q#{@@ID += 1}"
         | 
| 34 | 
            +
             | 
| 35 | 
            +
                        if args.length > 0
         | 
| 36 | 
            +
                            opts = args[0] if Hash === args[0]
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                            [:Id, :Identities, :Composites, :Composite, :Feeds,
         | 
| 39 | 
            +
                                :Combiners, :Combiner, :Flags].each do |option|
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                                if opts.has_key? option
         | 
| 42 | 
            +
                                    send("#{option.to_s.downcase}=", opts[option])
         | 
| 43 | 
            +
                                end
         | 
| 44 | 
            +
                            end
         | 
| 45 | 
            +
                        end
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    attr_accessor :id, :composites, :feeds, :combiners
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                    attr_writer :flags
         | 
| 51 | 
            +
                    def flags
         | 
| 52 | 
            +
                      @flags.to_i
         | 
| 53 | 
            +
                    end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    def composite=(newcomposite)
         | 
| 56 | 
            +
                        self.composites=newcomposite
         | 
| 57 | 
            +
                    end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                    def feed=(newfeed)
         | 
| 60 | 
            +
                        @feeds=[newfeed]
         | 
| 61 | 
            +
                    end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    def identities=(stuff)
         | 
| 64 | 
            +
                        if String === stuff then
         | 
| 65 | 
            +
                            return self.identities=[stuff]
         | 
| 66 | 
            +
                        end
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                        @identities = if Array === stuff then
         | 
| 69 | 
            +
                                          stuff.map do |item|
         | 
| 70 | 
            +
                                              if Array === item then
         | 
| 71 | 
            +
                                                  item
         | 
| 72 | 
            +
                                              else
         | 
| 73 | 
            +
                                                  [item, guess_identity_type(item)]
         | 
| 74 | 
            +
                                              end
         | 
| 75 | 
            +
                                          end
         | 
| 76 | 
            +
                                      end
         | 
| 77 | 
            +
                    end
         | 
| 78 | 
            +
                    attr_reader :identities
         | 
| 79 | 
            +
                    alias identity= identities=
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                    def to_hash
         | 
| 82 | 
            +
                        retval={}
         | 
| 83 | 
            +
                        [:Id, :Identities, :Composites, 
         | 
| 84 | 
            +
                            :Feeds, :Combiners, :Flags].each do |k|
         | 
| 85 | 
            +
                            if instance_variables.member? "@#{k.to_s.downcase}"
         | 
| 86 | 
            +
                                retval[Realflag[k]]=send "#{k.to_s.downcase}"
         | 
| 87 | 
            +
                            end
         | 
| 88 | 
            +
                        end
         | 
| 89 | 
            +
                        retval
         | 
| 90 | 
            +
                    end
         | 
| 91 | 
            +
                end
         | 
| 92 | 
            +
            end
         | 
| @@ -0,0 +1,116 @@ | |
| 1 | 
            +
            #------------------------------------------------------------------------
         | 
| 2 | 
            +
            # Desired Output Format
         | 
| 3 | 
            +
            #------------------------------------------------------------------------
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            # the Java, Perl and C clients all produce the same output format.
         | 
| 6 | 
            +
            #
         | 
| 7 | 
            +
            #   20060907-15:53:55 mengwong@newyears-air:~/src/karmasphere/trunk/lib% karmaclient --ip4=127.0.0.2 --host=bowie.tx.karmasphere.com
         | 
| 8 | 
            +
            #   Response id 'q0': 12ms, 1 combinations, 8 facts
         | 
| 9 | 
            +
            #   Combiner 'karmasphere.emailchecker': verdict 1000 (isipp.iadb-vouched-ip: if-pass(0) => return good(1.0))
         | 
| 10 | 
            +
            #   Feed 'sorbs.dul' opinion -1000 (Dynamic IP Addresses See: http://www.sorbs.net/lookup.shtml?$)
         | 
| 11 | 
            +
            #   Feed 'spamhaus.xbl-cbl' opinion -1000 (http://www.spamhaus.org/query/bl?ip=$)
         | 
| 12 | 
            +
            #   Feed 'cymru.bogons' opinion -1000 (Invalid source IP address (cymru))
         | 
| 13 | 
            +
            #   Feed 'dsbl.list' opinion -1000 (http://dsbl.org/listing?$)
         | 
| 14 | 
            +
            #   Feed 'dsbl.multihop' opinion -1000 (http://dsbl.org/listing?$)
         | 
| 15 | 
            +
            #   Feed 'spamcop.bl' opinion 2147483647 (null data)
         | 
| 16 | 
            +
            #   Feed 'isipp.iadb-vouched-ip' opinion 1000 (Vouched by ISIPP/IADB)
         | 
| 17 | 
            +
            #   Feed 'spamhaus.sbl' opinion -1000 (http://www.spamhaus.org/query/bl?ip=$)
         | 
| 18 | 
            +
            #   20060907-15:54:01 mengwong@newyears-air:~/src/karmasphere/trunk/lib%
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            #------------------------------------------------------------------------
         | 
| 21 | 
            +
            # Response class for the Karmasphere client
         | 
| 22 | 
            +
            #------------------------------------------------------------------------
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            module Karmasphere
         | 
| 25 | 
            +
                class Response
         | 
| 26 | 
            +
                    private
         | 
| 27 | 
            +
                    def combination_get(key, combiner=nil)
         | 
| 28 | 
            +
                        if combinations then
         | 
| 29 | 
            +
                            if !combiner and combinations.has_key?("default") then
         | 
| 30 | 
            +
                                combination('default')
         | 
| 31 | 
            +
                            elsif !combiner then
         | 
| 32 | 
            +
                                combinations.values.find do |combo|
         | 
| 33 | 
            +
                                    if combo.has_key? key then combo[key] end
         | 
| 34 | 
            +
                                end
         | 
| 35 | 
            +
                            else
         | 
| 36 | 
            +
                                my_combination=combination(combiner)
         | 
| 37 | 
            +
                                if my_combination then
         | 
| 38 | 
            +
                                    return my_combination[key]
         | 
| 39 | 
            +
                                end
         | 
| 40 | 
            +
                            end
         | 
| 41 | 
            +
                        end
         | 
| 42 | 
            +
                    end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    public
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    def initialize(hash, query=nil)
         | 
| 47 | 
            +
                        @hash=hash
         | 
| 48 | 
            +
            	    @query=query
         | 
| 49 | 
            +
                    end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                    def id; @hash["_"] end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    def time; @hash["time"] if @hash.has_key? "time" end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    def facts
         | 
| 56 | 
            +
                        if @hash.has_key? "facts" then 
         | 
| 57 | 
            +
                            @hash["facts"]
         | 
| 58 | 
            +
                        elsif @hash.has_key? "f" then 
         | 
| 59 | 
            +
                            @hash["f"] 
         | 
| 60 | 
            +
                        else
         | 
| 61 | 
            +
                            []
         | 
| 62 | 
            +
                        end
         | 
| 63 | 
            +
                    end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                    def combinations
         | 
| 66 | 
            +
                        if @hash.has_key? "c" then 
         | 
| 67 | 
            +
                            @hash["c"] 
         | 
| 68 | 
            +
                        elsif @hash.has_key? "combiners" then 
         | 
| 69 | 
            +
                            @hash["combiners"] 
         | 
| 70 | 
            +
                        end
         | 
| 71 | 
            +
                    end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    def combination(combiner)
         | 
| 74 | 
            +
                        combinations[combiner]
         | 
| 75 | 
            +
                    end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
                    def combiner_names
         | 
| 78 | 
            +
                        if combinations then
         | 
| 79 | 
            +
                            combinations.keys
         | 
| 80 | 
            +
                        else
         | 
| 81 | 
            +
                            []
         | 
| 82 | 
            +
                        end
         | 
| 83 | 
            +
                    end
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                    def verdict(name=nil); combination_get "v",name; end
         | 
| 86 | 
            +
                    alias value verdict
         | 
| 87 | 
            +
                    def data(name=nil); combination_get "d", name; end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    def error; @hash["error"] if @hash.has_key? "error"; end
         | 
| 90 | 
            +
                    def message; @hash["message"] if @hash.has_key? "message"; end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                    def to_s;
         | 
| 93 | 
            +
                        "Response_id '#{id}': " +
         | 
| 94 | 
            +
                            if time then "#{time}ms, "  else "" end + 
         | 
| 95 | 
            +
                            "#{combiner_names.length} combinations, " +
         | 
| 96 | 
            +
                            "#{facts.length} facts\n" +
         | 
| 97 | 
            +
                            if error then 
         | 
| 98 | 
            +
                                "Error: #{message}\n" 
         | 
| 99 | 
            +
                            else
         | 
| 100 | 
            +
                                combiner_names.map do |name|
         | 
| 101 | 
            +
                                    "Combiner '#{name}': verdict #{value(name)} " +
         | 
| 102 | 
            +
                                    "(#{data(name) || '(undef)'})\n"
         | 
| 103 | 
            +
                                end.join("") +
         | 
| 104 | 
            +
                                facts.map do |fact|
         | 
| 105 | 
            +
                                        "Feed '#{fact['f']}' opinion #{fact['v']} (" +
         | 
| 106 | 
            +
                                        if fact.has_key? "d" then
         | 
| 107 | 
            +
                                            fact["d"]
         | 
| 108 | 
            +
                                        else
         | 
| 109 | 
            +
                                            "null data"
         | 
| 110 | 
            +
                                        end + ")" +
         | 
| 111 | 
            +
                            if fact.has_key? "i" then " (identity=#{fact['i']})" else "" end + "\n"
         | 
| 112 | 
            +
                                end.join("")
         | 
| 113 | 
            +
                            end
         | 
| 114 | 
            +
                    end
         | 
| 115 | 
            +
                end
         | 
| 116 | 
            +
            end
         | 
| @@ -0,0 +1,182 @@ | |
| 1 | 
            +
            ## bencoding.rb -- parse and generate bencoded values.
         | 
| 2 | 
            +
            ## Copyright 2004 William Morgan.
         | 
| 3 | 
            +
            ##
         | 
| 4 | 
            +
            ## This file is part of RubyTorrent. RubyTorrent is free software;
         | 
| 5 | 
            +
            ## you can redistribute it and/or modify it under the terms of version
         | 
| 6 | 
            +
            ## 2 of the GNU General Public License as published by the Free
         | 
| 7 | 
            +
            ## Software Foundation.
         | 
| 8 | 
            +
            ##
         | 
| 9 | 
            +
            ## RubyTorrent is distributed in the hope that it will be useful, but
         | 
| 10 | 
            +
            ## WITHOUT ANY WARRANTY; without even the implied warranty of
         | 
| 11 | 
            +
            ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
         | 
| 12 | 
            +
            ## General Public License (in the file COPYING) for more details.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
            require 'uri'
         | 
| 15 | 
            +
            require 'digest/sha1'
         | 
| 16 | 
            +
             
         | 
| 17 | 
            +
            module RubyTorrent
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            ## we mess in the users' namespaces in this file. there's no good way
         | 
| 20 | 
            +
            ## around it. i don't think it's too egregious though.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            class BEncodingError < StandardError; end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            class BStream
         | 
| 25 | 
            +
              include Enumerable
         | 
| 26 | 
            +
             | 
| 27 | 
            +
              @@classes = []
         | 
| 28 | 
            +
             | 
| 29 | 
            +
              def initialize(s)
         | 
| 30 | 
            +
                @s = s
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
              def self.register_bencoded_class(c)
         | 
| 34 | 
            +
                @@classes.push c
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              def each
         | 
| 38 | 
            +
                happy = true
         | 
| 39 | 
            +
                begin
         | 
| 40 | 
            +
                  happy = false
         | 
| 41 | 
            +
                  c = @s.getc
         | 
| 42 | 
            +
                  @@classes.each do |klass|
         | 
| 43 | 
            +
                    if klass.bencoded? c
         | 
| 44 | 
            +
                      o = klass.parse_bencoding(c, @s)
         | 
| 45 | 
            +
                      happy = true
         | 
| 46 | 
            +
                      yield o
         | 
| 47 | 
            +
                      break
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  end unless c.nil?
         | 
| 50 | 
            +
                  unless happy
         | 
| 51 | 
            +
                    @s.ungetc c unless c.nil?
         | 
| 52 | 
            +
                  end
         | 
| 53 | 
            +
                end while happy
         | 
| 54 | 
            +
                self
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            end
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            class String
         | 
| 61 | 
            +
              def to_bencoding
         | 
| 62 | 
            +
                self.length.to_s + ":" + self.to_s
         | 
| 63 | 
            +
              end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
              def self.bencoded?(c)
         | 
| 66 | 
            +
                (?0 .. ?9).include? c
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              def self.parse_bencoding(c, s)
         | 
| 70 | 
            +
                lens = c.chr
         | 
| 71 | 
            +
                while ((x = s.getc) != ?:)
         | 
| 72 | 
            +
                  unless (?0 .. ?9).include? x
         | 
| 73 | 
            +
                    s.ungetc x
         | 
| 74 | 
            +
                    raise RubyTorrent::BEncodingError, "invalid bencoded string length #{lens} + #{x}" 
         | 
| 75 | 
            +
                  end
         | 
| 76 | 
            +
                  lens += x.chr
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
                raise RubyTorrent::BEncodingError, %{invalid length #{lens} in bencoded string} unless lens.length <= 20
         | 
| 79 | 
            +
                len = lens.to_i
         | 
| 80 | 
            +
                raise RubyTorrent::BEncodingError, %{invalid length #{lens} in bencoded string} unless len >= 0
         | 
| 81 | 
            +
                (len > 0 ? s.read(len) : "")
         | 
| 82 | 
            +
              end
         | 
| 83 | 
            +
             | 
| 84 | 
            +
              RubyTorrent::BStream.register_bencoded_class self
         | 
| 85 | 
            +
            end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
            class Integer
         | 
| 88 | 
            +
              def to_bencoding
         | 
| 89 | 
            +
                "i" + self.to_s + "e"
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              def self.bencoded?(c)
         | 
| 93 | 
            +
                c == ?i
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
             | 
| 96 | 
            +
              def self.parse_bencoding(c, s)
         | 
| 97 | 
            +
                ints = ""
         | 
| 98 | 
            +
                while ((x = s.getc.chr) != 'e')
         | 
| 99 | 
            +
                  raise RubyTorrent::BEncodingError, "invalid bencoded integer #{x.inspect}" unless x =~ /\d|-/
         | 
| 100 | 
            +
                  ints += x
         | 
| 101 | 
            +
                end
         | 
| 102 | 
            +
                raise RubyTorrent::BEncodingError, "invalid integer #{ints} (too long)" unless ints.length <= 20
         | 
| 103 | 
            +
                int = ints.to_i
         | 
| 104 | 
            +
                raise RubyTorrent::BEncodingError, %{can't parse bencoded integer "#{ints}"} if (int == 0) && (ints !~ /^0$/) #'
         | 
| 105 | 
            +
                int
         | 
| 106 | 
            +
              end
         | 
| 107 | 
            +
             | 
| 108 | 
            +
              RubyTorrent::BStream.register_bencoded_class self
         | 
| 109 | 
            +
            end
         | 
| 110 | 
            +
             | 
| 111 | 
            +
            class Time
         | 
| 112 | 
            +
              def to_bencoding
         | 
| 113 | 
            +
                self.to_i.to_bencoding
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
            end
         | 
| 116 | 
            +
             | 
| 117 | 
            +
            module URI
         | 
| 118 | 
            +
              def to_bencoding
         | 
| 119 | 
            +
                self.to_s.to_bencoding
         | 
| 120 | 
            +
              end
         | 
| 121 | 
            +
            end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
            # Symbol#to_bencoding added by dagbrown 2006/6/3 for karmaclient
         | 
| 124 | 
            +
             | 
| 125 | 
            +
            class Symbol
         | 
| 126 | 
            +
                def to_bencoding
         | 
| 127 | 
            +
                    to_s.bencoding
         | 
| 128 | 
            +
                end
         | 
| 129 | 
            +
            end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
            class Array
         | 
| 132 | 
            +
              def to_bencoding
         | 
| 133 | 
            +
                "l" + self.map { |e| e.to_bencoding }.join + "e"
         | 
| 134 | 
            +
              end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
              def self.bencoded?(c)
         | 
| 137 | 
            +
                c == ?l
         | 
| 138 | 
            +
              end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
              def self.parse_bencoding(c, s)
         | 
| 141 | 
            +
                ret = RubyTorrent::BStream.new(s).map { |x| x }
         | 
| 142 | 
            +
                raise RubyTorrent::BEncodingError, "missing list terminator" unless s.getc == ?e
         | 
| 143 | 
            +
                ret
         | 
| 144 | 
            +
              end
         | 
| 145 | 
            +
             | 
| 146 | 
            +
              RubyTorrent::BStream.register_bencoded_class self
         | 
| 147 | 
            +
            end
         | 
| 148 | 
            +
             | 
| 149 | 
            +
            class Hash
         | 
| 150 | 
            +
              def to_bencoding
         | 
| 151 | 
            +
                "d" + keys.sort.map do |k|
         | 
| 152 | 
            +
                  v = self[k]
         | 
| 153 | 
            +
                  if v.nil?
         | 
| 154 | 
            +
                    nil
         | 
| 155 | 
            +
                  else
         | 
| 156 | 
            +
                    [k.to_bencoding, v.to_bencoding].join
         | 
| 157 | 
            +
                  end
         | 
| 158 | 
            +
                end.compact.join + "e"
         | 
| 159 | 
            +
              end
         | 
| 160 | 
            +
             | 
| 161 | 
            +
              def self.bencoded?(c)
         | 
| 162 | 
            +
                c == ?d
         | 
| 163 | 
            +
              end
         | 
| 164 | 
            +
             | 
| 165 | 
            +
              def self.parse_bencoding(c, s)
         | 
| 166 | 
            +
                ret = {}
         | 
| 167 | 
            +
                key = nil
         | 
| 168 | 
            +
                RubyTorrent::BStream.new(s).each do |x|
         | 
| 169 | 
            +
                  if key == nil
         | 
| 170 | 
            +
                    key = x
         | 
| 171 | 
            +
                  else
         | 
| 172 | 
            +
                    ret[key] = x
         | 
| 173 | 
            +
                    key = nil
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
                end
         | 
| 176 | 
            +
             | 
| 177 | 
            +
                raise RubyTorrent::BEncodingError, "no dictionary terminator" unless s.getc == ?e
         | 
| 178 | 
            +
                ret
         | 
| 179 | 
            +
              end
         | 
| 180 | 
            +
             | 
| 181 | 
            +
              RubyTorrent::BStream.register_bencoded_class self
         | 
| 182 | 
            +
            end
         | 
    
        data/test/test_all.rb
    ADDED
    
    
    
        data/test/test_client.rb
    ADDED
    
    | @@ -0,0 +1,264 @@ | |
| 1 | 
            +
            #------------------------------------------------------------------------
         | 
| 2 | 
            +
            # Tests for the client
         | 
| 3 | 
            +
            #------------------------------------------------------------------------
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            require "test/unit"
         | 
| 6 | 
            +
            require "rubytorrent/bencoding"
         | 
| 7 | 
            +
            require "socket"
         | 
| 8 | 
            +
            require "karmasphere/client"
         | 
| 9 | 
            +
            require "karmasphere/query"
         | 
| 10 | 
            +
            require "karmasphere/response"
         | 
| 11 | 
            +
            require "karmasphere/debug"
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            # For test purposes, we create a mini-server which bencodes
         | 
| 14 | 
            +
            # and transmits this response no matter what input is given.
         | 
| 15 | 
            +
            # In this test suite -- we're testing the client -- we
         | 
| 16 | 
            +
            # decode the response from the mini-server and match it
         | 
| 17 | 
            +
            # against this expected value.
         | 
| 18 | 
            +
             | 
| 19 | 
            +
            $stub_response = { 
         | 
| 20 | 
            +
                "_" => 12345,
         | 
| 21 | 
            +
                "facts" => [ 
         | 
| 22 | 
            +
                    { 
         | 
| 23 | 
            +
                        "f" => 4000,
         | 
| 24 | 
            +
                        "v" => -1,
         | 
| 25 | 
            +
                        "d" => "Invalid Source IP Address (cymru)"
         | 
| 26 | 
            +
                    }
         | 
| 27 | 
            +
                ],
         | 
| 28 | 
            +
                "combiners" => {
         | 
| 29 | 
            +
                    "karmasphere.emailchecker" => {
         | 
| 30 | 
            +
                        "v" => -1000,
         | 
| 31 | 
            +
                        "d" => "<f4000: if-fail(0) => return bad(1.0)>"
         | 
| 32 | 
            +
                    }
         | 
| 33 | 
            +
                }
         | 
| 34 | 
            +
            }
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            # We have four test cases in total, exploring each combination of:
         | 
| 37 | 
            +
            # * Turnaround vs Stub
         | 
| 38 | 
            +
            # * TCP vs UDP
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            $port = 8666
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            class TC_Client_Turnaround_TCP < Test::Unit::TestCase
         | 
| 43 | 
            +
              @@port = $port+1
         | 
| 44 | 
            +
             | 
| 45 | 
            +
              def setup
         | 
| 46 | 
            +
                @thr=Thread.new do
         | 
| 47 | 
            +
                  Karmasphere.dprint("TC_Client_Turnaround_TCP: constructing listen server on port #@@port\n");
         | 
| 48 | 
            +
                  @server = TCPServer.new(nil, @@port)
         | 
| 49 | 
            +
             | 
| 50 | 
            +
                  # mengwong 20060701: i believe TCPServers are
         | 
| 51 | 
            +
                  # automatically created with reuseaddr = true,
         | 
| 52 | 
            +
                  # but you may use the following code to check.
         | 
| 53 | 
            +
                  Karmasphere.dprint("created server with #{@server.getsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR).inspect}\n");
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  while(session = @server.accept)
         | 
| 56 | 
            +
                    Thread.new do
         | 
| 57 | 
            +
                      Karmasphere.dprint("accepted new session #{session.inspect}\n");
         | 
| 58 | 
            +
                      len_str = session.recv(4)
         | 
| 59 | 
            +
                      len=len_str.unpack("N")[0]
         | 
| 60 | 
            +
                      info=session.recv(len)
         | 
| 61 | 
            +
                      Karmasphere.dprint("received #{len} bytes of info: #{info}\n");
         | 
| 62 | 
            +
                      session.send len_str+info, 0
         | 
| 63 | 
            +
                      Karmasphere.dprint("echoing back #{len} bytes of info: #{info}\n");
         | 
| 64 | 
            +
                      session.close
         | 
| 65 | 
            +
                    end
         | 
| 66 | 
            +
                  end
         | 
| 67 | 
            +
                end
         | 
| 68 | 
            +
              end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
              def teardown
         | 
| 71 | 
            +
                @server.close
         | 
| 72 | 
            +
                @server = nil
         | 
| 73 | 
            +
                @thr.kill
         | 
| 74 | 
            +
                GC.start
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              def test_startup
         | 
| 78 | 
            +
                Karmasphere.dprint("test_client: test_startup: beginning\n");
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                # we need to wait for the listener thread established in
         | 
| 81 | 
            +
                # setup to be ready.  we do a poor man's thread
         | 
| 82 | 
            +
                # synchronization by simply testing the @server.  if we
         | 
| 83 | 
            +
                # were doing this right, we'd use a MonitorMixin as
         | 
| 84 | 
            +
                # documented on page 138 of the pickax book.
         | 
| 85 | 
            +
                while not @server do
         | 
| 86 | 
            +
                  Karmasphere.dprint("test_startup: server not ready.  passing.\n");
         | 
| 87 | 
            +
                  Thread.pass
         | 
| 88 | 
            +
                end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                Karmasphere.dprint("test_client: test_startup: proceeding.\n");
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                assert client=Karmasphere::Client.new(:host => "localhost", 
         | 
| 93 | 
            +
                                                      :port => @@port,
         | 
| 94 | 
            +
                                                      :type => Karmasphere::CONNECTION_TCP)
         | 
| 95 | 
            +
                query = Karmasphere::Query.new({ "_" => 12345 })
         | 
| 96 | 
            +
                response = client.ask(query)
         | 
| 97 | 
            +
                Karmasphere.dprint("test_client: got back response " , response.instance_variable_get("@hash"));
         | 
| 98 | 
            +
                assert_equal query.to_hash, response.instance_variable_get("@hash")
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
            end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            class TC_Client_Turnaround_UDP < Test::Unit::TestCase
         | 
| 103 | 
            +
              @@port = $port + 2
         | 
| 104 | 
            +
              def setup
         | 
| 105 | 
            +
                Karmasphere.dprint("TC_Client_Turnaround_UDP: constructing listen server on port #@@port\n");
         | 
| 106 | 
            +
                @thr=Thread.new do
         | 
| 107 | 
            +
             | 
| 108 | 
            +
                  @server = UDPSocket.new
         | 
| 109 | 
            +
                  @server.bind(nil, @@port)
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  info=@server.recvfrom(8192)
         | 
| 112 | 
            +
                  Karmasphere.dprint("TC_Client_Turnaround_UDP: received ", info, "\n");
         | 
| 113 | 
            +
                    
         | 
| 114 | 
            +
                  @server.flush
         | 
| 115 | 
            +
                  client_h=info[1][2]
         | 
| 116 | 
            +
                  client_p=info[1][1]
         | 
| 117 | 
            +
                  query=info[0]
         | 
| 118 | 
            +
                  @server.send query, 0, client_h, client_p
         | 
| 119 | 
            +
                  @server.flush
         | 
| 120 | 
            +
                  Karmasphere.dprint("TC_Client_Turnaround_UDP: sent stuff back to #{client_h}:#{client_p}\n");
         | 
| 121 | 
            +
                  
         | 
| 122 | 
            +
                end
         | 
| 123 | 
            +
              end
         | 
| 124 | 
            +
             | 
| 125 | 
            +
              def teardown
         | 
| 126 | 
            +
                Karmasphere.dprint("TC_Client_Turnaround_UDP: tearing down server.\n");
         | 
| 127 | 
            +
                @server.close
         | 
| 128 | 
            +
                @server = nil
         | 
| 129 | 
            +
                @thr.kill
         | 
| 130 | 
            +
                GC.start
         | 
| 131 | 
            +
              end
         | 
| 132 | 
            +
             | 
| 133 | 
            +
              def test_startup
         | 
| 134 | 
            +
                while not @server do
         | 
| 135 | 
            +
                  Karmasphere.dprint("test_startup: server not ready.  passing.\n");
         | 
| 136 | 
            +
                  Thread.pass
         | 
| 137 | 
            +
                end
         | 
| 138 | 
            +
                assert client=Karmasphere::Client.new(:host => "localhost",
         | 
| 139 | 
            +
                                                      :port => @@port
         | 
| 140 | 
            +
                                                      )
         | 
| 141 | 
            +
                query = Karmasphere::Query.new({ "_" => 12345 })
         | 
| 142 | 
            +
                response = client.ask(query)
         | 
| 143 | 
            +
                assert_equal query.to_hash, response.instance_variable_get("@hash")
         | 
| 144 | 
            +
             | 
| 145 | 
            +
              end
         | 
| 146 | 
            +
             | 
| 147 | 
            +
              def test_credentials
         | 
| 148 | 
            +
                while not @server do
         | 
| 149 | 
            +
                  Karmasphere.dprint("test_startup: server not ready.  passing.\n");
         | 
| 150 | 
            +
                  Thread.pass
         | 
| 151 | 
            +
                end
         | 
| 152 | 
            +
                assert_raises Karmasphere::CredentialsError do
         | 
| 153 | 
            +
                  Karmasphere::Client.new(:host => "localhost",
         | 
| 154 | 
            +
                                          :port => @@port,
         | 
| 155 | 
            +
                                          :principal => "foo")
         | 
| 156 | 
            +
                end
         | 
| 157 | 
            +
                assert_raises Karmasphere::CredentialsError do
         | 
| 158 | 
            +
                  Karmasphere::Client.new(:host => "localhost",
         | 
| 159 | 
            +
                                          :port => @@port,
         | 
| 160 | 
            +
                                          :credentials => "bar")
         | 
| 161 | 
            +
                end
         | 
| 162 | 
            +
             | 
| 163 | 
            +
                assert client=Karmasphere::Client.new(:host => "localhost",
         | 
| 164 | 
            +
                                                      :port => @@port,
         | 
| 165 | 
            +
                                                      :principal => "foo",
         | 
| 166 | 
            +
                                                      :credentials => "bar"
         | 
| 167 | 
            +
                                                      )
         | 
| 168 | 
            +
                query = Karmasphere::Query.new({ "_" => 12345 })
         | 
| 169 | 
            +
                response = client.ask(query)
         | 
| 170 | 
            +
                assert_equal query.to_hash.merge({"a" => [ "foo", "bar" ]}),
         | 
| 171 | 
            +
                response.instance_variable_get("@hash")
         | 
| 172 | 
            +
              end
         | 
| 173 | 
            +
            end
         | 
| 174 | 
            +
             | 
| 175 | 
            +
            class TC_Client_Stub_UDP < Test::Unit::TestCase
         | 
| 176 | 
            +
              @@port = $port + 3
         | 
| 177 | 
            +
              def setup
         | 
| 178 | 
            +
                @thr=Thread.new do
         | 
| 179 | 
            +
                  Karmasphere.dprint("TC_Client_Stub_UDP: constructing listen server on port #@@port\n");
         | 
| 180 | 
            +
             | 
| 181 | 
            +
                  @server = UDPSocket.new
         | 
| 182 | 
            +
                  @server.bind("localhost", @@port)
         | 
| 183 | 
            +
                  Karmasphere.dprint("TC_Client_Stub_UDP: created server #@port\n");
         | 
| 184 | 
            +
                  @server_ready = true
         | 
| 185 | 
            +
                  
         | 
| 186 | 
            +
                  info=@server.recvfrom(8192)
         | 
| 187 | 
            +
                  @server.flush
         | 
| 188 | 
            +
                  client_h=info[1][2]
         | 
| 189 | 
            +
                  client_p=info[1][1]
         | 
| 190 | 
            +
                  Karmasphere.dprint("TC_Client_Stub_UDP: server received packet from #{client_h}:#{client_p}\n");
         | 
| 191 | 
            +
                  query=info[0]
         | 
| 192 | 
            +
                  @server.send $stub_response.to_bencoding, 0, client_h, client_p
         | 
| 193 | 
            +
                  Karmasphere.dprint("TC_Client_Stub_UDP: miniserver sent stuff back to #{client_h}:#{client_p}\n");
         | 
| 194 | 
            +
                  Karmasphere.dprint("TC_Client_Stub_UDP: close_write()d.\n");
         | 
| 195 | 
            +
                end
         | 
| 196 | 
            +
              end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
              def teardown
         | 
| 199 | 
            +
                @thr.kill
         | 
| 200 | 
            +
                @server.close
         | 
| 201 | 
            +
                @server = nil
         | 
| 202 | 
            +
                GC.start
         | 
| 203 | 
            +
              end
         | 
| 204 | 
            +
             | 
| 205 | 
            +
              def test_startup
         | 
| 206 | 
            +
                while not @server_ready do
         | 
| 207 | 
            +
                  Karmasphere.dprint("Stub_UDP test_startup: server not ready.  passing.\n");
         | 
| 208 | 
            +
                  Thread.pass
         | 
| 209 | 
            +
                end
         | 
| 210 | 
            +
                Karmasphere.dprint("test_startup: proceeding.\n");
         | 
| 211 | 
            +
                assert client=Karmasphere::Client.new(:host => "localhost",
         | 
| 212 | 
            +
                                                      :port => @@port
         | 
| 213 | 
            +
                                                      )
         | 
| 214 | 
            +
                query = Karmasphere::Query.new(:Id => 12345)
         | 
| 215 | 
            +
                Karmasphere.dprint("test_startup: client asking query...\n");
         | 
| 216 | 
            +
                response = client.ask(query)
         | 
| 217 | 
            +
                Karmasphere.dprint("test_startup: ... client received response #{response}\n");
         | 
| 218 | 
            +
                assert_equal $stub_response, response.instance_variable_get('@hash')
         | 
| 219 | 
            +
              end
         | 
| 220 | 
            +
            end
         | 
| 221 | 
            +
             | 
| 222 | 
            +
            class TC_Client_Stub_TCP < Test::Unit::TestCase
         | 
| 223 | 
            +
              @@port = $port + 4
         | 
| 224 | 
            +
                def setup
         | 
| 225 | 
            +
                Karmasphere.dprint("TC_Client_Stub_TCP: constructing listen server on port #@@port\n");
         | 
| 226 | 
            +
                    @thr = Thread.new do
         | 
| 227 | 
            +
             | 
| 228 | 
            +
                        @server = TCPServer.new(nil, @@port)
         | 
| 229 | 
            +
                        while(session = @server.accept)
         | 
| 230 | 
            +
                            Thread.new do
         | 
| 231 | 
            +
                                while not session.closed?
         | 
| 232 | 
            +
                                    len_str = session.recv(4)
         | 
| 233 | 
            +
                                    len=len_str.unpack("N")[0]
         | 
| 234 | 
            +
                                    info=session.recv(len)
         | 
| 235 | 
            +
                                    response_str=$stub_response.to_bencoding
         | 
| 236 | 
            +
                                    response_len_str = [ response_str.length ].pack "N"
         | 
| 237 | 
            +
                                    session.send response_len_str+response_str, 0
         | 
| 238 | 
            +
                                end
         | 
| 239 | 
            +
                            end
         | 
| 240 | 
            +
                        end
         | 
| 241 | 
            +
                    end
         | 
| 242 | 
            +
                end
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                def teardown
         | 
| 245 | 
            +
                    @server.close
         | 
| 246 | 
            +
                    @server = nil
         | 
| 247 | 
            +
                    @thr.kill
         | 
| 248 | 
            +
                    GC.start
         | 
| 249 | 
            +
                end
         | 
| 250 | 
            +
             | 
| 251 | 
            +
                def test_startup
         | 
| 252 | 
            +
                    while not @server do
         | 
| 253 | 
            +
                      Karmasphere.dprint("test_startup: server not ready.  passing.\n");
         | 
| 254 | 
            +
                      Thread.pass
         | 
| 255 | 
            +
                    end
         | 
| 256 | 
            +
                    assert client=Karmasphere::Client.new(:host => "localhost", 
         | 
| 257 | 
            +
                                                          :port => @@port,
         | 
| 258 | 
            +
                                                          :type => Karmasphere::CONNECTION_TCP)
         | 
| 259 | 
            +
                    query = Karmasphere::Query.new(:Id => 12345)
         | 
| 260 | 
            +
                    response = client.ask(query)
         | 
| 261 | 
            +
                    assert_equal $stub_response, response.instance_variable_get('@hash')
         | 
| 262 | 
            +
                end
         | 
| 263 | 
            +
            end
         | 
| 264 | 
            +
             | 
    
        data/test/test_query.rb
    ADDED
    
    | @@ -0,0 +1,120 @@ | |
| 1 | 
            +
            require "test/unit"
         | 
| 2 | 
            +
            require "karmasphere/query"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            class TC_Basic_Query < Test::Unit::TestCase
         | 
| 5 | 
            +
                def test_automatic_query_id
         | 
| 6 | 
            +
                    client=Karmasphere::Query.new
         | 
| 7 | 
            +
                    assert_kind_of Karmasphere::Query, client
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    client2=Karmasphere::Query.new
         | 
| 10 | 
            +
                    assert_kind_of Karmasphere::Query, client2
         | 
| 11 | 
            +
             | 
| 12 | 
            +
                    assert_equal client.id, "q1"
         | 
| 13 | 
            +
                    assert_equal client.to_hash, { "_" => "q1" }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    assert_equal client2.id, "q2"
         | 
| 16 | 
            +
                    assert_equal client2.to_hash, { "_" => "q2" }
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                def test_query_identities_munging
         | 
| 20 | 
            +
                    client=Karmasphere::Query.new(:Id => "q2")
         | 
| 21 | 
            +
                    assert_kind_of Karmasphere::Query, client
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                    client.identities=[ ["127.0.0.1", 0 ] ]
         | 
| 24 | 
            +
                    assert_equal( [ ["127.0.0.1", 0 ] ], client.identities)
         | 
| 25 | 
            +
                    assert_equal( { "_" => "q2", "i" => [ ["127.0.0.1", 0 ] ] },
         | 
| 26 | 
            +
                        client.to_hash)
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                    client.identities = [ "127.0.0.1" ]
         | 
| 29 | 
            +
                    assert_equal( [ ["127.0.0.1", 0 ] ], client.identities)
         | 
| 30 | 
            +
                    assert_equal({ "_" => "q2", "i" => [ ["127.0.0.1", 0 ] ] }, 
         | 
| 31 | 
            +
                        client.to_hash)
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                    client.identities = "127.0.0.1"
         | 
| 34 | 
            +
                    assert_equal( [ ["127.0.0.1", 0 ] ], client.identities)
         | 
| 35 | 
            +
                    assert_equal({ "_" => "q2", "i" => [ ["127.0.0.1", 0 ] ] }, 
         | 
| 36 | 
            +
                        client.to_hash)
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                    client.identity = "127.0.0.1"
         | 
| 39 | 
            +
                    assert_equal( [ ["127.0.0.1", 0 ] ], client.identities)
         | 
| 40 | 
            +
                    assert_equal({ "_" => "q2", "i" => [ ["127.0.0.1", 0 ] ] }, 
         | 
| 41 | 
            +
                        client.to_hash)
         | 
| 42 | 
            +
                end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                def test_query_identities_guessing
         | 
| 45 | 
            +
                    client=Karmasphere::Query.new(:Id => "q3")
         | 
| 46 | 
            +
                    assert_kind_of Karmasphere::Query, client
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    client.identities = "127.0.0.1"
         | 
| 49 | 
            +
                    assert_equal( [ ["127.0.0.1", 0 ] ], client.identities )
         | 
| 50 | 
            +
                    assert_equal({ "_" => "q3", "i" => [ ["127.0.0.1", 0 ] ] }, 
         | 
| 51 | 
            +
                        client.to_hash)
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                    client.identities = "::1/128"
         | 
| 54 | 
            +
                    assert_equal( [ ["::1/128", 1 ] ], client.identities )
         | 
| 55 | 
            +
                    assert_equal({ "_" => "q3", "i" => [ ["::1/128", 1 ] ] }, 
         | 
| 56 | 
            +
                        client.to_hash)
         | 
| 57 | 
            +
             | 
| 58 | 
            +
                    client.identities = "example.com"
         | 
| 59 | 
            +
                    assert_equal( [ ["example.com", 2 ] ], client.identities )
         | 
| 60 | 
            +
                    assert_equal({ "_" => "q3", "i" => [ ["example.com", 2 ] ] }, 
         | 
| 61 | 
            +
                        client.to_hash)
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                    client.identities = "example@example.com"
         | 
| 64 | 
            +
                    assert_equal( [ ["example@example.com", 3 ] ], client.identities )
         | 
| 65 | 
            +
                    assert_equal({ "_" => "q3", "i" => [ ["example@example.com", 3 ] ] }, 
         | 
| 66 | 
            +
                        client.to_hash)
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                    client.identities = "http://www.example.com/"
         | 
| 69 | 
            +
                    assert_equal( [ ["http://www.example.com/", 4 ] ], client.identities )
         | 
| 70 | 
            +
                    assert_equal({ "_" => "q3", "i" => [ ["http://www.example.com/", 4 ] ] }, 
         | 
| 71 | 
            +
                        client.to_hash)
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    client.identities = "chunky bacon"
         | 
| 74 | 
            +
                    assert_equal( [ ["chunky bacon", 5 ] ], client.identities )
         | 
| 75 | 
            +
                    assert_equal({ "_" => "q3", "i" => [ ["chunky bacon", 5 ] ] }, 
         | 
| 76 | 
            +
                        client.to_hash)
         | 
| 77 | 
            +
                end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                def test_query_identities_on_construction
         | 
| 80 | 
            +
                    client=Karmasphere::Query.new(:Id => 'q4',
         | 
| 81 | 
            +
                                                  :Identities => "example.com")
         | 
| 82 | 
            +
                    assert_kind_of Karmasphere::Query, client
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                    assert_equal( [ ["example.com", 2 ] ], client.identities,
         | 
| 85 | 
            +
                                "Automatically-detected identity at construction time")
         | 
| 86 | 
            +
                    assert_equal({ "_" => "q4", "i" => [ ["example.com", 2 ] ] }, 
         | 
| 87 | 
            +
                        client.to_hash, "Simple identity at construction time")
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    client = Karmasphere::Query.new( :Id => 'q5',
         | 
| 90 | 
            +
                                                     :Identities => [ [ "127.0.0.1", 
         | 
| 91 | 
            +
                                                         Karmasphere::IDT_IP4_ADDRESS,
         | 
| 92 | 
            +
                                                         Karmasphere::AUTHENTIC ] ] )
         | 
| 93 | 
            +
                    assert_equal( [ [ "127.0.0.1", 0, "a" ] ], client.identities )
         | 
| 94 | 
            +
                    assert_equal({ "_" => "q5", "i" => [ ["127.0.0.1", 0, "a" ] ] }, 
         | 
| 95 | 
            +
                        client.to_hash, "Complicated identity at construction time")
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                def test_query_example_query
         | 
| 99 | 
            +
                    client = Karmasphere::Query.new( :Id => 12345, 
         | 
| 100 | 
            +
                        :Identities => [ [ "127.0.0.1", Karmasphere::IDT_IP4_ADDRESS,
         | 
| 101 | 
            +
                                                        Karmasphere::SMTP_CLIENT_IP ],
         | 
| 102 | 
            +
                                         [ "antony@karmasphere.com", 
         | 
| 103 | 
            +
                                             Karmasphere::IDT_EMAIL_ADDRESS,
         | 
| 104 | 
            +
                                             Karmasphere::SMTP_ENV_MAIL_FROM ],
         | 
| 105 | 
            +
                                         [ "karmasphere.com",
         | 
| 106 | 
            +
                                             Karmasphere::IDT_DOMAIN_NAME,
         | 
| 107 | 
            +
                                             Karmasphere::SMTP_ENV_HELO ] ],
         | 
| 108 | 
            +
                        :Composites => "karmasphere.emailchecker",
         | 
| 109 | 
            +
                        :Flags => 1 )
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                    assert_kind_of Karmasphere::Query, client
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                    assert_equal( { "_" => 12345, 
         | 
| 114 | 
            +
                                    "i" => [ [ "127.0.0.1", 0, "smtp.client-ip" ],
         | 
| 115 | 
            +
                                    [ "antony@karmasphere.com", 3, "smtp.env.mail-from" ],
         | 
| 116 | 
            +
                                    [ "karmasphere.com", 2, "smtp.env.helo" ] ],
         | 
| 117 | 
            +
                                    "s" => "karmasphere.emailchecker", "fl" => 1 },
         | 
| 118 | 
            +
                                 client.to_hash, "Test query from the protocol spec")
         | 
| 119 | 
            +
                end
         | 
| 120 | 
            +
            end
         | 
| @@ -0,0 +1,65 @@ | |
| 1 | 
            +
            require "test/unit"
         | 
| 2 | 
            +
            require "karmasphere/response"
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            $response_hash = { 
         | 
| 5 | 
            +
                "_" => 12345,
         | 
| 6 | 
            +
                "facts" => [ 
         | 
| 7 | 
            +
                    { 
         | 
| 8 | 
            +
                        "f" => 4000,
         | 
| 9 | 
            +
                        "v" => -1,
         | 
| 10 | 
            +
                        "d" => "Invalid Source IP Address (cymru)"
         | 
| 11 | 
            +
                    }
         | 
| 12 | 
            +
                ],
         | 
| 13 | 
            +
                "combiners" => {
         | 
| 14 | 
            +
                    "karmasphere.emailchecker" => {
         | 
| 15 | 
            +
                        "v" => -1000,
         | 
| 16 | 
            +
                        "d" => "<f4000: if-fail(0) => return bad(1.0)>"
         | 
| 17 | 
            +
                    }
         | 
| 18 | 
            +
                }
         | 
| 19 | 
            +
            }
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            class TC_BasicResponse < Test::Unit::TestCase
         | 
| 22 | 
            +
                def test_basicresponse
         | 
| 23 | 
            +
                    response=nil
         | 
| 24 | 
            +
                    assert_nothing_raised {
         | 
| 25 | 
            +
                        response=Karmasphere::Response.new({"_" => 12345})
         | 
| 26 | 
            +
                    }
         | 
| 27 | 
            +
                    assert_kind_of Karmasphere::Response, response
         | 
| 28 | 
            +
                    assert_equal 12345, response.id
         | 
| 29 | 
            +
                    assert_nil response.time
         | 
| 30 | 
            +
                    assert_nil response.combinations
         | 
| 31 | 
            +
                    assert_equal [], response.facts
         | 
| 32 | 
            +
                    assert_equal [], response.combiner_names
         | 
| 33 | 
            +
                    assert_nil response.error
         | 
| 34 | 
            +
                    assert_nil response.message
         | 
| 35 | 
            +
                end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
                def test_errorresponse
         | 
| 38 | 
            +
                    response=nil
         | 
| 39 | 
            +
                    assert_nothing_raised {
         | 
| 40 | 
            +
                        response=Karmasphere::Response.new({"_" => "q314159", 
         | 
| 41 | 
            +
                                                       "error" => 1,
         | 
| 42 | 
            +
                                                       "message" => "an error occurred"})
         | 
| 43 | 
            +
                    }
         | 
| 44 | 
            +
                    assert_kind_of Karmasphere::Response, response
         | 
| 45 | 
            +
                    assert_equal "q314159", response.id
         | 
| 46 | 
            +
                    # I don't think I need go through all those assert_nils again
         | 
| 47 | 
            +
                    assert_equal 1, response.error
         | 
| 48 | 
            +
                    assert_equal "an error occurred", response.message
         | 
| 49 | 
            +
                    assert_equal "Response_id 'q314159': 0 combinations, 0 facts\nError: an error occurred\n", response.to_s
         | 
| 50 | 
            +
                end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
                def test_success
         | 
| 53 | 
            +
                    response=nil
         | 
| 54 | 
            +
                    assert_nothing_raised { 
         | 
| 55 | 
            +
                        response=Karmasphere::Response.new $response_hash
         | 
| 56 | 
            +
                    }
         | 
| 57 | 
            +
                    assert_kind_of Karmasphere::Response, response
         | 
| 58 | 
            +
                    assert_equal ["karmasphere.emailchecker"], response.combiner_names
         | 
| 59 | 
            +
                    assert_equal([{ 
         | 
| 60 | 
            +
                            "f" => 4000,
         | 
| 61 | 
            +
                            "v" => -1,
         | 
| 62 | 
            +
                            "d" => "Invalid Source IP Address (cymru)"
         | 
| 63 | 
            +
                        }], response.facts)
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
            end
         | 
    
        metadata
    ADDED
    
    | @@ -0,0 +1,57 @@ | |
| 1 | 
            +
            --- !ruby/object:Gem::Specification 
         | 
| 2 | 
            +
            rubygems_version: 0.9.0
         | 
| 3 | 
            +
            specification_version: 1
         | 
| 4 | 
            +
            name: karmasphere-client
         | 
| 5 | 
            +
            version: !ruby/object:Gem::Version 
         | 
| 6 | 
            +
              version: 0.6.4
         | 
| 7 | 
            +
            date: 2007-04-30 00:00:00 -07:00
         | 
| 8 | 
            +
            summary: Karmasphere Client
         | 
| 9 | 
            +
            require_paths: 
         | 
| 10 | 
            +
              - lib
         | 
| 11 | 
            +
            email: devsupport@karmasphere.com
         | 
| 12 | 
            +
            homepage: http://www.karmasphere.com.com/devzone/
         | 
| 13 | 
            +
            rubyforge_project: 
         | 
| 14 | 
            +
            description: 
         | 
| 15 | 
            +
            autorequire: karmasphere
         | 
| 16 | 
            +
            default_executable: 
         | 
| 17 | 
            +
            bindir: bin
         | 
| 18 | 
            +
            has_rdoc: false
         | 
| 19 | 
            +
            required_ruby_version: !ruby/object:Gem::Version::Requirement 
         | 
| 20 | 
            +
              requirements: 
         | 
| 21 | 
            +
                - 
         | 
| 22 | 
            +
                  - ">"
         | 
| 23 | 
            +
                  - !ruby/object:Gem::Version 
         | 
| 24 | 
            +
                    version: 0.0.0
         | 
| 25 | 
            +
              version: 
         | 
| 26 | 
            +
            platform: ruby
         | 
| 27 | 
            +
            signing_key: 
         | 
| 28 | 
            +
            cert_chain: 
         | 
| 29 | 
            +
            post_install_message: 
         | 
| 30 | 
            +
            authors: 
         | 
| 31 | 
            +
              - Meng Weng Wong
         | 
| 32 | 
            +
            files: 
         | 
| 33 | 
            +
              - bin/rubykarmaclient
         | 
| 34 | 
            +
              - test/test_all.rb
         | 
| 35 | 
            +
              - test/test_client.rb
         | 
| 36 | 
            +
              - test/test_query.rb
         | 
| 37 | 
            +
              - test/test_response.rb
         | 
| 38 | 
            +
              - lib/karmasphere
         | 
| 39 | 
            +
              - lib/karmasphere.rb
         | 
| 40 | 
            +
              - lib/rubytorrent
         | 
| 41 | 
            +
              - lib/karmasphere/client.rb
         | 
| 42 | 
            +
              - lib/karmasphere/constants.rb
         | 
| 43 | 
            +
              - lib/karmasphere/debug.rb
         | 
| 44 | 
            +
              - lib/karmasphere/query.rb
         | 
| 45 | 
            +
              - lib/karmasphere/response.rb
         | 
| 46 | 
            +
              - lib/rubytorrent/bencoding.rb
         | 
| 47 | 
            +
              - README
         | 
| 48 | 
            +
            test_files: 
         | 
| 49 | 
            +
              - test/test_all.rb
         | 
| 50 | 
            +
            rdoc_options: []
         | 
| 51 | 
            +
            extra_rdoc_files: 
         | 
| 52 | 
            +
              - README
         | 
| 53 | 
            +
            executables: 
         | 
| 54 | 
            +
              - rubykarmaclient
         | 
| 55 | 
            +
            extensions: []
         | 
| 56 | 
            +
            requirements: []
         | 
| 57 | 
            +
            dependencies: []
         |